<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          第五回 | 進(jìn)入保護(hù)模式前的最后一次折騰內(nèi)存

          共 4203字,需瀏覽 9分鐘

           ·

          2021-11-29 21:38

          新讀者看這里,老讀者直接跳過。


          本系列會以一個讀小說的心態(tài),從開機(jī)啟動后的代碼執(zhí)行順序,帶著大家閱讀和賞析 Linux 0.11 全部核心代碼,了解操作系統(tǒng)的技術(shù)細(xì)節(jié)和設(shè)計思想。



          你會跟著我一起,看著一個操作系統(tǒng)從啥都沒有開始,一步一步最終實現(xiàn)它復(fù)雜又精巧的設(shè)計,讀完這個系列后希望你能發(fā)出感嘆,原來操作系統(tǒng)源碼就是這破玩意。


          以下是已發(fā)布文章的列表,詳細(xì)了解本系列可以先從開篇詞看起。


          開篇詞

          第一回 | 最開始的兩行代碼

          第二回 | 自己給自己挪個地兒

          第三回 | 做好最最基礎(chǔ)的準(zhǔn)備工作

          第四回 | 把自己在硬盤里的其他部分也放到內(nèi)存來


          本系列的 GitHub 地址如下(文末閱讀原文可直接跳轉(zhuǎn))

          https://github.com/sunym1993/flash-linux0.11-talk



          ------- 正文開始?-------



          書接上回,上回書咱們說到,操作系統(tǒng)已經(jīng)完成了各種從硬盤到內(nèi)存的加載,以及內(nèi)存到內(nèi)存的復(fù)制。

          ?
          ?
          至此,整個 bootsect.s 的使命就完成了,也是我們品讀完的第一個操作系統(tǒng)源碼文件。之后便跳轉(zhuǎn)到了 0x90200 這個位置開始執(zhí)行,這個位置處的代碼就是位于 setup.s 的開頭,我們接著來看。
          start:
          ????mov?ax,#0x9000??
          ;?this?is?done?in?bootsect?already,?but...
          ????mov?ds,ax
          ????mov?ah,#0x03????
          ;?read?cursor?pos
          ????xor?bh,bh
          ????
          int?0x10????????;?save?it?in?known?place,?con_init?fetches
          ????mov?[0],dx??????
          ;?it?from?0x90000.
          又有個 int 指令。
          ?
          前面的文章好好看過的話,一下就能猜出它要干嘛。還記不記得之前有個 int 0x13 表示觸發(fā) BIOS 提供的讀磁盤中斷程序?這個 int 0x10 也是一樣的,它也是觸發(fā) BIOS 提供的顯示服務(wù)中斷處理程序,而 ah 寄存器被賦值為 0x03 表示顯示服務(wù)里具體的讀取光標(biāo)位置功能

          具體 BIOS 提供了哪些中斷服務(wù),如何去調(diào)用和獲取返回值,請大家自行尋找資料,這里只說結(jié)果。
          ?
          這個 int 0x10 中斷程序執(zhí)行完畢并返回時,dx 寄存器里的值表示光標(biāo)的位置,具體說來其高八位 dh 存儲了行號,低八位 dl 存儲了列號。
          ?
          ?
          這里說明一下:計算機(jī)在加電自檢后會自動初始化到文字模式,在這種模式下,一屏幕可以顯示 25 行,每行 80 個字符,也就是 80 列。
          ?
          那下一步 mov [0],dx 就是把這個光標(biāo)位置存儲在 [0] 這個內(nèi)存地址處。注意,前面我們說過,這個內(nèi)存地址僅僅是偏移地址,還需要加上 ds 這個寄存器里存儲的段基址,最終的內(nèi)存地址是在 0x90000 處,這里存放著光標(biāo)的位置,以便之后在初始化控制臺的時候用到。
          ?
          所以從這里也可以看出,這和我們平時調(diào)用一個方法沒什么區(qū)別,只不過這里的寄存器的用法相當(dāng)于入?yún)⒑头祷刂?/strong>,這里的 0x10 中斷號相當(dāng)于方法名

          這里又應(yīng)了之前說的一句話,操作系統(tǒng)內(nèi)核的最開始也處處都是 BIOS 的調(diào)包俠,有現(xiàn)成的就用唄。
          ?
          再接下來的幾行代碼,都是和剛剛一樣的邏輯,調(diào)用一個 BIOS 中斷獲取點什么信息,然后存儲在內(nèi)存中某個位置,我們迅速瀏覽一下就好咯。
          比如獲取內(nèi)存信息。
          ; Get memory size (extended mem, kB)
          mov ah,#0x88
          int 0x15
          mov [2],ax
          獲取顯卡顯示模式。
          ; Get video-card data:
          mov ah,#0x0f
          int 0x10
          mov [4],bx ; bh = display page
          mov [6],ax ; al = video mode, ah = window width
          檢查顯示方式并取參數(shù)
          ; check for EGA/VGA and some config parameters
          mov ah,#0x12
          mov bl,#0x10
          int 0x10
          mov [8],ax
          mov [10],bx
          mov [12],cx
          獲取第一塊硬盤的信息。
          ; Get hd0 data
          mov ax,#0x0000
          mov ds,ax
          lds si,[4*0x41]
          mov ax,#INITSEG
          mov es,ax
          mov di,#0x0080
          mov cx,#0x10
          rep
          movsb
          獲取第二塊硬盤的信息。
          ; Get hd1 data
          mov ax,#0x0000
          mov ds,ax
          lds si,[4*0x46]
          mov ax,#INITSEG
          mov es,ax
          mov di,#0x0090
          mov cx,#0x10
          rep
          movsb
          以上原理都是一樣的。
          ?
          我們就沒必要細(xì)琢磨了,對操作系統(tǒng)的理解作用不大,只需要知道最終存儲在內(nèi)存中的信息是什么,在什么位置,就好了,之后會用到他們的。

          內(nèi)存地址長度(字節(jié))名稱
          0x900002光標(biāo)位置
          0x900022
          擴(kuò)展內(nèi)存數(shù)
          0x900042顯示頁面
          0x900061
          顯示模式
          0x900071字符列數(shù)
          0x900082未知
          0x9000A1
          顯示內(nèi)存
          0x9000B1
          顯示狀態(tài)
          0x9000C2顯卡特性參數(shù)
          0x9000E1
          屏幕行數(shù)
          0x9000F1屏幕列數(shù)
          0x9008016
          硬盤1參數(shù)表
          0x9009016硬盤2參數(shù)表
          0x901FC2
          根設(shè)備號


          由于之后很快就會用 c 語言進(jìn)行編程,雖然匯編和 c 語言也可以用變量的形式進(jìn)行傳遞數(shù)據(jù),但這需要編譯器在鏈接時做一些額外的工作,所以這么多數(shù)據(jù)更方便的還是雙方共同約定一個內(nèi)存地址,我往這里存,你從這里取,就完事了。這恐怕是最最原始和直觀的變量傳遞的方式了。
          ?
          把這些信息存儲好之后,操作系統(tǒng)又要做什么呢?我們繼續(xù)往下看。
          cli?????????;?no?interrupts?allowed?;
          就一行 cli,表示關(guān)閉中斷的意思。
          ?
          因為后面我們要把原本是 BIOS 寫好的中斷向量表給覆蓋掉,也就是給破壞掉了,寫上我們自己的中斷向量表,所以這個時候是不允許中斷進(jìn)來的。

          繼續(xù)看。
          ;?first?we?move?the?system?to?it's?rightful?place
          ????mov?ax,#0x0000
          ????cld?????????
          ;?'direction'=0,?movs?moves?forward
          do_move:
          ????mov?es,ax???????
          ;?destination?segment
          ????add?ax,#0x1000
          ????cmp?ax,#0x9000
          ????jz??end_move
          ????mov?ds,ax???????
          ;?source?segment
          ????sub?di,di
          ????sub?si,si
          ????mov?cx,#0x8000
          ????
          rep?movsw
          ????jmp?do_move
          ;?then?we?load?the?segment?descriptors
          end_move:
          ????...
          看到后面那個 rep movsw 熟不熟悉,一開始我們把操作系統(tǒng)代碼從 0x7c00 移動到 0x90000 的時候就是用的這個指令,來圖回憶一下。
          ?
          ?
          同前面的原理一樣,也是做了個內(nèi)存復(fù)制操作,最終的結(jié)果是,把內(nèi)存地址 0x10000 處開始往后一直到 0x90000 的內(nèi)容,統(tǒng)統(tǒng)復(fù)制到內(nèi)存的最開始的 0 位置,大概就是這么個效果。
          ?
          ?
          由于之前的各種加載和復(fù)制,導(dǎo)致內(nèi)存看起來很亂,是時候進(jìn)行一波取舍和整理了,我們重新梳理一下此時的內(nèi)存布局。
          ?
          棧頂?shù)刂啡匀皇?0x9FF00 沒有改變。
          ?
          0x90000 開始往上的位置,原來是 bootsectsetup 程序的代碼,現(xiàn) bootsect 的一部分代碼在已經(jīng)被操作系統(tǒng)為了記錄內(nèi)存、硬盤、顯卡等一些臨時存放的數(shù)據(jù)給覆蓋了一部分。
          ?
          內(nèi)存最開始的 00x80000 這 512K 被 system 模塊給占用了,之前講過,這個 system 模塊就是除了 bootsect 和 setup 之外的全部程序鏈接在一起的結(jié)果,可以理解為操作系統(tǒng)的全部

          那么現(xiàn)在的內(nèi)存布局就是這個樣子。
          ?
          ?
          好了,記住上面的圖就好了,這回是不是又重新清晰起來了?之前的什么 0x7c00,已經(jīng)是過去式了,趕緊忘掉它,向前看!
          ?
          接下來,就要進(jìn)行有點技術(shù)含量的工作了,那就是模式的轉(zhuǎn)換,需要從現(xiàn)在的 16 位的實模式轉(zhuǎn)變?yōu)橹?32 位的保護(hù)模式,這是一項大工程!也是我認(rèn)為的這趟操作系統(tǒng)源碼旅程中,第一個頗為精彩的地方,大家做好準(zhǔn)備!

          后面的世界越來越精彩,欲知后事如何,且聽下回分解。



          ------- 本回擴(kuò)展與延伸 -------



          嘗試在文本模式下,用直接寫顯存的方式,把自己的名字輸出在屏幕上。實驗源碼請自行到 GitHub 上尋找。



          ------- 關(guān)于本系列?-------



          本系列的開篇詞看這

          閃客新系列!你管這破玩意叫操作系統(tǒng)源碼


          本系列的擴(kuò)展資料看這(也可點擊閱讀原文),這里有很多有趣的資料、答疑、互動參與項目,持續(xù)更新中,希望有你的參與。

          https://github.com/sunym1993/flash-linux0.11-talk


          本系列全局視角



          最后,祝大家都能追更到系列結(jié)束,只要你敢持續(xù)追更,并且把每一回的內(nèi)容搞懂,我就敢讓你在系列結(jié)束后說一句,我對 Linux 0.11 很熟悉。


          另外,本系列完全免費(fèi),希望大家能多多傳播給同樣喜歡的人,同時給我的 GitHub 項目點個 star,就在閱讀原文處,這些就足夠讓我堅持寫下去了!我們下回見。

          瀏覽 70
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  免费黄色电影在线观看 | 美女啊爽操叫 | 成人免费性生活视频 | 国产免费一区二区三区四区午夜视频 | 亚洲第一页在线播放 |