[自制簡單操做系統] 一、從0-1到彙編再到c語言的奧祕

 


目錄:linux

一、用0-1編寫最簡單的操做系統程序員

二、用匯編改寫上面0-1程序編程

  2.1 只用DB的彙編改寫版  2.2 加入RESB彙編的改寫版  2.3 進一步使用匯編替換0-1文件  2.4 核心程序也用匯編改寫  2.5 向彙編程序中加入IPL(啓動程序裝載器)  2.6 從啓動區執行操做系統(讀盤的應用)windows

三、彙編和C語言混合開發數組

  3.1 32位開發及C語言混合開發引入 3.2 彙編引入C語言(用匯編寫C語言函數)  3.3 C語言實現內存寫入  3.4 C語言指針的強大  3.5 色號設定與調色板 3.6 簡單界面實現數據結構


 

一、用0-1編寫最簡單的操做系統編輯器

>_<" 用二進制編輯器(Binary Editor),輸入下面的內容(這裏是16進制的)ide

PS: 如上圖,藍色部分要仔細,下面一直到168000這個地址都是00,在0001F0和001400附近還有些地方不是0,要把他們改過來,檢查一遍,保存爲helloos.img函數

>_<" 將這個文件寫入軟盤用來啓動電腦就能顯示「hello,world」這個字符串。oop

PS: 上面界面是用了一個PC模擬器


 

二、用匯編改寫上面0-1程序

>_<" 這裏就把上述超長的0-1文件改爲彙編語言文件helloos.nas,而後調用nask.exe編譯器將.nas文件編譯爲.img~剩下的就不用說了~

2.1 只用DB的彙編改寫版

1 DB    0xeb, 0x4e, 0x90, 0x48, 0x45, 0x4c, 0x4c, 0x4f
2 DB    0x49, 0x50, 0x4c, 0x00, 0x02, 0x01, 0x01, 0x00
3 DB    0x02, 0xe0, 0x00, 0x40, 0x0b, 0xf0, 0x09, 0x00
4 DB    0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
5 DB    0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x29, 0xff
6 (爲節省紙張,這裏省略18萬4314行)
7 DB    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

PS:DB是data byte的縮寫,就是往文件裏直接寫入1字節的指令~這樣就實現了彙編實現最上面的0-1文件,可是貌似看起來更長了....(若是足夠牛B的話,只用DB就能作出任何文件)

 

2.2 加入RESB彙編的改寫版

 1 DB    0xeb, 0x4e, 0x90, 0x48, 0x45, 0x4c, 0x4c, 0x4f
 2 DB    0x49, 0x50, 0x4c, 0x00, 0x02, 0x01, 0x01, 0x00
 3 DB    0x02, 0xe0, 0x00, 0x40, 0x0b, 0xf0, 0x09, 0x00
 4 DB    0x12, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
 5 DB    0x40, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x29, 0xff
 6 DB    0xff, 0xff, 0xff, 0x48, 0x45, 0x4c, 0x4c, 0x4f
 7 DB    0x2d, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x46, 0x41
 8 DB    0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00
 9 RESB    16
10 DB    0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
11 DB    0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
12 DB    0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
13 DB    0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
14 DB    0xee, 0xf4, 0xeb, 0xfd, 0x0a, 0x0a, 0x68, 0x65
15 DB    0x6c, 0x6c, 0x6f, 0x2c, 0x20, 0x77, 0x6f, 0x72
16 DB    0x6c, 0x64, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00  ;到000080前8個的內容,後8個和000090以後填0,部分作修改
17 RESB    368
18 DB    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa  ;這就是0001F0處非0的內容
19 DB    0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
20 RESB    4600
21 DB    0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00  ;夥計發現沒,這就是001400地址處的內容
22 RESB    1469432

PS: 這裏多加入了一個彙編指令RESB,就使文件大體清新多了~這裏RESB指令是reserve byte的縮寫,若是想從某個字節開始空出10個字節就能寫成RESB 10,這樣咱們就節約了大約10萬行代碼~

 

2.3 進一步使用匯編替換0-1文件

>_<" 雖然上面把10幾萬行的0-1改寫的只有20幾行,可是仍是沒法理解其意思,下面進行優化,使咱們能理解代碼的意思~

 1 ; hello-os
 2 ; TAB=4
 3 
 4 ; 如下段落是標準FAT12格式軟盤專用代碼
 5     DB    0xeb, 0x4e, 0x90  ; 注意和咱們寫的0-1代碼,以及上面幾個版本的對比一下,你就會明白的
 6     DB    "HELLOIPL"        ; 啓動區的名稱能夠是任意字符串(8字節)
 7     DW    512              ; 每一個扇區(sector)的大小必須爲512字節
 8     DB    1               ; 簇(cluster)的大小必須爲1個扇區
 9     DW    1               ; FAT的起始位置(通常從第一個扇區開始)
10     DB    2               ; FAT的個數(必須爲2)
11     DW    224              ; 根目錄的大小(通常設爲244項)
12     DW    2880             ; 該磁盤的的大小(必須爲2880扇區)
13     DB    0xf0             ; 磁盤的種類(必須爲0xfd)
14     DW    9                ; FAT的長度(必須爲9扇區)
15     DW    18               ; 一個磁道(track)有幾個扇區(必須爲18)
16     DW    2                ; 磁頭數(必須爲2)
17     DD    0                ; 不使用分區(必須爲0)
18     DD    2880             ; 重寫一次磁盤大小
19     DB    0,0,0x29         ; 意義不明,固定
20     DD    0xffffffff       ; (多是)卷標號碼
21     DB    "HELLO-OS   "    ; 磁盤名稱(11字節)
22     DB    "FAT12   "       ; 磁盤格式名稱(8字節)
23     RESB    18             ; 先騰出18字節
24 
25 ; 程序主體
26     DB    0xb8, 0x00, 0x00, 0x8e, 0xd0, 0xbc, 0x00, 0x7c
27     DB    0x8e, 0xd8, 0x8e, 0xc0, 0xbe, 0x74, 0x7c, 0x8a
28     DB    0x04, 0x83, 0xc6, 0x01, 0x3c, 0x00, 0x74, 0x09
29     DB    0xb4, 0x0e, 0xbb, 0x0f, 0x00, 0xcd, 0x10, 0xeb
30     DB    0xee, 0xf4, 0xeb, 0xfd
31 
32 ; 信息顯示部分
33     DB    0x0a, 0x0a        ; 2個換行
34     DB    "hello, world"
35     DB    0x0a              ; 換行
36     DB    0
37 
38     RESB    0x1fe-$            ; 填寫0x00直到0x001fe
39     DB    0x55, 0xaa
40 
41 ; 如下是啓動區之外部分的輸出
42     DB    0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
43     RESB    4600
44     DB    0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
45     RESB    1469432

PS: 不用解釋,程序主體放在下面講,如何轉換爲容易理解的彙編~

 

2.4 核心程序也用匯編改寫

>_<" 這裏主要對上面改進版彙編的25~36行進行改寫爲更容易理解的彙編程序(最開頭也改動一點點),其餘同樣:

 1 ; hello-os
 2 ; TAB=4
 3         ORG        0x7c00            ; 指明程序的裝載地址
 4 ; 如下段落是標準FAT12格式軟盤專用代碼
 5         JMP        entry
 6         DB        0x90
 7         DB        "HELLOIPL"        ; 啓動區的名稱能夠是任意字符串(8字節)
 8         DW        512                ; 每一個扇區(sector)的大小必須爲512字節
 9         DB        1                ; 簇(cluster)的大小必須爲1個扇區
10         DW        1                ; FAT的起始位置(通常從第一個扇區開始)
11         DB        2                ; FAT的個數(必須爲2)
12         DW        224                ; 根目錄的大小(通常設爲244項)
13         DW        2880            ; 該磁盤的的大小(必須爲2880扇區)
14         DB        0xf0            ; 磁盤的種類(必須爲0xfd)
15         DW        9                ; FAT的長度(必須爲9扇區)
16         DW        18                ; 一個磁道(track)有幾個扇區(必須爲18)
17         DW        2                ; 磁頭數(必須爲2)
18         DD        0                ; 不使用分區(必須爲0)
19         DD        2880            ; 重寫一次磁盤大小
20         DB        0,0,0x29        ; 意義不明,固定
21         DD        0xffffffff        ; (多是)卷標號碼
22         DB        "HELLO-OS   "    ; 磁盤名稱(11字節)
23         DB        "FAT12   "        ; 磁盤格式名稱(8字節)
24         RESB    18                ; 先騰出18字節
25 
26 ; 程序核心
27 entry:
28         MOV        AX,0            ; 初始化寄存器
29         MOV        SS,AX
30         MOV        SP,0x7c00
31         MOV        DS,AX
32         MOV        ES,AX
33 
34         MOV        SI,msg          ;主程序就是把msg的內容給SI而後循環逐個輸出
35 putloop:
36         MOV        AL,[SI]
37         ADD        SI,1            ; SI++
38         CMP        AL,0
39         JE        fin
40         MOV        AH,0x0e            ; 顯示一個文字
41         MOV        BX,15            ; 指定字符顏色
42         INT        0x10            ; 調用顯卡BIOS(彙編中常常會用到的一種調用形式)
43         JMP        putloop
44 fin:
45         HLT                        ; 讓CPU中止等待指令(和在main函數的結尾寫一個getchar()相似)
46         JMP        fin                ; 無限循環
47 
48 msg:
49         DB        0x0a, 0x0a        ; 2個回車
50         DB        "hello, world"
51         DB        0x0a            ; 回車
52         DB        0
53 
54         RESB    0x7dfe-$        ; 填充0
55 
56         DB        0x55, 0xaa
57 
58 ; 如下是啓動區之外部分的輸出
59         DB        0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
60         RESB    4600
61         DB        0xf0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00
62         RESB    1469432

PS: 這裏咱們能夠方便的看出來,原來主程序的功能就是把msg裏面的字符先傳給SI而後SI++遍歷循環輸出的意思,哈哈,終於能完整的從0-1轉到彙編而後理解0-1的意思啦~

PS: 這裏剛開始的125字節就是啓動區125字節內容,其地址爲0x00007c00-0x00007dff,因此第3行指明程序加載地址~

 

2.5 向彙編程序中加入IPL(啓動程序裝載器)

>_<" 上面的彙編實現了將msg的字符串顯示到顯示屏上,可是這裏的msg是原本保存在內存中的,通常CPU的內存是很小的,若是把大量的信息(如整個操做系統)都保存在這裏確定是不合理的,所以就須要把這部份內容存儲在其餘上(如內存條,這裏採用軟盤)!所以,咱們就要在覈心程序初始化以後從軟盤讀取數據放到內存在執行~(下面是調用INT 0x13讀取磁盤的相關代碼)

 1 ; 讀磁盤(從軟盤中讀數據裝到內存中0x8200--0x83ff  125字節的地方)
 2 MOV        AX,0x0820        ;ES:BX=緩衝地址
 3 MOV        ES,AX
 4 MOV        CH,0            ; 柱面0
 5 MOV        DH,0            ; 磁頭0
 6 MOV        CL,2            ; 扇區2
 7 
 8 MOV        AH,0x02            ; AH=0x02 : 讀盤
 9 MOV        AL,1            ; 1個扇區
10 MOV        BX,0
11 MOV        DL,0x00            ; A驅動器
12 INT        0x13            ; 調用磁盤BIOS
13 JC        error

 >_<" 修改後的彙編代碼以下:(這裏從磁盤讀取數據裝到0x8200--0x83ff 125字節的地方,若是讀取出錯就跳轉到error,顯示讀取出錯這個內容~

 1 ; haribote-ipl
 2 ; TAB=4
 3         ORG        0x7c00            ; 指明程序裝載地址
 4 
 5 ; 如下這段是FAT12格式軟盤專用代碼  0x7c00--0x7dff 125字節 用於啓動區
 6         JMP        entry
 7         DB        0x90
 8         DB        "HARIBOTE"        ; 啓動區的名字能夠是任意的,但必須是8字節
 9         DW        512                ; 每一個扇區(sector)的大小必須爲512字節
10         DB        1                ; 簇(cluster)的大小必須爲1個扇區
11         DW        1                ; FAT的起始位置(通常從第一個扇區開始)
12         DB        2                ; FAT的個數(必須爲2)
13         DW        224                ; 根目錄的大小(通常設爲244項)
14         DW        2880            ; 該磁盤的的大小(必須爲2880扇區)
15         DB        0xf0            ; 磁盤的種類(必須爲0xfd)
16         DW        9                ; FAT的長度(必須爲9扇區)
17         DW        18                ; 一個磁道(track)有幾個扇區(必須爲18)
18         DW        2                ; 磁頭數(必須爲2)
19         DD        0                ; 不使用分區(必須爲0)
20         DD        2880            ; 重寫一次磁盤大小
21         DB        0,0,0x29        ; 意義不明,固定
22         DD        0xffffffff        ; (多是)卷標號碼
23         DB        "HARIBOTEOS "    ; 磁盤名稱(11字節)
24         DB        "FAT12   "        ; 磁盤格式名稱(8字節)
25         RESB    18                ; 先騰出18字節
26 
27 ; 程序核心
28 entry:
29         MOV        AX,0            ; 初始化寄存器
30         MOV        SS,AX
31         MOV        SP,0x7c00
32         MOV        DS,AX
33 
34 ; 讀磁盤(從軟盤中讀數據裝到內存中0x8200--0x83ff  125字節的地方)
35         MOV        AX,0x0820        ;ES:BX=緩衝地址
36         MOV        ES,AX
37         MOV        CH,0            ; 柱面0
38         MOV        DH,0            ; 磁頭0
39         MOV        CL,2            ; 扇區2
40 
41         MOV        AH,0x02            ; AH=0x02 : 讀盤
42         MOV        AL,1            ; 1個扇區
43         MOV        BX,0
44         MOV        DL,0x00            ; A驅動器
45         INT        0x13            ; 調用磁盤BIOS
46         JC        error
47  
48 fin:
49         HLT                        ; 讓CPU中止等待指令
50         JMP        fin                ; 無限循環
51 
52 error:
53         MOV        SI,msg            ; 循環輸出msg裏面的內容     
54         
55 putloop:
56         MOV        AL,[SI]
57         ADD        SI,1            ; 給SI加1
58         CMP        AL,0
59         JE        fin
60         MOV        AH,0x0e            ; 顯示一個文字
61         MOV        BX,15            ; 指定字符顏色
62         INT        0x10            ; 調用顯卡BIOS
63         JMP        putloop  
64         
65 msg:
66         DB        0x0a, 0x0a        ; 換行2次
67         DB        "load error"
68         DB        0x0a            ; 換行
69         DB        0
70 
71         RESB    0x7dfe-$        ; 0x7dfe傑偱傪0x00偱杽傔傞柦椷
72 
73         DB        0x55, 0xaa
從磁盤讀取內容IPL

 

2.6 從啓動區執行操做系統(讀盤的應用)

>_<" 軟盤這種東西不可靠,所以咱們要屢次讀盤嘗試,若是屢次以後還不行再放棄讀盤,讀盤代碼改動以下:

 1 ; 讀磁盤(從軟盤中讀數據裝到內存中0x8200--0x83ff  125字節的地方)
 2         MOV        AX,0x0820        ;ES:BX=緩衝地址
 3         MOV        ES,AX
 4         MOV        CH,0            ; 柱面0
 5         MOV        DH,0            ; 磁頭0
 6         MOV        CL,2            ; 扇區2   
 7         
 8         MOv     SI,0            ; 記錄失敗次數的寄存器
 9 retry:
10         MOV        AH,0x02            ; AH=0x02 : 讀盤
11         MOV        AL,1            ; 1個扇區
12         MOV        BX,0
13         MOV        DL,0x00            ; A驅動器
14         INT        0x13            ; 調用磁盤BIOS
15         JNC     fin             ; 沒出錯就跳轉到fin
16         ADD     SI,1              ; SI++
17         CMP     SI,5            ; 比較SI和5
18         JAE     error           ; SI>=5時,跳轉到error
19         MOV     AH,0x00
20         MOV     DL,0x00         ; A驅動器
21         INT     0x13            ; 重置驅動器
22         JMP     retry
5次讀盤的核心代碼
 1 ; haribote-ipl
 2 ; TAB=4
 3         ORG        0x7c00            ; 指明程序裝載地址
 4 
 5 ; 如下這段是FAT12格式軟盤專用代碼  0x7c00--0x7dff 125字節 用於啓動區
 6         JMP        entry
 7         DB        0x90
 8         DB        "HARIBOTE"        ; 啓動區的名字能夠是任意的,但必須是8字節
 9         DW        512                ; 每一個扇區(sector)的大小必須爲512字節
10         DB        1                ; 簇(cluster)的大小必須爲1個扇區
11         DW        1                ; FAT的起始位置(通常從第一個扇區開始)
12         DB        2                ; FAT的個數(必須爲2)
13         DW        224                ; 根目錄的大小(通常設爲244項)
14         DW        2880            ; 該磁盤的的大小(必須爲2880扇區)
15         DB        0xf0            ; 磁盤的種類(必須爲0xfd)
16         DW        9                ; FAT的長度(必須爲9扇區)
17         DW        18                ; 一個磁道(track)有幾個扇區(必須爲18)
18         DW        2                ; 磁頭數(必須爲2)
19         DD        0                ; 不使用分區(必須爲0)
20         DD        2880            ; 重寫一次磁盤大小
21         DB        0,0,0x29        ; 意義不明,固定
22         DD        0xffffffff        ; (多是)卷標號碼
23         DB        "HARIBOTEOS "    ; 磁盤名稱(11字節)
24         DB        "FAT12   "        ; 磁盤格式名稱(8字節)
25         RESB    18                ; 先騰出18字節
26 
27 ; 程序核心
28 entry:
29         MOV        AX,0            ; 初始化寄存器
30         MOV        SS,AX
31         MOV        SP,0x7c00
32         MOV        DS,AX
33 
34 ; 讀磁盤(從軟盤中讀數據裝到內存中0x8200--0x83ff  125字節的地方)
35         MOV        AX,0x0820        ;ES:BX=緩衝地址
36         MOV        ES,AX
37         MOV        CH,0            ; 柱面0
38         MOV        DH,0            ; 磁頭0
39         MOV        CL,2            ; 扇區2   
40         
41         MOv     SI,0            ; 記錄失敗次數的寄存器
42 retry:
43         MOV        AH,0x02            ; AH=0x02 : 讀盤
44         MOV        AL,1            ; 1個扇區
45         MOV        BX,0
46         MOV        DL,0x00            ; A驅動器
47         INT        0x13            ; 調用磁盤BIOS
48         JNC     fin             ; 沒出錯就跳轉到fin
49         ADD     SI,1              ; SI++
50         CMP     SI,5            ; 比較SI和5
51         JAE     error           ; SI>=5時,跳轉到error
52         MOV     AH,0x00
53         MOV     DL,0x00         ; A驅動器
54         INT     0x13            ; 重置驅動器
55         JMP     retry
56  
57 fin:
58         HLT                        ; 讓CPU中止等待指令
59         JMP        fin                ; 無限循環
60 
61 error:
62         MOV        SI,msg            ; 循環輸出msg裏面的內容     
63         
64 putloop:
65         MOV        AL,[SI]
66         ADD        SI,1            ; 給SI加1
67         CMP        AL,0
68         JE        fin
69         MOV        AH,0x0e            ; 顯示一個文字
70         MOV        BX,15            ; 指定字符顏色
71         INT        0x10            ; 調用顯卡BIOS
72         JMP        putloop  
73         
74 msg:
75         DB        0x0a, 0x0a        ; 換行2次
76         DB        "load error"
77         DB        0x0a            ; 換行
78         DB        0
79 
80         RESB    0x7dfe-$        ; 0x7dfe傑偱傪0x00偱杽傔傞柦椷
81 
82         DB        0x55, 0xaa
83 
84 完整的代碼
5次讀盤的所有代碼

>_<" 趁着上面的盡頭,我們直接寫個從扇區2讀到扇區18的代碼吧!

PS:這裏採用的思路是:把扇區2->18的內容讀到內存,內存剛開始的地址爲0x0820,每次讀一個扇區向後移動0x0200個地址(即:125字節)

 1 ; 讀磁盤(從軟盤中讀數據裝到內存中0x8200--0x83ff  125字節的地方)
 2         MOV        AX,0x0820        ; ES:BX=緩衝地址
 3         MOV        ES,AX
 4         MOV        CH,0            ; 柱面0
 5         MOV        DH,0            ; 磁頭0
 6         MOV        CL,2            ; 扇區2   
 7 readloop:        
 8         MOv     SI,0            ; 記錄失敗次數的寄存器
 9 retry:
10         MOV        AH,0x02            ; AH=0x02 : 讀盤
11         MOV        AL,1            ; 1個扇區
12         MOV        BX,0
13         MOV        DL,0x00            ; A驅動器
14         INT        0x13            ; 調用磁盤BIOS
15         JNC     next            ; 沒出錯就跳轉到next繼續讀下一個作準備
16         ADD     SI,1            ; SI++
17         CMP     SI,5            ; 比較SI和5
18         JAE     error           ; SI>=5時,跳轉到error
19         MOV     AH,0x00
20         MOV     DL,0x00         ; A驅動器
21         INT     0x13            ; 重置驅動器
22         JMP     retry           
23 next:   
24         MOV     AX,ES           ; 把內存地址後移0x200
25         ADD     AX,0x0020
26         MOV     ES,AX           ; 由於沒有ADD ES,0x200指令,因此這裏繞個彎
27         ADD     CL,1            ; 往CL里加1 (所讀扇區標號,開始是2,見初始化部分)
28         CMP     CL,18           ; 和18比較 
29         JBE     readloop        ; 小於18就跳轉到readloop繼續讀
讀取到18扇區的核心代碼
 1 ; haribote-ipl
 2 ; TAB=4
 3         ORG        0x7c00            ; 指明程序裝載地址
 4 
 5 ; 如下這段是FAT12格式軟盤專用代碼  0x7c00--0x7dff 125字節 用於啓動區
 6         JMP        entry
 7         DB        0x90
 8         DB        "HARIBOTE"        ; 啓動區的名字能夠是任意的,但必須是8字節
 9         DW        512                ; 每一個扇區(sector)的大小必須爲512字節
10         DB        1                ; 簇(cluster)的大小必須爲1個扇區
11         DW        1                ; FAT的起始位置(通常從第一個扇區開始)
12         DB        2                ; FAT的個數(必須爲2)
13         DW        224                ; 根目錄的大小(通常設爲244項)
14         DW        2880            ; 該磁盤的的大小(必須爲2880扇區)
15         DB        0xf0            ; 磁盤的種類(必須爲0xfd)
16         DW        9                ; FAT的長度(必須爲9扇區)
17         DW        18                ; 一個磁道(track)有幾個扇區(必須爲18)
18         DW        2                ; 磁頭數(必須爲2)
19         DD        0                ; 不使用分區(必須爲0)
20         DD        2880            ; 重寫一次磁盤大小
21         DB        0,0,0x29        ; 意義不明,固定
22         DD        0xffffffff        ; (多是)卷標號碼
23         DB        "HARIBOTEOS "    ; 磁盤名稱(11字節)
24         DB        "FAT12   "        ; 磁盤格式名稱(8字節)
25         RESB    18                ; 先騰出18字節
26 
27 ; 程序核心
28 entry:
29         MOV        AX,0            ; 初始化寄存器
30         MOV        SS,AX
31         MOV        SP,0x7c00
32         MOV        DS,AX
33 
34 ; 讀磁盤(從軟盤中讀數據裝到內存中0x8200--0x83ff  125字節的地方)
35         MOV        AX,0x0820        ; ES:BX=緩衝地址
36         MOV        ES,AX
37         MOV        CH,0            ; 柱面0
38         MOV        DH,0            ; 磁頭0
39         MOV        CL,2            ; 扇區2   
40 readloop:        
41         MOv     SI,0            ; 記錄失敗次數的寄存器
42 retry:
43         MOV        AH,0x02            ; AH=0x02 : 讀盤
44         MOV        AL,1            ; 1個扇區
45         MOV        BX,0
46         MOV        DL,0x00            ; A驅動器
47         INT        0x13            ; 調用磁盤BIOS
48         JNC     next            ; 沒出錯就跳轉到next繼續讀下一個作準備
49         ADD     SI,1            ; SI++
50         CMP     SI,5            ; 比較SI和5
51         JAE     error           ; SI>=5時,跳轉到error
52         MOV     AH,0x00
53         MOV     DL,0x00         ; A驅動器
54         INT     0x13            ; 重置驅動器
55         JMP     retry           
56 next:   
57         MOV     AX,ES           ; 把內存地址後移0x200
58         ADD     AX,0x0020
59         MOV     ES,AX           ; 由於沒有ADD ES,0x200指令,因此這裏繞個彎
60         ADD     CL,1            ; 往CL里加1 (所讀扇區標號,開始是2,見初始化部分)
61         CMP     CL,18           ; 和18比較 
62         JBE     readloop        ; 小於18就跳轉到readloop繼續讀
63  
64 fin:
65         HLT                        ; 讓CPU中止等待指令
66         JMP        fin                ; 無限循環
67 
68 error:
69         MOV        SI,msg            ; 循環輸出msg裏面的內容     
70         
71 putloop:
72         MOV        AL,[SI]
73         ADD        SI,1            ; 給SI加1
74         CMP        AL,0
75         JE        fin
76         MOV        AH,0x0e            ; 顯示一個文字
77         MOV        BX,15            ; 指定字符顏色
78         INT        0x10            ; 調用顯卡BIOS
79         JMP        putloop  
80         
81 msg:
82         DB        0x0a, 0x0a        ; 換行2次
83         DB        "load error"
84         DB        0x0a            ; 換行
85         DB        0
86 
87         RESB    0x7dfe-$        ; 0x7dfe傑偱傪0x00偱杽傔傞柦椷
88 
89         DB        0x55, 0xaa
讀取到18扇區的完整代碼

>_<" 趁熱打鐵,C0-H0-S18的下一扇區就是磁盤的反面C0-H1-S1,此次是要從C0-H0-S2---->C0-H0-S3----->C9-H1-S18

 1 ; 讀磁盤(從軟盤中讀數據裝到內存中0x8200--0x83ff  125字節的地方)
 2         MOV        AX,0x0820        ; ES:BX=緩衝地址
 3         MOV        ES,AX
 4         MOV        CH,0            ; 柱面0
 5         MOV        DH,0            ; 磁頭0
 6         MOV        CL,2            ; 扇區2   
 7 readloop:        
 8         MOv     SI,0            ; 記錄失敗次數的寄存器
 9 retry:
10         MOV        AH,0x02            ; AH=0x02 : 讀盤
11         MOV        AL,1            ; 1個扇區
12         MOV        BX,0
13         MOV        DL,0x00            ; A驅動器
14         INT        0x13            ; 調用磁盤BIOS
15         JNC     next            ; 沒出錯就跳轉到next繼續讀下一個作準備
16         ADD     SI,1            ; SI++
17         CMP     SI,5            ; 比較SI和5
18         JAE     error           ; SI>=5時,跳轉到error
19         MOV     AH,0x00
20         MOV     DL,0x00         ; A驅動器
21         INT     0x13            ; 重置驅動器
22         JMP     retry           
23 next:   
24         MOV     AX,ES           ; 把內存地址後移0x200
25         ADD     AX,0x0020
26         MOV     ES,AX           ; 由於沒有ADD ES,0x200指令,因此這裏繞個彎
27         ADD     CL,1            ; 往CL里加1 (所讀扇區標號,開始是2,見初始化部分)
28         CMP     CL,18           ; 和18比較 
29         JBE     readloop        ; 小於18就跳轉到readloop繼續讀 
30         MOV     CL,1            ; 扇區1
31         ADD     DH,1            ; 磁頭+1
32         CMP     DH,2            ; 判斷磁頭是否超過2
33         JB      readloop        ; 沒有超過就繼續讀
34         MOV     DH,0            ; 超過2就轉爲0
35         ADD     CH,1            ; CH記錄讀取的柱面數
36         CMP     CH,CYLS         ; CYLS在前面定義 CYLS EQU 10
37         JB      readloop
讀取10個柱面的核心代碼
 1 ; haribote-ipl
 2 ; TAB=4
 3 CYLS    EQU        10                ; 定義讀的柱面數
 4         ORG        0x7c00            ; 指明程序裝載地址
 5 
 6 ; 如下這段是FAT12格式軟盤專用代碼  0x7c00--0x7dff 125字節 用於啓動區
 7         JMP        entry
 8         DB        0x90
 9         DB        "HARIBOTE"        ; 啓動區的名字能夠是任意的,但必須是8字節
10         DW        512                ; 每一個扇區(sector)的大小必須爲512字節
11         DB        1                ; 簇(cluster)的大小必須爲1個扇區
12         DW        1                ; FAT的起始位置(通常從第一個扇區開始)
13         DB        2                ; FAT的個數(必須爲2)
14         DW        224                ; 根目錄的大小(通常設爲244項)
15         DW        2880            ; 該磁盤的的大小(必須爲2880扇區)
16         DB        0xf0            ; 磁盤的種類(必須爲0xfd)
17         DW        9                ; FAT的長度(必須爲9扇區)
18         DW        18                ; 一個磁道(track)有幾個扇區(必須爲18)
19         DW        2                ; 磁頭數(必須爲2)
20         DD        0                ; 不使用分區(必須爲0)
21         DD        2880            ; 重寫一次磁盤大小
22         DB        0,0,0x29        ; 意義不明,固定
23         DD        0xffffffff        ; (多是)卷標號碼
24         DB        "HARIBOTEOS "    ; 磁盤名稱(11字節)
25         DB        "FAT12   "        ; 磁盤格式名稱(8字節)
26         RESB    18                ; 先騰出18字節
27 
28 ; 程序核心
29 entry:
30         MOV        AX,0            ; 初始化寄存器
31         MOV        SS,AX
32         MOV        SP,0x7c00
33         MOV        DS,AX
34 
35 ; 讀磁盤(從軟盤中讀數據裝到內存中0x8200--0x83ff  125字節的地方)
36         MOV        AX,0x0820        ; ES:BX=緩衝地址
37         MOV        ES,AX
38         MOV        CH,0            ; 柱面0
39         MOV        DH,0            ; 磁頭0
40         MOV        CL,2            ; 扇區2   
41 readloop:        
42         MOv     SI,0            ; 記錄失敗次數的寄存器
43 retry:
44         MOV        AH,0x02            ; AH=0x02 : 讀盤
45         MOV        AL,1            ; 1個扇區
46         MOV        BX,0
47         MOV        DL,0x00            ; A驅動器
48         INT        0x13            ; 調用磁盤BIOS
49         JNC     next            ; 沒出錯就跳轉到next繼續讀下一個作準備
50         ADD     SI,1            ; SI++
51         CMP     SI,5            ; 比較SI和5
52         JAE     error           ; SI>=5時,跳轉到error
53         MOV     AH,0x00
54         MOV     DL,0x00         ; A驅動器
55         INT     0x13            ; 重置驅動器
56         JMP     retry           
57 next:   
58         MOV     AX,ES           ; 把內存地址後移0x200
59         ADD     AX,0x0020
60         MOV     ES,AX           ; 由於沒有ADD ES,0x200指令,因此這裏繞個彎
61         ADD     CL,1            ; 往CL里加1 (所讀扇區標號,開始是2,見初始化部分)
62         CMP     CL,18           ; 和18比較 
63         JBE     readloop        ; 小於18就跳轉到readloop繼續讀 
64         MOV     CL,1            ; 扇區1
65         ADD     DH,1            ; 磁頭+1
66         CMP     DH,2            ; 判斷磁頭是否超過2
67         JB      readloop        ; 沒有超過就繼續讀
68         MOV     DH,0            ; 超過2就轉爲0
69         ADD     CH,1            ; CH記錄讀取的柱面數
70         CMP     CH,CYLS         ; CYLS在前面定義 CYLS EQU 10
71         JB      readloop
72         
73 fin:
74         HLT                        ; 讓CPU中止等待指令
75         JMP        fin                ; 無限循環
76 
77 error:
78         MOV        SI,msg            ; 循環輸出msg裏面的內容     
79         
80 putloop:
81         MOV        AL,[SI]
82         ADD        SI,1            ; 給SI加1
83         CMP        AL,0
84         JE        fin
85         MOV        AH,0x0e            ; 顯示一個文字
86         MOV        BX,15            ; 指定字符顏色
87         INT        0x10            ; 調用顯卡BIOS
88         JMP        putloop  
89         
90 msg:
91         DB        0x0a, 0x0a        ; 換行2次
92         DB        "load error"
93         DB        0x0a            ; 換行
94         DB        0
95 
96         RESB    0x7dfe-$        ; 0x7dfe傑偱傪0x00偱杽傔傞柦椷
97 
98         DB        0x55, 0xaa
讀取10個柱面的所有代碼

 

三、彙編和C語言混合開發

3.1 32位開發及C語言混合開發引入

>_<" 如今咱們已經學會如何從磁盤讀數據放到內存中了,那麼下面就是如何將操做系統自己內容寫進磁盤映像,而後咱們從啓動區執行這個內容就好了~

>_<" 前兩部分咱們已經把操做系統的引導程序寫好了,便是最終的讀取10個柱面的所有代碼,咱們經過編譯就能把其編譯爲磁盤鏡像文件(即最上面看的0-1文件);接下來新建一個haribote.nas彙編文件,在裏面先寫上以下代碼,這就是一個簡單的操做系統內容文件,用nask編譯爲.sys格式的文件,保存到磁盤映像.img裏(這個過程比較複雜,其實有比較好的軟件能夠幫助咱們直接解決上述保存到磁盤映像的問題:edimg.exe) 。這裏文件保存到映像文件時有一個規律:

  • 文件名會在0x002600之後的地方出現
  • 文件的內容會寫在0x004200後的地方

 根據上面的規律,咱們就能夠將操做系統自己的內容寫到名爲haribote.sys文件中,再把他們保存到磁盤映像裏,而後咱們從啓動區執行這個haribotes.sys就好了。

1 fin:
2         HLT                        ; 讓CPU中止等待指令
3         JMP        fin                ; 無限循環

>_<" 那麼該怎樣才能執行磁盤映像上位於0x004200號地址的程序呢?咱們在第二節已經介紹,程序是從啓動區開始執行,把磁盤上的內容裝在到內存0x8000號地址,因此磁盤0x4200處的內容位於內存0x8000+0x4200=0xc200號地址處。 這樣咱們在haribote.nas里加上ORG 0xc200,而後在第二節最後讀取10個柱面的所有代碼(下面命名爲ipl.nas)加上JMP 0xc200。

1 ; haribote-os
2 ; TAB=4
3 
4         ORG        0xc200            
5 fin:
6         HLT
7         JMP        fin

這樣將上面兩個文件編譯併合併爲映像文件並運行,什麼都沒有發生,那麼咱們想看看程序到底有沒有運行,該則麼辦呢?其實很簡單,就像咱們剛學C++的時候讓程序輸出個hello world,可是這裏,由於咱們上兩節已經實現了這個功能,再玩一遍沒啥意思,因而,這裏來個高級一點的:此次切換一下畫面模式(由於咱們最終要作成windows那樣地畫面),所以須要把在咱們的haribote.nas內添加一些內容(主要是調用顯卡BIOS的函數,具體搜索INT 0x10):

 1 ; haribote-os
 2 ; TAB=4
 3 
 4         ORG        0xc200            ; 這個程序要被裝在到程序的什麼位置
 5 
 6         MOV        AL,0x13            ; VGA顯卡,320X200X8位彩色
 7         MOV        AH,0x00
 8         INT        0x10
 9 fin:
10         HLT
11         JMP        fin

這樣若是程序正常運行,畫面將是一片漆黑,光標會消失。另外,咱們將ipl.nas的文件名改爲ipl10.nas(提醒你們,這個程序只能讀入10個柱面),另外,想要把磁盤裝在內容的結束地址告訴haribote.sys,因此咱們要在JMP 0xc200以前加上一行命令,將CYLS的值寫到地址0x0ff0中,這樣啓動程序就修改好了~

1 ; 磁盤內容裝載內容的結束地址告訴haribote.sys
2 
3         MOV        [0x0ff0],CH        ; 將CYLS的值寫到內存地址0x0ff0中 
4         JMP        0xc200
  1 ; haribote-ipl
  2 ; TAB=4
  3 CYLS    EQU        10                ; 定義讀的柱面數
  4         ORG        0x7c00            ; 指明程序裝載地址
  5 
  6 ; 如下這段是FAT12格式軟盤專用代碼  0x7c00--0x7dff 125字節 用於啓動區
  7         JMP        entry
  8         DB        0x90
  9         DB        "HARIBOTE"        ; 啓動區的名字能夠是任意的,但必須是8字節
 10         DW        512                ; 每一個扇區(sector)的大小必須爲512字節
 11         DB        1                ; 簇(cluster)的大小必須爲1個扇區
 12         DW        1                ; FAT的起始位置(通常從第一個扇區開始)
 13         DB        2                ; FAT的個數(必須爲2)
 14         DW        224                ; 根目錄的大小(通常設爲244項)
 15         DW        2880            ; 該磁盤的的大小(必須爲2880扇區)
 16         DB        0xf0            ; 磁盤的種類(必須爲0xfd)
 17         DW        9                ; FAT的長度(必須爲9扇區)
 18         DW        18                ; 一個磁道(track)有幾個扇區(必須爲18)
 19         DW        2                ; 磁頭數(必須爲2)
 20         DD        0                ; 不使用分區(必須爲0)
 21         DD        2880            ; 重寫一次磁盤大小
 22         DB        0,0,0x29        ; 意義不明,固定
 23         DD        0xffffffff        ; (多是)卷標號碼
 24         DB        "HARIBOTEOS "    ; 磁盤名稱(11字節)
 25         DB        "FAT12   "        ; 磁盤格式名稱(8字節)
 26         RESB    18                ; 先騰出18字節
 27 
 28 ; 程序核心
 29 entry:
 30         MOV        AX,0            ; 初始化寄存器
 31         MOV        SS,AX
 32         MOV        SP,0x7c00
 33         MOV        DS,AX
 34 
 35 ; 讀磁盤(從軟盤中讀數據裝到內存中0x8200--0x83ff  125字節的地方)
 36         MOV        AX,0x0820        ; ES:BX=緩衝地址
 37         MOV        ES,AX
 38         MOV        CH,0            ; 柱面0
 39         MOV        DH,0            ; 磁頭0
 40         MOV        CL,2            ; 扇區2   
 41 readloop:        
 42         MOv     SI,0            ; 記錄失敗次數的寄存器
 43 retry:
 44         MOV        AH,0x02            ; AH=0x02 : 讀盤
 45         MOV        AL,1            ; 1個扇區
 46         MOV        BX,0
 47         MOV        DL,0x00            ; A驅動器
 48         INT        0x13            ; 調用磁盤BIOS
 49         JNC     next            ; 沒出錯就跳轉到next繼續讀下一個作準備
 50         ADD     SI,1            ; SI++
 51         CMP     SI,5            ; 比較SI和5
 52         JAE     error           ; SI>=5時,跳轉到error
 53         MOV     AH,0x00
 54         MOV     DL,0x00         ; A驅動器
 55         INT     0x13            ; 重置驅動器
 56         JMP     retry           
 57 next:   
 58         MOV     AX,ES           ; 把內存地址後移0x200
 59         ADD     AX,0x0020
 60         MOV     ES,AX           ; 由於沒有ADD ES,0x200指令,因此這裏繞個彎
 61         ADD     CL,1            ; 往CL里加1 (所讀扇區標號,開始是2,見初始化部分)
 62         CMP     CL,18           ; 和18比較 
 63         JBE     readloop        ; 小於18就跳轉到readloop繼續讀 
 64         MOV     CL,1            ; 扇區1
 65         ADD     DH,1            ; 磁頭+1
 66         CMP     DH,2            ; 判斷磁頭是否超過2
 67         JB      readloop        ; 沒有超過就繼續讀
 68         MOV     DH,0            ; 超過2就轉爲0
 69         ADD     CH,1            ; CH記錄讀取的柱面數
 70         CMP     CH,CYLS         ; CYLS在前面定義 CYLS EQU 10
 71         JB      readloop
 72 
 73 ; 磁盤內容裝載內容的結束地址告訴haribote.sys
 74         MOV        [0x0ff0],CH        ; 將CYLS的值寫到內存地址0x0ff0中 
 75         JMP        0xc200        
 76 
 77 error:
 78         MOV        SI,msg            ; 循環輸出msg裏面的內容     
 79         
 80 putloop:
 81         MOV        AL,[SI]
 82         ADD        SI,1            ; 給SI加1
 83         CMP        AL,0
 84         JE        fin
 85         MOV        AH,0x0e            ; 顯示一個文字
 86         MOV        BX,15            ; 指定字符顏色
 87         INT        0x10            ; 調用顯卡BIOS
 88         JMP        putloop                       
 89 fin:
 90         HLT                        ; 讓CPU中止等待指令
 91         JMP        fin                ; 無限循環
 92         
 93 msg:
 94         DB        0x0a, 0x0a        ; 換行2次
 95         DB        "load error"
 96         DB        0x0a            ; 換行
 97         DB        0
 98 
 99         RESB    0x7dfe-$        ; 0x7dfe傑偱傪0x00偱杽傔傞柦椷
100 
101         DB        0x55, 0xaa
ipl10.nas(啓動程序)

PS: 這裏咱們把啓動區裏與haribote.sys無關的先後部分也讀了進來,因此啓動很慢,可是之後會有用的~

>_<" 如今,彙編語言開發終於能夠告一段落啦~,接下來咱們主要以C語言開發爲 主了~由於這裏用的是32位C語言編譯器(32位模式比16位的要好不少,這裏不詳細說明了),可是32位模式就不能調用BIOS功能了(這是由於BIOS是由16位機器語言寫的,若是咱們有什麼事情想用BIOS來作,就要所有放在開頭作,一旦進入32位模式就不能調用BIOS函數了(其實也有32位返回16位的方法)。再回頭說說使用BIOS的事情,在上面咱們已經把畫面模式設定已經作完了,接下來還想從BIOS獲取鍵盤狀態(即:NumLock是ON仍是OFF),此次只修改了haribote.nas:

 1 ; haribote-os
 2 ; TAB=4
 3 
 4 ; BOOT_INFO相關
 5 CYLS    EQU        0x0ff0            ; 設定啓動區
 6 LEDS    EQU        0x0ff1
 7 VMODE    EQU        0x0ff2            ; 關於顏色的信息顏色的位數
 8 SCRNX    EQU        0x0ff4            ; 分辨率X
 9 SCRNY    EQU        0x0ff6            ; 分辨率Y
10 VRAM    EQU        0x0ff8            ; 圖像緩衝區的開始地址
11 
12         ORG        0xc200            ; 這個程序要裝載到什麼地方
13 
14         MOV        AL,0x13            ; VGA顯卡,320X200X8位色彩
15         MOV        AH,0x00
16         INT        0x10
17         MOV        BYTE [VMODE],8    ; 記錄畫面模式
18         MOV        WORD [SCRNX],320
19         MOV        WORD [SCRNY],200
20         MOV        DWORD [VRAM],0x000a0000
21 
22 ; 用BIOS得到鍵盤上各類LED指示燈的狀態
23 
24         MOV        AH,0x02
25         INT        0x16             ; keyboard BIOS
26         MOV        [LEDS],AL
27 
28 fin:
29         HLT
30         JMP        fin

這個程序一看就明白,其實就是設置畫面模式以後,將設置的信息保存到內存中(之後可能要設置不一樣的畫面模式,就要把如今的設置信息保存起來以備後用);[VRAM]裏保存的是0xa0000,在電腦的世界裏,VRAM是指顯卡內存(Video RAM)也就是顯示畫面的內存,這一塊能夠像通常的內存同樣存儲數據,但VRAM的功能不只限於此,它的各個地址都對應着畫面上的像素,能夠利用這一機制在畫面上繪製出五光十色的圖案~

 

3.2 彙編引入C語言(用匯編寫C語言函數)

>_<" 終於準備就緒了,如今咱們直接切換到32位模式,而後運行C語言程序,此次要修改不少:首先是haribote.sys,它的前半部分是用匯編寫的,後半部分是用C語言寫的,因此爲了方便把文件名也從haribote.nas也隨之改爲了asmhead.nas,而且爲了調用C語言在前面加了100行左右的彙編代碼(從此再詳細介紹這100行代碼)下面先把到這裏所有的代碼貼出來(我猜不少人已經暈了,不知道究竟是哪些文件了)

  1 ; haribote-ipl
  2 ; TAB=4
  3 CYLS    EQU        10                ; 定義讀的柱面數
  4         ORG        0x7c00            ; 指明程序裝載地址
  5 
  6 ; 如下這段是FAT12格式軟盤專用代碼  0x7c00--0x7dff 125字節 用於啓動區
  7         JMP        entry
  8         DB        0x90
  9         DB        "HARIBOTE"         ; 啓動區的名字能夠是任意的,但必須是8字節
 10         DW        512                ; 每一個扇區(sector)的大小必須爲512字節
 11         DB        1                  ; 簇(cluster)的大小必須爲1個扇區
 12         DW        1                  ; FAT的起始位置(通常從第一個扇區開始)
 13         DB        2                  ; FAT的個數(必須爲2)
 14         DW        224                ; 根目錄的大小(通常設爲244項)
 15         DW        2880               ; 該磁盤的的大小(必須爲2880扇區)
 16         DB        0xf0               ; 磁盤的種類(必須爲0xfd)
 17         DW        9                  ; FAT的長度(必須爲9扇區)
 18         DW        18                 ; 一個磁道(track)有幾個扇區(必須爲18)
 19         DW        2                  ; 磁頭數(必須爲2)
 20         DD        0                  ; 不使用分區(必須爲0)
 21         DD        2880               ; 重寫一次磁盤大小
 22         DB        0,0,0x29           ; 意義不明,固定
 23         DD        0xffffffff         ; (多是)卷標號碼
 24         DB        "HARIBOTEOS "      ; 磁盤名稱(11字節)
 25         DB        "FAT12   "         ; 磁盤格式名稱(8字節)
 26         RESB    18                   ; 先騰出18字節
 27 
 28 ; 程序核心
 29 entry:
 30         MOV        AX,0              ; 初始化寄存器
 31         MOV        SS,AX
 32         MOV        SP,0x7c00
 33         MOV        DS,AX
 34 
 35 ; 讀磁盤(從軟盤中讀數據裝到內存中0x8200--0x83ff  125字節的地方)
 36         MOV        AX,0x0820         ; ES:BX=緩衝地址
 37         MOV        ES,AX
 38         MOV        CH,0              ; 柱面0
 39         MOV        DH,0              ; 磁頭0
 40         MOV        CL,2              ; 扇區2   
 41 readloop:        
 42         MOv     SI,0                 ; 記錄失敗次數的寄存器
 43 retry:
 44         MOV        AH,0x02           ; AH=0x02 : 讀盤
 45         MOV        AL,1              ; 1個扇區
 46         MOV        BX,0
 47         MOV        DL,0x00           ; A驅動器
 48         INT        0x13              ; 調用磁盤BIOS
 49         JNC     next                 ; 沒出錯就跳轉到next繼續讀下一個作準備
 50         ADD     SI,1                 ; SI++
 51         CMP     SI,5                 ; 比較SI和5
 52         JAE     error                ; SI>=5時,跳轉到error
 53         MOV     AH,0x00
 54         MOV     DL,0x00              ; A驅動器
 55         INT     0x13                 ; 重置驅動器
 56         JMP     retry           
 57 next:   
 58         MOV     AX,ES                ; 把內存地址後移0x200
 59         ADD     AX,0x0020
 60         MOV     ES,AX                ; 由於沒有ADD ES,0x200指令,因此這裏繞個彎
 61         ADD     CL,1                 ; 往CL里加1 (所讀扇區標號,開始是2,見初始化部分)
 62         CMP     CL,18                ; 和18比較 
 63         JBE     readloop             ; 小於18就跳轉到readloop繼續讀 
 64         MOV     CL,1                 ; 扇區1
 65         ADD     DH,1                 ; 磁頭+1
 66         CMP     DH,2                 ; 判斷磁頭是否超過2
 67         JB      readloop             ; 沒有超過就繼續讀
 68         MOV     DH,0                 ; 超過2就轉爲0
 69         ADD     CH,1                 ; CH記錄讀取的柱面數
 70         CMP     CH,CYLS              ; CYLS在前面定義 CYLS EQU 10
 71         JB      readloop
 72 
 73 ; 磁盤內容裝載內容的結束地址告訴haribote.sys
 74         MOV        [0x0ff0],CH       ; 將CYLS的值寫到內存地址0x0ff0中 
 75         JMP        0xc200        
 76 
 77 error:
 78         MOV        SI,msg            ; 循環輸出msg裏面的內容     
 79         
 80 putloop:
 81         MOV        AL,[SI]
 82         ADD        SI,1              ; 給SI加1
 83         CMP        AL,0
 84         JE        fin
 85         MOV        AH,0x0e           ; 顯示一個文字
 86         MOV        BX,15             ; 指定字符顏色
 87         INT        0x10              ; 調用顯卡BIOS
 88         JMP        putloop                       
 89 fin:
 90         HLT                          ; 讓CPU中止等待指令
 91         JMP        fin               ; 無限循環
 92         
 93 msg:
 94         DB        0x0a, 0x0a         ; 換行2次
 95         DB        "load error"
 96         DB        0x0a               ; 換行
 97         DB        0
 98 
 99         RESB    0x7dfe-$             ; 0x7dfe傑偱傪0x00偱杽傔傞柦椷
100 
101         DB        0x55, 0xaa
ipl10.asm(負責讀取磁盤加載主程序)
  1 ; haribote-os boot asm
  2 ; TAB=4
  3 
  4 BOTPAK    EQU        0x00280000        ; bootpack偺儘乕僪愭
  5 DSKCAC    EQU        0x00100000        ; 僨傿僗僋僉儍僢僔儏偺応強
  6 DSKCAC0    EQU        0x00008000        ; 僨傿僗僋僉儍僢僔儏偺応強乮儕傾儖儌乕僪乯
  7 
  8 ; BOOT_INFO相關
  9 CYLS    EQU        0x0ff0            ; 設定啓動區
 10 LEDS    EQU        0x0ff1
 11 VMODE    EQU        0x0ff2            ; 關於顏色的信息顏色的位數
 12 SCRNX    EQU        0x0ff4            ; 分辨率X
 13 SCRNY    EQU        0x0ff6            ; 分辨率Y
 14 VRAM    EQU        0x0ff8            ; 圖像緩衝區的開始地址
 15 
 16         ORG        0xc200            ; 這個程序要裝在到什麼位置
 17 
 18         MOV        AL,0x13            ; VGA顯卡,320X200X8位色彩
 19         MOV        AH,0x00
 20         INT        0x10
 21         MOV        BYTE [VMODE],8    ; 記錄畫面模式
 22         MOV        WORD [SCRNX],320
 23         MOV        WORD [SCRNY],200
 24         MOV        DWORD [VRAM],0x000a0000
 25 
 26 ; 用BIOS得到鍵盤上各類LED指示燈的狀態
 27         MOV        AH,0x02
 28         INT        0x16             ; keyboard BIOS
 29         MOV        [LEDS],AL
 30 
 31 ; PIC偑堦愗偺妱傝崬傒傪庴偗晅偗側偄傛偆偵偡傞
 32 ;    AT屳姺婡偺巇條偱偼丄PIC偺弶婜壔傪偡傞側傜丄
 33 ;    偙偄偮傪CLI慜偵傗偭偰偍偐側偄偲丄偨傑偵僴儞僌傾僢僾偡傞
 34 ;    PIC偺弶婜壔偼偁偲偱傗傞
 35 
 36         MOV        AL,0xff
 37         OUT        0x21,AL
 38         NOP                        ; OUT柦椷傪楢懕偝偣傞偲偆傑偔偄偐側偄婡庬偑偁傞傜偟偄偺偱
 39         OUT        0xa1,AL
 40 
 41         CLI                        ; 偝傜偵CPU儗儀儖偱傕妱傝崬傒嬛巭
 42 
 43 ; CPU偐傜1MB埲忋偺儊儌儕偵傾僋僙僗偱偒傞傛偆偵丄A20GATE傪愝掕
 44 
 45         CALL    waitkbdout
 46         MOV        AL,0xd1
 47         OUT        0x64,AL
 48         CALL    waitkbdout
 49         MOV        AL,0xdf            ; enable A20
 50         OUT        0x60,AL
 51         CALL    waitkbdout
 52 
 53 ; 僾儘僥僋僩儌乕僪堏峴
 54 
 55 [INSTRSET "i486p"]                ; 486偺柦椷傑偱巊偄偨偄偲偄偆婰弎
 56 
 57         LGDT    [GDTR0]            ; 巄掕GDT傪愝掕
 58         MOV        EAX,CR0
 59         AND        EAX,0x7fffffff    ; bit31傪0偵偡傞乮儁乕僕儞僌嬛巭偺偨傔乯
 60         OR        EAX,0x00000001    ; bit0傪1偵偡傞乮僾儘僥僋僩儌乕僪堏峴偺偨傔乯
 61         MOV        CR0,EAX
 62         JMP        pipelineflush
 63 pipelineflush:
 64         MOV        AX,1*8            ;  撉傒彂偒壜擻僙僌儊儞僩32bit
 65         MOV        DS,AX
 66         MOV        ES,AX
 67         MOV        FS,AX
 68         MOV        GS,AX
 69         MOV        SS,AX
 70 
 71 ; bootpack偺揮憲
 72 
 73         MOV        ESI,bootpack    ; 揮憲尦
 74         MOV        EDI,BOTPAK        ; 揮憲愭
 75         MOV        ECX,512*1024/4
 76         CALL    memcpy
 77 
 78 ; 偮偄偱偵僨傿僗僋僨乕僞傕杮棃偺埵抲傊揮憲
 79 
 80 ; 傑偢偼僽乕僩僙僋僞偐傜
 81 
 82         MOV        ESI,0x7c00        ; 揮憲尦
 83         MOV        EDI,DSKCAC        ; 揮憲愭
 84         MOV        ECX,512/4
 85         CALL    memcpy
 86 
 87 ; 巆傝慡晹
 88 
 89         MOV        ESI,DSKCAC0+512    ; 揮憲尦
 90         MOV        EDI,DSKCAC+512    ; 揮憲愭
 91         MOV        ECX,0
 92         MOV        CL,BYTE [CYLS]
 93         IMUL    ECX,512*18*2/4    ; 僔儕儞僟悢偐傜僶僀僩悢/4偵曄姺
 94         SUB        ECX,512/4        ; IPL偺暘偩偗嵎偟堷偔
 95         CALL    memcpy
 96 
 97 ; asmhead偱偟側偗傟偽偄偗側偄偙偲偼慡晹偟廔傢偭偨偺偱丄
 98 ;    偁偲偼bootpack偵擟偣傞
 99 
100 ; bootpack偺婲摦
101 
102         MOV        EBX,BOTPAK
103         MOV        ECX,[EBX+16]
104         ADD        ECX,3            ; ECX += 3;
105         SHR        ECX,2            ; ECX /= 4;
106         JZ        skip            ; 揮憲偡傞傋偒傕偺偑側偄
107         MOV        ESI,[EBX+20]    ; 揮憲尦
108         ADD        ESI,EBX
109         MOV        EDI,[EBX+12]    ; 揮憲愭
110         CALL    memcpy
111 skip:
112         MOV        ESP,[EBX+12]    ; 僗僞僢僋弶婜抣
113         JMP        DWORD 2*8:0x0000001b
114 
115 waitkbdout:
116         IN         AL,0x64
117         AND         AL,0x02
118         JNZ        waitkbdout        ; AND偺寢壥偑0偱側偗傟偽waitkbdout傊
119         RET
120 
121 memcpy:
122         MOV        EAX,[ESI]
123         ADD        ESI,4
124         MOV        [EDI],EAX
125         ADD        EDI,4
126         SUB        ECX,1
127         JNZ        memcpy            ; 堷偒嶼偟偨寢壥偑0偱側偗傟偽memcpy傊
128         RET
129 ; memcpy偼傾僪儗僗僒僀僘僾儕僼傿僋僗傪擖傟朰傟側偗傟偽丄僗僩儕儞僌柦椷偱傕彂偗傞
130 
131         ALIGNB    16
132 GDT0:
133         RESB    8                ; 僰儖僙儗僋僞
134         DW        0xffff,0x0000,0x9200,0x00cf    ; 撉傒彂偒壜擻僙僌儊儞僩32bit
135         DW        0xffff,0x0000,0x9a28,0x0047    ; 幚峴壜擻僙僌儊儞僩32bit乮bootpack梡乯
136 
137         DW        0
138 GDTR0:
139         DW        8*3-1
140         DD        GDT0
141 
142         ALIGNB    16
143 bootpack:
asmhead.asm
1 void HariMain(void)
2 {
3 fin:
4     /* 這裏想寫上HLT,可是C語言中不能使用HLT! */
5     goto fin;
6 }
bootpack.c

下面說一下C語言部分:(之後爲了啓動操做系統還須要不少處理函數,因此就把這些處理函數打成一個包,爲了好理解就取了bootpack名字),這裏有c語言基礎的人一眼就懂這個簡單程序的意思了~關鍵是它如何變成機器語言的呢?下面就是詳細過程:

  • 首先:使用cc1.exe從bootpack.c生成bootpack.gas[這一步主要實現將c語言編譯爲gas彙編]
  • 第二步:使用gas2nask.exe從bootpack.gas生成bootpack.nas[這一步主要實現從gas彙編到nas彙編]
  • 第三步:使用nask.exe從bootpack.nas生成bootpack.obj[將nas彙編編譯爲機器語言]
  • 第四步:使用bim2bim.exe從bootpack.obj生成bootpack.bim[製成二進制映像文件]
  • 第五步:使用bim2hrb.exe從bootpack.bim生成bootpack.hrb[將映像製成對應操做系統所須要的文件]
  • 最後:這樣就作成了機器語言,再適用copy指令將asmhead.bin和bootpack.hrb單純結合起來,就製成了haribote.sys[合併造成系統文件]

PS: 1) C語言編譯生成的彙編不是nask彙編,因此要有一、2兩步將c語言轉換爲nask彙編

   2) 咱們用從C語言轉換來的nask彙編而後轉換成的機器語言是一種特殊的obj機器語言,必須與其餘文件連接(link)以後才能造成真正能夠運行的機器語言

   3) 這裏咱們把obj轉換爲bim映像其實就是將各個分部分連接在一塊兒,作成一個完整的機器文件

   4) 此外,咱們爲了能讓上面完整的機器語言實際使用,還要針對不一樣操做系統進行必要的加工,好比說加上識別文件頭、壓縮等

PS: 有人在windows和linux上也作過不少次C語言開發,可是也沒有這麼煩,說到底,是人家的編譯器已經很成熟啦!咱們爲了要開發出適用不一樣平臺的操做系統甚至是本身的操做系統,就沒有將中間的過程省略~

PS: 這裏的HariMain不要改動名字[由於程序要從這個地方開始運行,就像main函數的main]

>_<" 這裏又要新建一個文件了:naskfunc.nas 它的功能就是用匯編寫一些函數,供c語言調用(由於上面已經說過,32位模式下沒法適用BIOS等功能),這個文件裏主要寫一些要用匯編實現的功能函數~

 1 ; naskfunc
 2 ; TAB=4
 3 
 4 [FORMAT "WCOFF"]                ; 製成目標文件的形式    
 5 [BITS 32]                        ; 製做32模式用的機器語言
 6 
 7 
 8 ; 製做目標文件信息
 9 
10 [FILE "naskfunc.nas"]            ; 源文件名信息
11 
12         GLOBAL    _io_hlt            ; 程序中包含的函數名
13 
14 
15 ; 如下是實際的函數
16 
17 [SECTION .text]        ; 目標文件中寫了這些後再寫程序
18 
19 _io_hlt:    ; void io_hlt(void);
20         HLT
21         RET

PS: 用匯編寫的函數,以後還要與bootpack.obj連接,因此也須要編譯成目標文件。所以將輸出格式設置爲WCOFF模式,另外還要設置爲32位機器語言模式。在nask目標文件的模式下,必須設定文件名信息,而後再寫明下面函數的名,注意這裏的函數名前面要加」-「而且聲明爲GLOBAL。再往下就是實際的函數了,這裏很簡單~這裏在bootpack.c要調用這個函數很簡單,以下:

 1 /* 告訴c編譯器,有一個函數在別的文件裏 */
 2 
 3 void io_hlt(void);
 4 
 5 void HariMain(void)
 6 {
 7 
 8 fin:
 9     io_hlt(); /*執行naskfunc.nas裏的_io_hlt*/
10     goto fin;
11 }

 

3.3 C語言實現內存寫入

>_<" 上面已經實現了讓畫面黑屏,可是隻作到這一點沒意思,仍是在畫面上畫點東西比較有趣。想要畫東西的話,只要往VRAM裏寫點東西就能夠了,可是c語言中又沒有直接寫入指定內存地址的語句(實際上是有的,一步步來)。因此咱們直接用匯編寫一個函數,在naskfunc.nas裏添加以下部分:

1 _write_mem8:    ; void write_mem8(int addr, int data);
2         MOV        ECX,[ESP+4]        ; [ESP+4]中存放的是地址,將其讀入ECX
3         MOV        AL,[ESP+8]        ; [ESP+8]中存放的是數據,將其讀入AL
4         MOV        [ECX],AL
5         RET
 1 ; naskfunc
 2 ; TAB=4
 3 
 4 [FORMAT "WCOFF"]                 ; 製成目標文件的形式   
 5 [INSTRSET "i486p"]                 ; 指明是486用的,EAX[新加的一條]
 6 [BITS 32]                        ; 製做32模式用的機器語言
 7 
 8 ; 製做目標文件信息
 9 [FILE "naskfunc.nas"]            ; 源文件名信息
10         GLOBAL    _io_hlt,_write_mem8     ;程序中包含的函數名
11 
12 ; 如下是實際的函數
13 [SECTION .text]        ; 目標文件中寫了這些後再寫程序
14 
15 _io_hlt:    ; void io_hlt(void);
16         HLT
17         RET
18 
19 _write_mem8:    ; void write_mem8(int addr, int data);
20         MOV        ECX,[ESP+4]        ; [ESP+4]中存放的是地址,將其讀入ECX
21         MOV        AL,[ESP+8]        ; [ESP+8]中存放的是數據,將其讀入AL
22         MOV        [ECX],AL
23         RET
naskfunc。nas所有代碼[除了上面說的函數外,還有其餘部分也作了修改]

上面的函數在c語言裏調用write_mem8(0x1234,0x56);語句時,就至關於MOV BYTE[0x1234],0x56。若是C語言中調用了write_mem8函數,就會跳轉到_write_mem8。此時參數指定的數字就是放在內存裏,分別是:

  • 第一個數字的存放地址:[ESP+4]
  • 第二個數字的存放地址:[ESP+8]
  • 第三個數字的存放地址:[ESP+12]
  • 第四個數字的存放地址:[ESP+16]
  • (依次類推...)

那麼在bootpack.c裏面調用這個函數填寫VRAM內存的方法以下:

 1 void io_hlt(void);
 2 void write_mem8(int addr, int data);
 3 
 4 void HariMain(void)
 5 {
 6     int i; /* 聲明變量i,i是一個32位的整數 */
 7 
 8     for (i = 0xa0000; i <= 0xaffff; i++) { //遍歷VRAM地址,每一個寫入15
 9         write_mem8(i, 15); /* MOV BYTE [i],15 */
10     }
11 
12     for (;;) {
13         io_hlt();
14     }
15 }

效果以下:整個屏幕變成了白色,這是由於向VRAM內都寫入的15,意思是全部顏色都是第15個顏色,而第15個顏色正好是純白色!

 

如今咱們稍微改動一下,寫入VRAM中的變量看看會有啥效果,咱們將循環中的write_mem8(i,15)改爲write_mem8(i,i & 0x0f),效果以下:咱們這種寫法就至關於每次寫入i%16,因此每一個16個像素,色號就反覆一次,而總體呈現出以下的條紋圖案:

 

3.4 C語言指針的強大

>_<" 上一節開頭說過:c語言不能對內存進行讀寫,其實不是,c語言的指針能完美地完成內存讀寫的工做,這裏就用c語言的指針代替上面用匯編寫的write_mem8函數實現內存寫入。

 1 void io_hlt(void);
 2 
 3 void HariMain(void)
 4 {
 5     int i; 
 6     char *p; /*用於BYTE型地址*/
 7 
 8     for (i = 0xa0000; i <= 0xaffff; i++) {
 9 
10         p = i; /* 帶入地址 */
11         *p = (char*)i & 0x0f;
12 
13         /* 代替 write_mem8(i, i & 0x0f); */
14     }
15 
16     for (;;) {
17         io_hlt();
18     }
19 }

這樣咱們就完美的代替了彙編寫的write_mem8函數,不得感嘆一句指針真實強大(其實關於指針的不少細節,這裏實在說不了了,可是它很強大,很強大~)!這裏只說幾點:

  • char *p;是BYTE類地址--short *p;是用於WORD類地址--int *p是用於DWORD類地址
  • 其實這樣寫就不用聲明個p了:((char *)i)=i & 0x0f    ps:這種寫法和BYTE[i]=i & 0x0f有些像吧
  • p表示地址,*p表示地址的內容
  • char *p是聲明p,通常把*靠在p上是爲了想聲明2個指針時更清晰:char *p,*q;
  • *(p+i)也能夠寫成p[i]形式,可是這裏p[i]不是數組,由於這裏*(p+i)能夠*(i+p)也行,即i[p]也對

 

3.5 色號設定與調色板

>_<" 咱們想經過上面的內存寫入能夠畫出一些亂的圖案,可是咱們想具體畫一些東西的時候就要考慮顏色問題了。這裏咱們採用的是320X200的8位顏色模式,色號使用8位(二進制數),也就是隻能從0~255的數。熟悉電腦顏色的人應該知道這是不多的,像電腦裏通常用6位16進制的數,即24位(二進制數)來指定顏色。那麼該怎樣來指定顏色呢?

>_<" 這個8位色彩模式,是由程序員隨意指定0~255的數字所對應的顏色。好比:25號對應#ffffff,26號對應#123456,若是像剛纔那樣程序員不作任何指定,0號就是#000000,15號就是#ffffff。這裏咱們想要製做個操做系統,所以由前輩的經驗知道,只要用如下16種顏色就夠了:

  • #000000:黑    #00ffff:淺亮色    #000084:暗藍    #ff0000:亮紅    #ffffff:白    #840084:暗紫    #00ff00:亮綠    #c6c6c6:亮灰
  • #008484:淺暗藍   #ffff00:亮黃    #840000:暗紅    #848484:暗灰    #0000ff:亮藍    #008400:暗綠    #ff00ff:亮紫    #848400:暗黃

因此要對bootpack.c進行較大的修改:

 1 /*彙編裏面的函數*/
 2 void io_hlt(void);
 3 void io_cli(void);   //彙編函數,禁止中斷
 4 void io_out8(int port, int data);  //向指定的設備傳送數據(第一參數是設備號,第二參數是傳送數據)
 5 int io_load_eflags(void);   //用匯編寫的函數,經過棧的處理得到當前中斷標誌
 6 void io_store_eflags(int eflags);  //用匯編寫的函數,經過棧的處理設置當前中斷標誌
 7 
 8 /*同一個文件中的函數*/
 9 void init_palette(void);
10 void set_palette(int start, int end, unsigned char *rgb);
11 
12 void HariMain(void)
13 {
14     int i;
15     char *p; 
16 
17     init_palette(); /*設定調色板*/
18 
19     p = (char *) 0xa0000; /*指定地址*/
20 
21     for (i = 0; i <= 0xffff; i++) {
22         p[i] = i & 0x0f;
23     }
24 
25     for (;;) {
26         io_hlt();
27     }
28 }
29 
30 void init_palette(void)
31 {
32     static unsigned char table_rgb[16 * 3] = {
33         0x00, 0x00, 0x00,    /*  0:黑 */
34         0xff, 0x00, 0x00,    /*  1:亮紅 */
35         0x00, 0xff, 0x00,    /*  2:亮綠 */
36         0xff, 0xff, 0x00,    /*  3:亮黃 */
37         0x00, 0x00, 0xff,    /*  4:亮藍 */
38         0xff, 0x00, 0xff,    /*  5:亮紫 */
39         0x00, 0xff, 0xff,    /*  6:淺亮藍 */
40         0xff, 0xff, 0xff,    /*  7:白 */
41         0xc6, 0xc6, 0xc6,    /*  8:亮灰 */
42         0x84, 0x00, 0x00,    /*  9:暗紅 */
43         0x00, 0x84, 0x00,    /* 10:暗綠 */
44         0x84, 0x84, 0x00,    /* 11:暗黃 */
45         0x00, 0x00, 0x84,    /* 12:暗青 */
46         0x84, 0x00, 0x84,    /* 13:暗紫 */
47         0x00, 0x84, 0x84,    /* 14:淺暗藍 */
48         0x84, 0x84, 0x84    /* 15:暗灰 */
49     };
50     set_palette(0, 15, table_rgb);
51     return;
52     /*C語言中static char只能用於數據,就像彙編中的DB指令 */
53 }
54 
55 void set_palette(int start, int end, unsigned char *rgb)
56 {
57     int i, eflags;
58     eflags = io_load_eflags();    /* 記錄中斷許可標誌 */
59     io_cli();                     /* 將中斷許可標誌置0,禁止中斷 */
60     io_out8(0x03c8, start);
61     for (i = start; i <= end; i++) {
62         io_out8(0x03c9, rgb[0] / 4);
63         io_out8(0x03c9, rgb[1] / 4);
64         io_out8(0x03c9, rgb[2] / 4);
65         rgb += 3;
66     }
67     io_store_eflags(eflags);    /* 恢復原中斷 */
68     return;
69 }
新的bootpack.c
 1 ; naskfunc
 2 ; TAB=4
 3 
 4 [FORMAT "WCOFF"]                
 5 [INSTRSET "i486p"]                
 6 [BITS 32]                        
 7 [FILE "naskfunc.nas"]            
 8 
 9         GLOBAL    _io_hlt, _io_cli, _io_sti, _io_stihlt
10         GLOBAL    _io_in8,  _io_in16,  _io_in32
11         GLOBAL    _io_out8, _io_out16, _io_out32
12         GLOBAL    _io_load_eflags, _io_store_eflags
13 
14 [SECTION .text]
15 
16 _io_hlt:    ; void io_hlt(void);
17         HLT
18         RET
19 
20 _io_cli:    ; void io_cli(void);
21         CLI
22         RET
23 
24 _io_sti:    ; void io_sti(void);
25         STI
26         RET
27 
28 _io_stihlt:    ; void io_stihlt(void);
29         STI
30         HLT
31         RET
32 
33 _io_in8:    ; int io_in8(int port);
34         MOV        EDX,[ESP+4]        ; port
35         MOV        EAX,0
36         IN        AL,DX
37         RET
38 
39 _io_in16:    ; int io_in16(int port);
40         MOV        EDX,[ESP+4]        ; port
41         MOV        EAX,0
42         IN        AX,DX
43         RET
44 
45 _io_in32:    ; int io_in32(int port);
46         MOV        EDX,[ESP+4]        ; port
47         IN        EAX,DX
48         RET
49 
50 _io_out8:    ; void io_out8(int port, int data);
51         MOV        EDX,[ESP+4]        ; port
52         MOV        AL,[ESP+8]        ; data
53         OUT        DX,AL
54         RET
55 
56 _io_out16:    ; void io_out16(int port, int data);
57         MOV        EDX,[ESP+4]        ; port
58         MOV        EAX,[ESP+8]        ; data
59         OUT        DX,AX
60         RET
61 
62 _io_out32:    ; void io_out32(int port, int data);
63         MOV        EDX,[ESP+4]        ; port
64         MOV        EAX,[ESP+8]        ; data
65         OUT        DX,EAX
66         RET
67 
68 _io_load_eflags:    ; int io_load_eflags(void);
69         PUSHFD        ; 指 PUSH EFLAGS 
70         POP        EAX
71         RET
72 
73 _io_store_eflags:    ; void io_store_eflags(int eflags);
74         MOV        EAX,[ESP+4]
75         PUSH    EAX
76         POPFD        ; 指 POP EFLAGS 
77         RET
新的naskfunc.nas

PS: 這裏要作幾點說明(這篇文章說的太多了,很少說還說不清,早知道不把這麼多放在一塊兒了!)

1)訪問調色板的步驟:(具體參照bootpack.c中的set_palette函數)

  • 屏蔽中斷(CLI)
  • 將想要設定的調色板號寫入0x03c8,緊接着按着R,G,B的順序寫入0x03c9,若是想繼續設定下一個調色板,省略調色板號,繼續按照RGB順序寫入0x03c9
  • 想要讀出當前調色板的狀態,首先要將調色板號寫入0x03c7,再從0x03c9依次讀3次,分別是R,G,B,若是想繼續讀取下一個,也是省略調色板號的設定繼續讀取
  • 若是最初執行了CLI那麼要恢復中斷STI

2)中斷標誌位的讀取和設置要涉及到棧的應用,這裏看一下代碼就理解了(前提是你得懂棧這種數據結構)

3)在set_palette中要注意關閉中斷與恢復中斷,這個在操做系統中特別是嵌入式操做系統中應用較多

如今運行一下程序看看效果:[仔細看,和上面那個條紋圖有點不同吧]

 

3.6 簡單界面實現

>_<" 上面咱們已經把調色板配好了,接下來看看咱們的繪畫能力了,這裏咱們稍微改動一下bootpack.c裏面的函數,實現畫矩形的功能:

 1 void io_hlt(void);
 2 void io_cli(void);
 3 void io_out8(int port, int data);
 4 int io_load_eflags(void);
 5 void io_store_eflags(int eflags);
 6 
 7 void init_palette(void);
 8 void set_palette(int start, int end, unsigned char *rgb);
 9 void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
10 
11 #define COL8_000000        0
12 #define COL8_FF0000        1
13 #define COL8_00FF00        2
14 #define COL8_FFFF00        3
15 #define COL8_0000FF        4
16 #define COL8_FF00FF        5
17 #define COL8_00FFFF        6
18 #define COL8_FFFFFF        7
19 #define COL8_C6C6C6        8
20 #define COL8_840000        9
21 #define COL8_008400        10
22 #define COL8_848400        11
23 #define COL8_000084        12
24 #define COL8_840084        13
25 #define COL8_008484        14
26 #define COL8_848484        15
27 
28 void HariMain(void)
29 {
30     char *p; 
31 
32     init_palette(); 
33 
34     p = (char *) 0xa0000; 
35 
36     boxfill8(p, 320, COL8_FF0000,  20,  20, 120, 120);
37     boxfill8(p, 320, COL8_00FF00,  70,  50, 170, 150);
38     boxfill8(p, 320, COL8_0000FF, 120,  80, 220, 180);
39 
40     for (;;) {
41         io_hlt();
42     }
43 }
44 
45 void init_palette(void)
46 {
47     static unsigned char table_rgb[16 * 3] = {
48         0x00, 0x00, 0x00,    
49         0xff, 0x00, 0x00,    
50         0x00, 0xff, 0x00,    
51         0xff, 0xff, 0x00,    
52         0x00, 0x00, 0xff,    
53         0xff, 0x00, 0xff,    
54         0x00, 0xff, 0xff,    
55         0xff, 0xff, 0xff,    
56         0xc6, 0xc6, 0xc6,    
57         0x84, 0x00, 0x00,    
58         0x00, 0x84, 0x00,    
59         0x84, 0x84, 0x00,    
60         0x00, 0x00, 0x84,    
61         0x84, 0x00, 0x84,    
62         0x00, 0x84, 0x84,    
63         0x84, 0x84, 0x84    
64     };
65     set_palette(0, 15, table_rgb);
66     return;
67 }
68 
69 void set_palette(int start, int end, unsigned char *rgb)
70 {
71     int i, eflags;
72     eflags = io_load_eflags();    
73     io_cli();                 
74     io_out8(0x03c8, start);
75     for (i = start; i <= end; i++) {
76         io_out8(0x03c9, rgb[0] / 4);
77         io_out8(0x03c9, rgb[1] / 4);
78         io_out8(0x03c9, rgb[2] / 4);
79         rgb += 3;
80     }
81     io_store_eflags(eflags);
82     return;
83 }
84 
85 void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
86 {
87     int x, y;
88     for (y = y0; y <= y1; y++) {
89         for (x = x0; x <= x1; x++)
90             vram[y * xsize + x] = c;
91     }
92     return;
93 }
繪製矩形例子的bootpack.c

>_<" 進一步咱們繪製一個像樣點的窗口:[哈哈,有點那個意思了吧!]

  1 void io_hlt(void);
  2 void io_cli(void);
  3 void io_out8(int port, int data);
  4 int io_load_eflags(void);
  5 void io_store_eflags(int eflags);
  6 
  7 void init_palette(void);
  8 void set_palette(int start, int end, unsigned char *rgb);
  9 void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1);
 10 
 11 #define COL8_000000        0
 12 #define COL8_FF0000        1
 13 #define COL8_00FF00        2
 14 #define COL8_FFFF00        3
 15 #define COL8_0000FF        4
 16 #define COL8_FF00FF        5
 17 #define COL8_00FFFF        6
 18 #define COL8_FFFFFF        7
 19 #define COL8_C6C6C6        8
 20 #define COL8_840000        9
 21 #define COL8_008400        10
 22 #define COL8_848400        11
 23 #define COL8_000084        12
 24 #define COL8_840084        13
 25 #define COL8_008484        14
 26 #define COL8_848484        15
 27 
 28 void HariMain(void)
 29 {
 30     char *vram;
 31     int xsize, ysize;
 32 
 33     init_palette();
 34     vram = (char *) 0xa0000;
 35     xsize = 320;
 36     ysize = 200;
 37 
 38     boxfill8(vram, xsize, COL8_008484,  0,         0,          xsize -  1, ysize - 29);
 39     boxfill8(vram, xsize, COL8_C6C6C6,  0,         ysize - 28, xsize -  1, ysize - 28);
 40     boxfill8(vram, xsize, COL8_FFFFFF,  0,         ysize - 27, xsize -  1, ysize - 27);
 41     boxfill8(vram, xsize, COL8_C6C6C6,  0,         ysize - 26, xsize -  1, ysize -  1);
 42 
 43     boxfill8(vram, xsize, COL8_FFFFFF,  3,         ysize - 24, 59,         ysize - 24);
 44     boxfill8(vram, xsize, COL8_FFFFFF,  2,         ysize - 24,  2,         ysize -  4);
 45     boxfill8(vram, xsize, COL8_848484,  3,         ysize -  4, 59,         ysize -  4);
 46     boxfill8(vram, xsize, COL8_848484, 59,         ysize - 23, 59,         ysize -  5);
 47     boxfill8(vram, xsize, COL8_000000,  2,         ysize -  3, 59,         ysize -  3);
 48     boxfill8(vram, xsize, COL8_000000, 60,         ysize - 24, 60,         ysize -  3);
 49 
 50     boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 24, xsize -  4, ysize - 24);
 51     boxfill8(vram, xsize, COL8_848484, xsize - 47, ysize - 23, xsize - 47, ysize -  4);
 52     boxfill8(vram, xsize, COL8_FFFFFF, xsize - 47, ysize -  3, xsize -  4, ysize -  3);
 53     boxfill8(vram, xsize, COL8_FFFFFF, xsize -  3, ysize - 24, xsize -  3, ysize -  3);
 54 
 55     for (;;) {
 56         io_hlt();
 57     }
 58 }
 59 
 60 void init_palette(void)
 61 {
 62     static unsigned char table_rgb[16 * 3] = {
 63         0x00, 0x00, 0x00,    
 64         0xff, 0x00, 0x00,    
 65         0x00, 0xff, 0x00,    
 66         0xff, 0xff, 0x00,    
 67         0x00, 0x00, 0xff,    
 68         0xff, 0x00, 0xff,    
 69         0x00, 0xff, 0xff,    
 70         0xff, 0xff, 0xff,    
 71         0xc6, 0xc6, 0xc6,    
 72         0x84, 0x00, 0x00,    
 73         0x00, 0x84, 0x00,    
 74         0x84, 0x84, 0x00,    
 75         0x00, 0x00, 0x84,    
 76         0x84, 0x00, 0x84,    
 77         0x00, 0x84, 0x84,    
 78         0x84, 0x84, 0x84    
 79     };
 80     set_palette(0, 15, table_rgb);
 81     return;
 82 }
 83 
 84 void set_palette(int start, int end, unsigned char *rgb)
 85 {
 86     int i, eflags;
 87     eflags = io_load_eflags();    
 88     io_cli();                 
 89     io_out8(0x03c8, start);
 90     for (i = start; i <= end; i++) {
 91         io_out8(0x03c9, rgb[0] / 4);
 92         io_out8(0x03c9, rgb[1] / 4);
 93         io_out8(0x03c9, rgb[2] / 4);
 94         rgb += 3;
 95     }
 96     io_store_eflags(eflags);
 97     return;
 98 }
 99 
100 void boxfill8(unsigned char *vram, int xsize, unsigned char c, int x0, int y0, int x1, int y1)
101 {
102     int x, y;
103     for (y = y0; y <= y1; y++) {
104         for (x = x0; x <= x1; x++)
105             vram[y * xsize + x] = c;
106     }
107     return;
108 }
繪製一個窗口的bootpack.c文件
 
 
LZ說明:沒想到一口氣居然說了這麼多,總結一下,其實就揭示了一個過程:編譯器是如何從c等高級語言轉換爲機器語言而後控制硬件呈現效果的~裏面涉及的知識略多,有些確實不能用幾句話說完~明天就要上課了,今天就到這裏吧~( http://www.cnblogs.com/zjutlitao/)
相關文章
相關標籤/搜索