1. 程式人生 > >30天自制操作系統(一)從計算機結構到匯編程序入門

30天自制操作系統(一)從計算機結構到匯編程序入門

ios 是什麽 program 信號 解釋 根目錄 自己 保存 音樂

學習這本書不代表我要親自動手把這本書中的代碼敲一遍哦,只是借機來學習一下操作系統。之前有段時間也在看操作系統的知識,怎麽說呢之前的看的書都是偏講理論多一些,對於我這個非科班出身的來說,由於之前的計算機知識基礎不牢,像計算機組成及其接口技術也只是自學了一點,所以看那些講理論的書有些陽春白雪了點,而且印象也只是停留在理論層面。《30天自制操作系統》這本書就不一樣,一點一點的構建一個玩具操作系統,雖然沒有多大的用處,但是對於操作系統的入門我想應該是夠了的。

這裏是總結一下我的看書心得體會,然後對其中提到或者擴展的知識點自己在消化一下,順便總結成文。

1 先動手操作

在這一節作者把一個計算機的啟動程序(什麽叫啟動程序後面再說),用二進制的編輯器把內容一個個都敲出來了,相當於把你編譯的二進制文件中的字節一個個敲,可想而知......最後成了軟盤映像文件,以.img結尾的,然後用工具將這個映像文件寫入到軟盤,最後作者用這個軟盤啟動了系統。

軟盤的容量為1440x1024Byte=1474560Byte=1.44MB

也就是作者硬是敲了1474560下才把這個啟動程序敲完了,剛開始啥也不懂只知道照著作者的來,結果沒敲下去,反正到現在我也強烈不建議做這個部分,看下作者就好了。

然後這個程序可以啟動程序,就這從零開始作者制作了一個軟盤啟動程序,成功點亮了。

2 究竟做了些什麽

電腦的中心是CPU,CPU除了與別的電路進行電信號交換以外什麽都不會,而且對於電信號,它也只能理解開(ON)和關(OFF)這兩種狀態。

CPU有指令因此可進行整數的加減乘除計算,也可以處理負數、計算小數。

雖然電腦可以寫文章、聽音樂、修照片和做其他各種各樣的事情,但是這一切只不過是和CPU交換電信號而已。

作者這裏是在科普計算機的基礎知識呢,感覺講得還是很樸實、很簡單,這裏的簡單是將復雜的知識用簡單的方式表述,而不是越講越復雜。

然後就是二進制和電信號,計算機中所有的指令和數據在內部都是用二進制來表示的。

而軟盤則是記錄指令與數據的地方,所以在第一部分中,作者就純粹用0和1寫出了映像文件。

只要有二進制的編輯器,啥都可以做出來,反正作者是這樣說的,制作和500萬像素數碼相機質量一樣的圖片,制作C編譯器等。

二進制來表示數據顯得有些繁瑣,然後就是牽扯到了二進制和十六進制。

3 初次體驗匯編程序

開始用匯編語言來寫程序啦。

用和NASM類似的作者自己開發的編譯器"nask"對匯編文件進行編譯了。

然後用匯編又把第一部分的程序寫了一遍,由於之前作者的程度中有很多連續的空白的字符串,這裏作者用了一個叫做RESB的指令,來我們一起學一下。

這裏不貼程序了,反正最後用的字節數一算還是1440KB。

匯編指令RESB

RESB指令是"reserve byte"的略寫預約字節。

如果想要從當前位置向後空出10個字節來,並且填0,如果後面18萬行全是0x00的話 使用本命令可以省去填寫18萬行0x00的時間。

例子:

RESB 10

DB 0

RESB 0x1f0-$ 填寫從0x00到0x1f0的數據;

匯編中resb這樣的指令是什麽意思?
resb條偽指令,在NASM中文手冊中查找一下:

"RESB", "RESW", "RESD", "RESQ" and "REST"被設計用在模塊的 BSS 段中:它們聲明 未初始化的存儲空間。每一個帶有單個操作數,用來表明字節數,字數,或雙字數或其它的需要保留單位。就像在 2.2.7 中所描述的,NASM 不支持 MASM/TASM 的扣留未初始化空間的語法"DW ?"或類似的東西:現在我們所描述的正是 NASM 自己的方式。"RESB"類偽指令的操作數是有嚴格的語法。

DB指令

DB指令是"data byte"的縮寫,也就是往文件裏直接寫入一個字節的指令。

4 加工潤色

這一部分才是真正的匯編代碼。

; hello-os
; TAB=4

; 一下這段是標準FAT12格式軟盤專用的代碼

        DB        0xeb, 0x4e, 0x90
        DB        "HELLOIPL"         ; 啟動扇區的名稱可以是任意的字符串 (8字節)
        DW        512                ; 每個扇區(sector)的大小(必須是512字節)
        DB        1                  ; 簇(cluster)的大小 (必須為512字節)
        DW        1                  ; FAT的起始位置 (一般從第一個扇區開始)
        DB        2                  ; FAT的個數 (必須為2)
        DW        224                ; 根目錄的大小(一般設成224項)
        DW        2880               ; 該磁盤的大小(必須是2880扇區)
        DB        0xf0               ; 磁盤的種類 (必須是0xf0)
        DW        9                  ; FAT的長度 (必須是9扇區)
        DW        18                 ; 1個磁道(track)有幾個扇區(必須是18)
        DW        2                  ; 磁頭數 (必須是2)
        DD        0                  ; 不使用分區, 必須是0
        DD        2880               ; 重寫一次磁盤大小
        DB        0,0,0x29           ; 意義不明, 固定
        DD        0xffffffff         ; (可能是)卷標號碼
        DB        "HELLO-OS   "      ; 磁盤的名稱(11字節)
        DB        "FAT12   "         ; 磁盤格式名稱 (8字節)
        RESB      18                 ; 先空出18字節

; 程序主體

        DB        0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
        DB        0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
        DB        0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
        DB        0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
        DB        0xee, 0xf4, 0xeb, 0xfd

; 信息顯示部分

        DB        0x0a, 0x0a        ; 2個換行
        DB        "hello, world"
        DB        0x0a              ; 換行
        DB        0

        RESB      0x1fe-$           ; 填寫0x00, 直到0x001fe, 0x001fe=510

        DB        0x55, 0xaa

; 以下是啟動區以外部分的輸出

        DB        0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
        RESB      4600
        DB        0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
        RESB      1469432

擦,程序主體部分和啟動區以外的部分使用十六進制的數表示的呢?

";"以後的部分是匯編語言的註釋方法

DB後面可以接字符串的部分,程序中已經有好幾處了

DW,DD指令

DW和DD分別是"data word"和"data double-word"的縮寫,和DB類似,只是占的字節數不一樣,DW稱為字,占2個字節;DD是雙字,占4個字節。

$指令

在RESB 0x1fe-$中用到了指令"$",它是一個變量,可以告訴我們現在這個位置的字節數(其他的意思先不講了),寫成這樣的好處是不用一個個計算我們前面已經寫了多少個字節,可以看成$這個變量幫我們計算了。

RESB 0x1fe-$是為了保證在第510字節開始的地方是55AA,也就是代碼中的"DB 0x55, 0xaa"。

其他的幾個名詞解釋

TAB=4

為了程序美觀、大方,一般都會有縮進,這個不用解釋了。

FAT12格式

用Window或者MS-DOS格式化出來的軟盤就是這種格式,這種格式的兼容性好,在Windows上也能用,而且剩余的磁盤空間還可以用來保存自己喜歡的文件。

啟動區

啟動區(boot sector)這個概念很重要。軟盤的第一個扇區稱為啟動區。計算機在讀寫軟盤的時候並不是一個一個字節來讀取的,而是以512字節為一個單位進行讀寫的。軟盤的512字節就是一個扇區。一張軟盤一共有1440KB,也就是1474560字節,除以512得2880,所以一張軟盤一共有2880個扇區。

那為什麽第一個扇區稱為啟動區呢?

那是因為計算機首先從最初一個扇區開始讀軟盤,然後去檢查這個扇區最後2個字節的內容。如果這最後2個字節不是55 AA,計算機會認為這張盤上沒有所需的啟動程序,就會報一個不能啟動的錯誤。(也許有人會問為什麽一定是55 AA呢?那是當初設計者隨便決定的,作者也沒法解釋)。如果計算機確認了第一個扇區的最後2個字節正好是55 AA,那它就任務這個扇區的開始是啟動程序,並開始執行這個程序。

十六進制的55或AA

不行,作者這個解釋我不是很滿意,然後上網搜了一下,還真有人給出了解釋

許多串口通訊中測試或握手信號使用AA或55這兩個特殊的十六進制數,在許多PIC內部的EEPROM改寫也使用這兩個數作為敲門磚,初學者可能不解何為,其實如果將這兩個數展開成二進制就可明白為什麽:AA展開為10101010,55展開為01010101,變成串行電平的話就是一個占空比為50%的方波,這種方波在電路中最容易被分辨是否受幹擾或者畸變,在實際波形的觀察中也最容易看出毛病所在,以異步串口通訊為例,通訊的每一個字節開始為一個數據位的低電平作為起始位,字節發送結束後是一個或兩個數據位的高電平作為停止位,在測試程序階段,我們可嘗試發送0xAA,利用示波器來驗證發送是否正確,以9600BPS的波特率計算,每個BIT的所用的時間大約是104.17μS,這裏我們選擇停止位占一個數據位,然後照此寫一個反復連續發送AA的發送程序,那麽在正確發送時在IO口看到的波形應該是一個大約4.8KHZ的方波,周期大約為208.34μS,占空比為50%。這樣我們可以很快斷定發送是否正確。由於這兩個數值的特殊性,還被用到其他一些地方,比如PC機引導過程中,bios程序在加載完MBR後,還要對MBR的最後兩個字節進行驗證,必須為0x55和0xAA

以下是軟綿綿老村長的補充:
Flash的存儲位,只能從1變成0,所以擦除完後,單元裏是1的,此時可以直接寫,當寫成0後,再要寫成1是不行的,一定要擦除,擦除後就變成1了。
每個字節先寫成55,再寫成AA,這樣每個bit都寫了一遍又擦了一遍,說明這個字節的位置是好用的。

IPL

IPL即initial program loader的縮寫,啟動程序加載器。啟動區只有區區512字節,實際的操作系統不可能這麽小,根本裝不進去。所以幾乎所有的操作系統,都是把加載操作系統本身的程序放在啟動區裏面。有鑒於此,有時也將啟動區稱為IPL。

啟動(boot)

boot這個詞的本意是長靴的單數形式。那它和計算機啟動又有什麽關系呢?原來boot這個詞是bootstrap的縮寫,在《吹牛大王歷險記》之後,bootstrap這個詞就有了"自己更生完成任務"的意思。

30天自制操作系統(一)從計算機結構到匯編程序入門