30天自制作業系統——第3天實驗總結
實驗日期 | 實驗專案 |
---|---|
2020.10.15 | 第3天 進入32位模式並匯入C語言 |
文章目錄
一、實驗主要內容
1、 內容1 製作真正的IPL
(1).內容概要
- 實驗內容:認識軟盤的結構,並使用IPL來裝載程式;優化Makefile內容,使用變數定義去簡化Makefile的寫法。
- 實驗重點:能夠使用匯編去讀取磁碟,清楚呼叫0x13號BIOS的相關值的設定。使用IPL來裝載程式。
軟盤的結構:軟盤為多層環狀磁條組成。一共有80個柱面(0-79號),每個柱面有18個扇區(1-18號),讀取時區分正反面,其中正面為磁頭0,反面為磁頭1。描述磁碟的某個位置時 可以用Cx-Hy-Sz表示,例如本次實驗中含有IPL的啟動區就位於C0-H0-S1(柱面0,磁頭0,扇區1)磁碟結構示意圖如下所示:
Makefile檔案中的變數表示:在Makefile檔案中將一些經常用到的路徑或者命令設定為變數,定義在檔案開頭,當編寫命令時,用到這些變數時,只需要將變數名外加上括號和$即可。簡化了Makefile的書寫。
記憶體地址的裝載:啟動區在記憶體地址0x7c00 ~ 0x7dff,用於啟動載入程式,軟盤的啟動區在0x8000~0x81ff,軟盤的資料從0x8200開始裝載,即第2扇區開始,每個扇區所佔空間為512個位元組。
(2).關鍵程式碼分析
;讀取磁碟
MOV AX,0x0820
MOV ES,AX
MOV CH,0 ; 柱面0
MOV DH,0 ; 磁頭0
MOV CL,2 ; 扇區2
MOV AH,0x02 ; AH=0x02 : 表示讀取磁碟操作
MOV AL,1 ; 1個磁碟
MOV BX,0
MOV DL,0x00 ; A驅動器
INT 0x13 ;呼叫磁碟BIOS
JC error ;jump if carry 如果進位值為1,說明出現了錯誤跳轉到error輸出錯誤資訊
這部分程式碼是在第2天內容的基礎上新增的讀取磁碟的操作,讀取磁碟相關的暫存器的設定根據筆者的書總結如下:
暫存器 | 設定的值 | 表示的含義 |
---|---|---|
AH | 0x02 | 讀取磁碟 |
AH | 0x03 | 寫入磁碟 |
AH | 0x04 | 校驗 |
AH | 0x0c | 尋道 |
AL | x | x表示處理的扇區數,這裡只能是連續的扇區 |
CH | 柱面號&0xff | 軟盤的柱面號 |
CL | 扇區號(0-5位) | (柱面號&0x300)>>2 |
DH | 0或1 | 表示軟盤的磁頭的正面或者反面 |
DL | 驅動器號 | 驅動器號 |
ES:BX | 緩衝地址 | 表示的實際地址為ES*16+BX |
上述暫存器的值在每次讀取磁碟時都需要進行相應的設定。另外,返回值在這裡是用來檢測是否有錯誤的,如果FLAGS.CF為1說明有錯誤,錯誤號碼存入AH內,否則AH=0。
其餘程式碼部分和第2天的程式碼一致。
2、 內容2 試錯
(1).內容概要
- 實驗內容:軟盤在讀取過程中可能會出現一些意料之外的錯誤,本次實驗將重複讀取磁碟多次,避免偶爾磁碟出錯帶來的影響。
(2).關鍵程式碼分析
;讀取磁碟
MOV AX,0x0820
MOV ES,AX
MOV CH,0 ; 柱面0
MOV DH,0 ; 磁頭0
MOV CL,2 ; 扇區2
MOV SI,0 ; 記錄讀取失敗的次數,如果次數超過5次,則輸出錯誤資訊
retry:
MOV AH,0x02 ; AH=0x02 : 讀入磁碟
MOV AL,1 ; 1個扇區
MOV BX,0
MOV DL,0x00 ; A驅動器
INT 0x13 ; 呼叫磁碟BIOS
JNC fin ; 沒有出錯則跳轉到fin
ADD SI,1 ; 出錯了,SI記錄的次數+1
CMP SI,5 ; SI和5比較
JAE error ; SI >= 5 跳轉到error
MOV AH,0x00
MOV DL,0x00 ; A驅動器
INT 0x13 ; 重置驅動器
JMP retry ;繼續嘗試
這部分程式碼設定了多次讀取磁碟的操作,如果沒有讀取成功,則一直重複retry部分的程式碼。JNC指令表示進位標誌位是0就跳轉;JAE表示大於或等於時跳轉。在重新讀取磁碟前,需要進行系統復位,即“AH=0x00,DL=0x00,INT 0x13”
3、 內容3 讀到18扇區和讀入10個柱面
(1).內容概要
- 實驗內容: 學會讀入18個扇區和10個柱面的方法。
指定處理的扇區數,範圍在0x01~0xff(指定0x02以上數值時,需要特別注意能夠處理多個扇區的條件。如果是FD的話,就不能跨越多個磁軌,也不能超過64KB的界限。
(2).關鍵程式碼分析
readloop部分和retry部分
readloop:
MOV SI ,0 ; 記錄失敗次數
retry:
MOV AH,0x02
MOV Al ,1 ;一個扇區,這裡是一個扇區一個扇區讀取
MOV BX,0
MOV DL,0x00 ;驅動器A
INT 0x13 ;呼叫BIOS
JNC next ;沒有出錯就跳轉到next,next是讀取磁碟
ADD SI ,1 ;SI 加1,記錄失敗次數
CMP SI ,5 ;和試錯允許次數5比較
JAE error ;超過允許的範圍,則跳轉到error,輸出錯誤資訊
MOV AH, 0x00
MOV DL ,0x00
INT 0x13 ;這三句表示重置驅動器
JMP retry
這部分程式碼是多次讀取磁碟,防止偶爾磁碟出錯帶來的問題。如果沒有出錯,則跳轉到next讀取下一個扇區。
next部分:
next:
MOV AX,ES
ADD AX ,0x0020
MOV ES ,AX ;將記憶體地址後移0x200,相當於到下一個扇區起始地址
ADD CL,1 ;下一個扇區
CMP CL ,18 ;比較CL和18,即判斷是否讀到18扇區
JBE readloop ;每次讀取新的扇區前需要將記錄失敗次數的暫存器重複值為0
MOV CL,1 ;從扇區1開始
ADD DH,1 ;DH+1,表示從反面讀
CMP DH ,2
JB readloop ;
MOV DH,0 ;從正面開始讀
ADD CH,1 ;下一個柱面
CMP CH,CYLS ;比較CH和CYLS,即判斷是否讀完10個柱面
JB readloop
這部分程式碼的實現邏輯是先判斷是否讀到18個扇區,讀完18個扇區則從反面繼續讀,正反面讀取完成就開始讀取下一個柱面,直到讀取到指定的柱面。
4、 內容4 著手開發作業系統
(1).內容概要
- 實驗內容: 學會將自己編寫的小程式編譯後得到的sys檔案儲存映像檔案中;從啟動區執行作業系統;確認作業系統的執行情況。
- 實驗重點:瞭解從啟動區執行作業系統的簡單流程,並學會呼叫BOIS確認作業系統的實際執行情況。
儲存到映像中的步驟:
a.使用make install指令,將磁碟映像檔案寫入磁碟。
b.在Windows中開啟磁碟,將haribote.sys儲存到磁碟上。
c.使用工具將磁碟備份為磁碟映像。
一般向一個空軟盤中儲存檔案時,檔名會寫在0x002600以後的地方,檔案的內容會寫在0x004200以後的地方。當我們將作業系統本身的內容寫到名為haribote.sys的檔案中,再將其儲存到磁碟映像裡,確定好磁碟映像0x4200在記憶體中對應的地址位置,即可從啟動區執行作業系統。例如將我們編寫的nas檔案製作映像檔案後開啟結果如下:
顯示卡模式設定:設定AH=0x00,AL根據具體的數值設定相應的模式。其中0x03表示16色字元模式,8025;0x12表示VGA模式,6404804位彩色模式,獨特的4面儲存模式;0x13表示VGA圖形模式,320200*8為彩色模式,調色盤模式;0x6a表示擴充套件的VGA圖形模式;無返回值。
記憶體的地址分佈,下圖是實驗過程中找的記憶體的地址分割槽圖,對於理解筆者彙編的涉及到的地址有一定的幫助。
(2).關鍵程式碼分析
這部分程式碼的功能是使得CPU進行待機功能的小程式。ORG表示將磁碟的內容裝載到0xc200處。在ipl.nas中讀取磁碟完成後加上JMP 0xc200表示跳轉到0xc200。當裝載啟動區執行時,讀取磁碟完成後,就會跳轉到0xc200處執行我們預先使用ORG指令裝載好的程式內容。INT 0x10表示呼叫顯示卡,對應的暫存器AH設定為0x00,AL 設定為對應模式。
5、 內容5 進入32位模式,並匯入C語言,實現HLT指令
(1).內容概要
- 實驗內容: 瞭解進入32位模式下需要做哪些前期準備;學會將編寫的C語言程式匯入sys檔案;編寫實現特定功能的C語言程式,如HLT指令。
- 實驗重點:32位模式和16位模式下的區別;如何將一個C程式檔案變成一個彙編程式,並匯入sys檔案。
32位模式和16位模式:32位模式,指的是CPU的模式。CPU有32位和16兩種模式。如果通過16位模式啟動,使用AX和CX等暫存器會十分方便,而EAX和ECX等32位的暫存器就會比較麻煩。在不同的模式下機器語言的命令程式碼不一樣,解釋方法不一樣,故16位模式的機器語言在32位模式下不能執行。另外,32位下可以使用CPU的自我保護功能(識別出可疑的機器語言並進行遮蔽,以避免破壞系統)。
C語言檔案變成機器語言,並生成haribote.sys的基本操作步驟:
a.使用ccl.exe將bootpack.c生成bootpack.gas
b.使用gas2nask.exe將bootpack.gas生成bootpack.nas
c.使用nask.exe將bootpack.nas生成bootpack.obj
d.使用obi2bim.exe將bootpack.obj生成bootpack.bim
e.使用bim2hrb.exe將bootpack.bim生成bootpack.hrb
f.使用copy指令將asmhead.bin與bootpack.hrb結合生成baribote.sys檔案
整個過程的流程圖如下所示:
編寫c程式和彙編程式時需要注意,在nask目標檔案的模式下,必須設定檔名資訊,寫明程式的函式名。特別在函式名前需要加上“_”,否則就不能很好地與C語言函式連結,連結的函式名必須使用GLOBAL宣告。
(2).關鍵程式碼分析
haribote.nas程式碼
; BOOT_INFO
CYLS EQU 0x0ff0 ;設定啟動區
LEDS EQU 0x0ff1
VMODE EQU 0x0ff2 ; 關於顏色數目的資訊。顏色的位數
SCRNX EQU 0x0ff4 ; 解析度X
SCRNY EQU 0x0ff6 ; 解析度Y
VRAM EQU 0x0ff8 ; 圖形緩衝區的開始地址
ORG 0xc200 ; 程式被裝載到內容中的地址
MOV AL,0x13 ; VGA顯示卡,320*200*8位彩色
MOV AH,0x00
INT 0x10
MOV BYTE [VMODE],8 ; 記錄畫面模式
MOV WORD [SCRNX],320
MOV WORD [SCRNY],200
MOV DWORD [VRAM],0x000a0000
; 用BIOS取得鍵盤上各種LED指示燈的狀態
MOV AH,0x02
INT 0x16 ; keyboard BIOS
MOV [LEDS],AL
fin:
HLT
JMP fin
這部分程式碼主要是設定畫面模式,畫面的畫素數,顏色數和從BIOS取得的鍵盤資訊都儲存起來,儲存在記憶體中0x0ff0的位置處。
naskfunc.nas程式碼:
[FORMAT "WCOFF"] ; 製作目標檔案的模式
[BITS 32] ; 製作32位模式用的機器語言
; 製作目標檔案的資訊
[FILE "naskfunc.nas"] ; 程式中包含的函式名
GLOBAL _io_hlt ;
; 以下是實際的函式
[SECTION .text]
_io_hlt: ; void io_hlt(void);
HLT
RET
這部分程式碼是彙編寫的HLT指令的實現函式
bootpack.c的程式碼:
void io_hlt(void);/* 函式宣告用;表示函式在別的檔案中 */
void HariMain(void)
{
fin:
io_hlt(); /* 執行naskfunc.nas裡面的_io_hlt函式 */
goto fin;
}
這部分程式碼是用C語言寫的具有停機功能的程式,裡面呼叫了彙編程式碼寫的HLT指令。
二、遇到的問題及解決方法
1、 描述問題1
- 問題描述
在筆者書中提到,將軟盤內容讀到記憶體0x8200,記憶體結構中0x7c00 ~ 0x7dff用於載入ipl,0x7e00~0x7fff用於引導區執行時棧,為什麼計算0x4200對應位置時是從0x8000開始?
- 解決方法
通過上網查閱資料,BIOS將磁碟0位置的內容拷貝到了記憶體0x7c00處,執行啟動區的內容後,會將軟盤內容讀入第2個扇區即0x8200的位置,而0x4200是相對於0號地址中第1個扇區的起始地址,所以0x4200對應記憶體中0x8200+0x4200-0x200=0x8000+0x4200。
2、 描述問題2
- 問題描述:
- 解決方法
make –r img時沒有規則生成ipl10.bin檔案。仔細檢查後發現筆者Makefile檔案中使用的工具是去上一級目錄中z_tools裡面找,而我新建了一個資料夾,導致沒有工具生成ipl10.bin檔案。
修改Makefile檔案中所有對應路徑;將路徑修改為Makefile中對應的路徑,前者需要修改的地方太多,還是選擇後者吧。
三、程式設計創新點
1、 描述創新點1,關鍵程式碼及結果截圖
- 創新點1
根據教材58頁上VRAM儲存著畫面的畫素,而每個畫素在地址0xa0000~0xaffff中,改變地址裡邊的畫素即可改變顯示畫面。
- 關鍵程式碼
bootpack.c程式碼
void change(int s,int d);
void HariMain(void)
{
int i;
for(i=0xa0000;i<=0xaffff;i+=0x200)
{
if(i>0xaffff||i+10>0xaffff||i+20>0xaffff) break;
change(i,45);
change(i+10,10);
change(i+20,8);
}
}
這部分程式碼是用來修改制定地址中畫素,change函式用匯編程式碼編寫。
change程式碼
[FORMAT "WCOFF"] ; 製作目標檔案的模式
[INSTRSET "i486p"]
[BITS 32] ; 製作32位模式用的機器語言
; 製作目標檔案的資訊
[FILE "naskfunc.nas"] ; 程式中包含的函式名
GLOBAL _change ;
[SECTION .text]
_change: ; void change(int s,int d);
MOV ECX,[ESP++4]
MOV AL,[ESP+8]
MOV [ECX],AL
RET
函式呼叫過程中引數1,引數2放在棧中esp+4和esp+8的位置,故只需要將esp+8處的資料放到esp+4的地址中即可。
- 結果截圖
四、實驗心得體會
- 本次實驗是自制作業系統的第3天,學習的內容比較多,包括繼續介紹組合語言的相關指令和BIOS的呼叫;講解讀取磁碟的彙編程式;從啟動區開始執行作業系統,並確認其執行情況;進入32位模式匯入C語言等內容。有了之前組合語言的基礎,在閱讀教材的時候比較容易理解筆者所寫的彙編程式碼,比較不清楚的是關於軟盤的結構,磁碟和記憶體地址的對應關係,通過查閱相關資料,解決了自己遇到的問題。總體來說,這次實驗內容多,但是都不難理解,跟著筆者的講解一步步深入,實驗很容易完成。
- 在這次實驗中梳理C程式轉化為彙編程式碼的步驟時,用到了流程圖的方式描述,清晰簡潔,可以在以後學習過程中對繁雜步驟梳理,以便學習和理解。實驗中受到教材58頁VRAM儲存著畫面的畫素,於是想通過改變不同地址中畫素的大小來繪製簡單的圖案,這就是本次實驗我想到的創新點。另外,是否能用C程式實現其他功能,比如簡單加法輸出。
相關文章
- 30天自制作業系統——第4天實驗總結作業系統
- 30天自制作業系統 For Linux作業系統Linux
- 30天自制作業系統:第三天作業系統
- 《30天自制作業系統》譯者序(偽)作業系統
- 30天自制作業系統(一)啟動區作業系統
- 讀懂《30天自制作業系統》的捷徑作業系統
- 30天自制作業系統-merk11的第三天作業系統
- 30天自制作業系統-merk11的第一天作業系統
- 由《30天自制作業系統》引發的漫畫創作作業系統
- 三十天自制作業系統(13)作業系統
- 釋出在《30天自制作業系統》之前的幫助閱讀貼作業系統
- 為什麼《30天自制作業系統》封面中的貓是兩隻尾巴作業系統
- 【全棧React】第30天: 總結和更多的資源全棧React
- 自制作業系統(一) 第一個作業系統作業系統
- 作業系統總結作業系統
- [自制作業系統] 第07回 認識保護模式之地址對映作業系統模式
- 作業系統身份驗證和口令檔案身份驗證總結作業系統
- 30 天精通 RxJS (25):Subject 總結JS
- 《作業系統30天》-合川秀實-學習日誌day11作業系統
- 作業系統實驗六實驗報告作業系統
- 作業系統實驗七實驗報告作業系統
- 作業系統寫題總結作業系統
- 《作業系統》分析與總結作業系統
- 作業系統實驗第七天:從滑鼠接受資料作業系統
- [自制作業系統] 第10回 認識保護模式之深入淺出特權級作業系統模式
- 常用快取系統使用經驗總結快取
- 這兩天的面試經驗總結面試
- 作業系統實驗——程式控制作業系統
- 作業系統之“實驗一”作業系統
- flex實驗總結Flex
- 實驗一 總結
- 作業系統常用知識總結!作業系統
- 【javaWeb】第55天——java web階段性總結JavaWeb
- 作業系統實驗4 系統呼叫聯絡作業系統
- 實習2天的總結
- 實驗0、瞭解和熟悉作業系統實驗作業系統
- Cobbler自動化批量安裝Linux作業系統 - 運維總結Linux作業系統運維
- 作業系統實驗2 程式控制和系統呼叫作業系統