os引导程序boot从扇区拷贝os加载程序loader文件到内存(boot copy kernel to mem in the same method)
【0】README
- 0.1) 本代碼旨在演示 在boot 代碼中,如何 通過 loader文件所在根目錄條目 找出該文件的 在 軟盤所有全局扇區號(簇號),并執行內存中的 loader 代碼;
- 0.2) 此代碼非常重要,關系到bootloader的加載和運行(打印字母 L)(干貨)
- 0.3) source code from orange’s implemention of a os and for complete code , please visit https://github.com/pacosonTang/Orange-s-OS/blob/master/boot.asm
- 0.4) 就本os而言,即orange’s os ,”從扇區copy os加載程序 loader 到內存0x09000:0100“這個任務 是在 引導扇區中的引導程序boot 中完成的,而且在 boot 完成本任務之前,引導程序boot還完成 ”在根目錄區尋找 加載程序loader 對應的根目錄條目“的任務,注意這與linux 是不同的;
- 0.5)即是說,orange’s os 中的啟動程序boot 執行了兩個任務: os引導程序boot 在根目錄區尋找os加載程序文件loader 對應的根目錄條目 + os引導程序boot 從扇區拷貝os加載程序loader文件到內存(boot copy kernel to mem in the same method)
- Attention)
- A1) loader文件所在根目錄條目 是由 p109.asm 得到的, 在查找完文件名稱且匹配后,di 指向文件名的后一個字節,但di還存在于當前匹配成功的 根目錄條目中;
- A2) 要死死記住 根目錄條目的數據結構存儲的是:(文件名 + 文件屬性 + 最后一次寫入時間 + 最后一次寫入日期 + 此條目對應的開始簇號 + 文件大小)
- A2) 要死死記住 根目錄條目的數據結構存儲的是:(文件名 + 文件屬性 + 最后一次寫入時間 + 最后一次寫入日期 + 此條目對應的開始簇號 + 文件大小)
【1】SOURCE CODE
LABEL_FILENAME_FOUND: ; 找到 LOADER.BIN 后便來到這里繼續
mov ax, RootDirSectors ; RootDirSectors=14and di, 0FFE0h ; di -> 當前條目的開始,每個條目=32字節,0ffe0==1111 1111 1110 0000add di, 01Ah ; di -> 首 Sector ,條目數據結構中,開始簇號的offset=26字節;mov cx, word [es:di]push cx ; 保存此 Sector 在 FAT 中的序號 ,cx等于loader文件的開始簇號(在數據區)add cx, axadd cx, DeltaSectorNo ; cl <- LOADER.BIN的起始扇區號(0-based); 這里加完之后,cx=該loader 文件相對于0號扇區的扇區號(也即相對于整個軟盤而言)mov ax, BaseOfLoadermov es, ax ; es <- BaseOfLoadermov bx, OffsetOfLoader ; bx <- OffsetOfLoadermov ax, cx ; ax <- Sector 號LABEL_GOON_LOADING_FILE:push ax ; `.push bx ; | es:bp 是串地址,CX=串長度,ah= ,al= '.' 打印什么東西, bh=頁號,bl=黑底紅字mov ah, 0Eh ; | 每讀一個扇區就在 "Booting " 后面mov al, '.' ; | 打一個點, 形成這樣的效果:mov bl, 0Fh ; | Booting ...... int 10h ; | | 一句話說完,以上對register的初始化,都是為觸發10h 號中斷做準備工作的, pop bx ; |pop ax ; /mov cl, 1call ReadSector ; 這個ReadSector非常重要,目的就是讀取cl個扇區到 es:bx中,而bx 每次都自增512字節;(這是讀軟盤某扇區到內存中的關鍵步驟)
pop ax ; cur_line=154, 取出此 Sector 在 FAT 中的序號(ax <- cx),line133 push cx 已壓入棧, cx=Loader文件在數據區的開始簇號;call GetFATEntry ; 找到序號為 ax 的 Sector 在 FAT 中的條目, 結果放在 ax 中
cmp ax, 0FFFhjz LABEL_FILE_LOADED ; 相等,則說明 該簇號是最后一個簇號push ax ; 保存 Sector 在 FAT 中的序號mov dx, RootDirSectorsadd ax, dxadd ax, DeltaSectorNo ; DeltaSectorNo equ 17add bx, [BPB_BytsPerSec] ; bx加上一個扇區的字節數,即跳轉到下一個扇區;因為讀取地址是 es:bxjmp LABEL_GOON_LOADING_FILE LABEL_FILE_LOADED:mov dh, 1 ; "Ready." 加載完畢 call DispStr ; 顯示字符串; jmp BaseOfLoader:OffsetOfLoader; 這一句正式跳轉到已加載到內, 開始執行loader 代碼;
; 存中的 LOADER.BIN 的開始處,
; 開始執行 LOADER.BIN 的代碼。
; Boot Sector 的使命到此結束**
GetFATEntry Source Code
;—————————————————————————-
; 函數名: GetFATEntry
;—————————————————————————-
; 作用:
; 找到序號為 ax 的 Sector 在 FAT 中的條目, 結果放在 ax 中
; 需要注意的是, 中間需要讀 FAT 的扇區到 es:bx 處, 所以函數一開始保存了 es 和 bx
【2】Conclusion(本代碼繼p109 后,接著擺)
2.0)寫在前面:假設這里有個內核,loader加載該內核到內存,而且內核開始執行的時候肯定已經在保護模式下了。所以loader需要做的事情有兩件:
- 2.0.a)加載內核入內存;
- 2.0.b)跳入保護模式;
2.1)下面演示 以上代碼的執行步驟:
step1)計算該文件起始簇號對應的全局扇區號:
從根目錄條目中抽取出 該文件的起始簇號(FAT專門用于存儲文件在數據區的簇號,簇號等于一個或多個扇區),該簇號是相對于數據區的簇號,(因為本FAT12文件系統中,一個簇號==一個扇區,所以簇號就等于扇區的說法,但是不管怎么,知道簇號,我就可以知道扇區號,這些設置是在 FAT12 的引導扇區中定義好了的)所以,我們要算出該簇號對應的 全局簇號(扇區號),因為第一個和第2個FAT不使用,所以全局簇號最后還要減2。
step2)從軟盤上 讀取該扇區到內存地址 es:bx=9000:1000處,以便進行數據分析;(當然,每次循環后,偏移地址要增加512字節,也即連續讀取該文件的扇區內容到 起始位置0x9000:1000處);
step3)找出 step1 中算出扇區號在 FAT中的條目:- step3.1)首先,算出該扇區在FAT的 對應條目 FATentry 在 FAT中的偏移量(一個條目= 12bits = 1.5Bytes);(注意,這里的條目是FAT條目,不是根目錄區條目,不要搞混了)
- step3.2)然后算出該偏移量在哪個扇區,以及在該扇區的偏移量;
- step3.3)讀取對應FAT條目所在扇區和相鄰扇區(也即讀2個扇區,因為條目占1.5個字節,可能跨扇區存儲)到 es:bx= (9000h-100h): 00 處;
- step3.4)在es:bx處 對兩個扇區求出 該扇區對應的 FAT條目值(即12位值);
step4)比較FAT條目值 是否 == fffh:
- step4.1)如果相等,則證明該條目是最后一個條目,即over了;
- step4.2)如果不等,將該FAT條目壓棧(因為它是一個鏈條,不斷壓棧,直到 fffh 出現),然后更新該文件的下一個全局扇區號(ax+RootDirSectors+DeltaSectorNo),然后再代入step2)進行循環;最后就可以找出該文件所對應的所有FAT條目,即該文件所占用的所有簇,也即所有扇區了,即是是壓棧形成的那個鏈條值;
step5)找到該文件占用的所有扇區后,跳轉到es:bx的地址,即 jmp BaseOfLoader:OffsetOfLoader ,該 loader文件 僅僅是 打印了 字符 ‘L’ ,(該文件內容,就是剛才step2步驟中把軟盤扇區中的內容讀入內存 es:bx 的內容),(因為正如step2所說的那樣,在上述循環過程中,程序已經把該文件的所有扇區內容讀取到起始地址為 BaseOfLoader:OffsetOfLoader=0x90000:1000 的內容空間中去了)
jmp BaseOfLoader:OffsetOfLoader ; 這一句正式跳轉到已加載到內 ; 存中的 LOADER.BIN 的開始處, ; 開始執行 LOADER.BIN 的代碼。 ; Boot Sector 的使命到此結束
Attntion)其實你發現: 這個 BaseOfLoader : OffsetOfLoader 處的內容,是 LABEL_GOON_LOADING_FILE 標識符后的 ReadSector函數每次讀一個扇區讀進去的,而每次的起始扇區號由 GetFATEntry 函數 提供的,而 GetFATEntry 函數的作用:找到序號為 ax 的 Sector 在 FAT 中的條目, 結果放在 ax 中。就這樣 ReadSector函數 + GetFATEntry 函數配合起來就把loader文件從 軟盤的扇區讀到了 起始內存地址 es:bx=9000h:0100 (每次循環后,偏移地址自增512字節);
Complementary)FAT的作用:當文件size 大于 512B,則FAT是找出該文件所占用的全部簇(簇:一個或多個扇區,引導扇區的BPB_SecPerClus記錄該數字)
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的os引导程序boot从扇区拷贝os加载程序loader文件到内存(boot copy kernel to mem in the same method)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FAT12中,如何定位大于一个扇区(51
- 下一篇: 计算机器内存数量+引入和显示ARDS成员