bios x86保护模式下的软盘操作floppy
Cpu啟動時,如果在bios中設置了從軟盤啟動,則bios會自動把軟盤的第一個扇區(512字節)搬移到0x7c00,然后會從0x7c00開始運行,我們需要在這512字節的程序中實現把boot從軟盤中搬移到內存中的功能。
此時x86系列的cpu還處在實模式中,可以利用bios提供的中斷完成軟盤讀寫,也就是著名的int 13。
1???軟盤操作 1.1 ???? 軟盤結構
以1.44M軟盤為例,軟盤有上、下兩個盤面,每個盤面被劃分為80個track,每個track被劃分為18個Sector,每個Sector大小為512 BYTES。
2×80×18×512=1440×1024=1.44MB
如果是單純的進行軟盤讀寫操作,知道軟盤的這些知識就夠了。
1.2 ???? 軟盤讀寫| 中斷號 | 寄存器 | 作用 |
| 13h | ah=00h??? ??al=驅動器號(0表示A盤) | 復位軟驅 |
| ah=02h??? ??al=要讀扇區數 ch=磁道號?? cl=起始扇區號 dh=磁頭號?? dl=驅動器號 es:bx=數據緩沖區 | 從cl/ch/dh/dl指向的扇區開始讀取al個扇區的數據到es:bx指向的緩沖區 | |
| ah=03h??? ??al=要寫扇區數 ch=磁道號?? cl=起始扇區號 dh=磁頭號?? dl=驅動器號 es:bx=數據緩沖區 | 從es:bx指向的緩沖區讀取al個扇區的數據寫入cl/ch/dh/dl指向的al個扇區 |
對于軟盤來說, DL=0(0表示A盤)
CL的取值范圍是:1—18
CH的取值范圍是:0—79
DH?的取值范圍是:0—1
如果軟盤的CL,CH,DH取值超過了范圍,中斷調用出錯。
使用int13時對應扇區數的計算方法如下:
?
1.3 ???? 軟盤編程用軟盤存放操作系統時,bios只會把前512個字節(即第一個扇區,引導區)讀入內存的0x7c00處執行。程序的長度也被限制在了512字節大小,一個出入保護模式的程序就會超出。
為了突破512字節的限制,需要在這個扇區內放置一段引導程序,用于把后面的程序加載到內存中。這也是第一個扇區被稱為引導區的原因。
下面的就是一段簡單的加載程序,reset軟驅后從LABEL_SECTOR2開始讀入17個扇區。加上0號扇區(引導區),一共是18個扇區,也就是第一個磁道。這是因為13號中斷不能跨磁道讀取,所以這里只讀入第一個磁道剩下的17個扇區。
| ??? ; reset floppy ??? xor ah, ah ??? xor dl,? dl ??? int 13h ??? ??? ; read sector 2 to memory ??? mov ah, 03h ??? mov al, 11h ??? mov ch, 00h ??? mov cl, 03h ??? mov dh, 00h ??? mov dl, 00h ??? mov bx, 0100h ??? int 13h |
下面的程序用于保證除引導程序外的所有程序都在引導區之外,完成把磁盤內容拷貝入memory的操作后,就會跳入LABEL_SECTOR2。
| ?????? jmp LABEL_SECTOR2 ? ; fill boot sector ??? times 510 - ($ - $$) db 1 ??? dw 0xaa55 ? ; Sector 2 LABEL_SECTOR2: |
下面是完整的程序代碼
| ?????? org 07c00h ??? jmp LABEL_BEGIN ? LABEL_BEGIN: ??? mov ax, cs ??? mov ds, ax ??? mov ss, ax ??? mov es, ax ??? ??? ; reset floppy ??? xor ah, ah ??? xor dl,? dl ??? int 13h ??? ??? ; read sector 2 ??? mov ah, 02h ??? mov al, 01h ??? mov ch, 00h ??? mov cl, 02h ??? mov dh, 00h ??? mov dl, 00h ??? mov bx, LABEL_SECTOR2 ??? int 13h ? ?????? jmp LABEL_SECTOR2 ? ; fill boot sector ??? uutimes 510 - ($ - $$) db 0 ??? dw 0xaa55 ? ; Sector 2 jmp into loader ;????? org 0100h LABEL_SECTOR2: ?????? mov ax, cs ?????? mov ds, ax ?????? mov es, ax ?????? call? DispStr???????????????? ; 調用顯示字符串例程 ?????? jmp? $?????????????????? ; 無限循環 DispStr: ?????? mov ax, BootMessage ?????? mov bp, ax?????????????????? ; ES:BP = 串地址 ?????? mov cx, 16?????????????????? ; CX = 串長度 ?????? mov ax, 01301h??????????? ; AH = 13,? AL = 01h ?????? mov bx, 000ch????????????? ; 頁號為0(BH = 0) 黑底紅字(BL = 0Ch,高亮) ?????? mov dl, 0 ?????? int?? 10h??????????????? ; 10h 號中斷 ?????? ret BootMessage:???????? db??? "Hello, OS world!" ? ; fill floppy ??? times (2 * 18 * 80 * 512 - ($ - $$)) db 0 |
?
?
軟盤,INT 13H和IMG文件
1:軟盤
?軟盤是以扇區為基本單位來進行操作的,每扇區512字節,共2880個扇區,空間大小為1.44M.
?這2880個扇區又可以用(磁頭、磁道、扇區)這三個參數來描述。我們簡單記(磁頭、磁道、扇區)為(x,y,z),那么
??X的取值范圍是:0—1
??Y的取值范圍是:0--79
??Z的取值范圍是:1—18
也就是說軟盤有2磁頭、每磁頭有80磁道、每磁道有18扇區,共2880個扇區(2880=2*80*18)。
如果把2880個扇區從0開始編號,一直到2879結束,那么
編號為i的扇區和(X,Y,Z)的換算公式為:i=80*18*x+18*y+z-1
2:INT?13H
??INT13H是磁盤的BOIS中斷,對于讀寫扇區操作,中斷的完整調用參數如下:
??AL=扇區數????
??AH=中斷子功能號?????;2=讀扇區,3=寫扇區
??CL的6,7位,CH?=?磁道號??;每磁頭最多可以有2^10=1024個磁道
??CL的低6位???=??扇區號??;每磁道最多可以有2^6=64個扇區
??DH?=?磁頭號?????;最多可以有256個磁頭
??DL?=?驅動器號?????;0=軟盤,80H=硬盤
??ES:BX=數據緩沖區的地址
其他:
1).
??對于軟盤來說,實際的INT?13H中DL=0,而CL,CH,DH的取值范圍也不可能取到上面的數值,根據1:中的數據,有
CL的取值范圍是:1--18
CH的取值范圍是:0-79
DH?的取值范圍是:0—1
如果軟盤的CL,CH,DH取值超過了范圍,中斷調用出錯。
AL的取值也不是任意的,一次調用INT13H進行讀寫扇區的只可以在一個磁道內的扇區進行。如果超出了一個磁道,必須要更新INT13H的中寄存器,重復調用INT13H。
對于軟盤來說?AL必須要小于19-CL。
下面是一個從軟盤的(x,y,z)扇區中連續讀出n個扇區的內容到緩沖區BUFFER中的代碼片段(?代碼使用了一些80386的指令和MASM6.0才支持的偽指令):
?MOV??AX,DS
?MOV??ES,AX
MOV??BX,OFFSET
MOV???BP,??n?
MOV?CL,z
MOV?CH,y
MOV?DL,0?
MOV?DH,x
.WHILE??BP??;bp記錄的是還沒有進行讀操作的扇區數量
;WHILE偽指令,和高級語言的WHILE一樣理解就可以了,下面的。IF也一樣
?;對AL的取值進行計算
?MOV?AL,19
????SUB?AL,CL?;最多可以讀19-CL個扇區
????XOR?AH,AH
?.IF?AX>BP??
??????MOV?AX,BP
???XOR?BP,BP?
????.ELSE??
??SUB?BP,AX?;更新BP
???????.ENDIF????
??MOV?AH,2
INT?13H???;讀扇區
?;更新CL,CH,DH
MOV?CL,1??
.IF??CH==79?
???INC?DH
???XOR?CH,CH
??.ELSE
??????INC?CH
??.ENDIF
??XOR?AH,AH
??SHL?AL,9?;AX=AL*512,等于已經處理的字節數
?????;SHL?AL,9和SHL?AX,4都是80386+才支持的指令
????????SHR?AX,4???;AX=AX/16
??ADD?ES,AX??;更新ES:BX,這里是更新了ES,也可以更新BX。
?.endw
2).
??INT13H只理論上最多處理?2^24個扇區*512字節/扇區=8G的磁盤空間,這對現在的硬盤來說,是遠遠不夠的,于是后來對INT13H進行了擴展,用AH=42H、AH=43H分別對大硬盤進行操作,這里就不詳細討論了。
3:IMG文件
?IMG文件是軟盤的鏡像文件,文件大小也是1.44M,它和軟盤是一種線性的對應關系。
軟盤上一個編號為(x,y,z)的512字節的扇區,對應IMG文件中的以2400H*x+4800H*y+(z-1)*512為基址的512個字節(注意,2400H,4800H是16進制數)。
IMG文件的字節和軟盤的扇區對應關系也可以如下圖所示(注意那些是十進制,那些是16進制)。
?
對于擴展INT?13中斷,參數如下:
中斷號?功能???????????????????????調用寄存器?返回寄存器???????備注
INT?13
AH=41H?檢測擴展中斷功能是否安裝?AH?=?41h
?????????????????BX=55AAh
??????????????? DL?=?驅動器號(80h到FFH)
?????????????????失敗:AH=1
?????????????????CF置位
?????????????????成功:AH=版本號
?????????????????CF=0?BX=AA55H?
INT?13
AH=42H?磁盤擴展讀操作??????????????AH?=?42H
????????????????? ??DL?=?驅動器號
????????????????? ??DS:SI=指向LBA地址包的指針?失敗:AH=錯誤號
????????????????? ??CF置位
?????????????? ?????成功:AH=0
????????????????? ??CF=0
??地址包定義:
??????????????????? 偏移?大小?描述
????????????????? ??00H?字節?地址包大小
????????????????? ??01H?字節?保留(為0)
????????????????? ??02H?字?????傳輸包個數
????????????????? ??04H?雙字?指向數據指針
????????????????? ??08H?4字?????起始地址
?????? ?????????????其中LBA=((柱面*磁頭/柱面+磁頭)*扇區/柱面)+扇區-1
INT?13
AH=43H?磁盤擴展寫操作???????????????AH=43H
????????????????? ???????AL=寫標志
????????????????? ????DL?=?驅動器號
????????????????? ????DS:SI=指向LBA地址包的指針?失敗:AH=錯誤號
????????????????? ???????????????????CF置位
?????????? ????????????????????成功:AH=0
????????????????? ???????????????????????????????????CF =0?同上
INT?13
AH=48H?獲取磁盤參數?AH=48H
???????????????????????????????????? DL=驅動器號
????????????????????????????????????? DS:SI=指向保存參數緩沖區的指針
??? ??? ??? ??? ??? ??? ??? ??? ??? ?? 失敗:AH=錯誤號
????????????????? ???????? CF置位
?????????????????????????????????????? 成功:AH=0
????????????????? ???????? CF=0
?參數緩沖區定義:
????????????????? ??偏移?大小?描述
????????????????? ??00H?字?緩沖區大小
????????????????? ??02H?字?信息標志位
????????????????? ??04H?雙字?物理柱面數
????????????????? ??08H?雙字?物理磁頭數
????????????????? ??0CH?雙字?物理每柱扇區數
????????????????? ??10H?4字?扇區總數
????????????????? ??18H?字?每扇區字節數
1.1 ???? 保護模式下實現軟盤編程
要發揮x86芯片的功能,必須要進入保護模式。
系統啟動時所加載的512字節的MBR區為bootloader區,用于加載真正的boot程序。在bootloader區中,cpu還運行于實模式,因此bootloader通過bios中斷加載boot。進入boot區后,一般來說已經完成了切換入保護模式的動作。
在保護模式下,不能使用bios中斷,需要通過讀寫軟盤控制器芯片8237來完成。
1.1.1 ? 軟盤控制器| I/O address | Read or Write | Register |
| 0x3f2 | Write | DOR: Digital Output Register |
| 0x3f4 | Read | FDC Status: Floppy Disk Status Register |
| 0x3f5 | Read/Write | FDC Data: Floppy Disk Data Register |
| 0x3f7 | Read | DIR: Digital Input Register |
| Write | DCR: Disk Control Register |
注:FDC為軟盤控制器
1.1.1.1 ???????? DOR數字輸出寄存器DOR是一個8為寄存器,他控制驅動器馬達的開啟、驅動器選擇、啟動/復位FDC以及允許/禁止DMA請求
| 位 | Name | Description |
| 7 | MOT_EN3 | Driver D motor:1-start;0-stop |
| 6 | MOT_EN2 | Driver C motor:1-start;0-stop |
| 5 | MOT_EN1 | Driver B motor:1-start;0-stop |
| 4 | MOT_EN0 | Driver A motor:1-start;0-stop |
| 3 | DMA_INT | DMA interrupt; 1 enable; 0-disable |
| 2 | RESET | FDC Reset |
| 1 | DRV_SEL1 | Select driver |
| 0 | DRV_SEL0 |
?
1.1.1.2 ???????? FDC Status:FDC狀態寄存器FDC status用于反映軟盤驅動器FDC的基本狀態。通常,在CPU想FDC發送命令或從FDC獲取結果前,都要讀取FDC的狀態為,以判斷當前的FDC data寄存器是否就需,以及確定數據傳輸方向。
| 位 | Name | Description |
| 7 | RQM | Data ready: FDD ready |
| 6 | DIO | Direction: 1 - FDD to CPU; 0 – CPU to FDD |
| 5 | NDM | DMA set: 1-not DMA; 0-DMA |
| 4 | CB | Controller busy |
| 3 | DDB | Driver D busy |
| 2 | DCB | Driver C busy |
| 1 | DBB | Driver B busy |
| 0 | DAB | Driver A busy |
?
1.1.1.3 ???????? FDC Data:FDC數據寄存器FDC Data寄存器用于向FDC發送控制命令或從FDC讀取狀態,實現數據讀寫等。FDC的使用比較復雜,可支持多種命令。每個命令都通過一個命令序列實現:命令階段、執行階段和結果階段。
1)? 重新校正命令(FD_RECALIBRATE)
軟盤啟動時調用
| 階段 | 序 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 說明 |
| cmd | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0x07 |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | US1 | US2 | Drive no. | |
| 執行 | ? | ? | 磁頭移動到track0 | |||||||
| 結果 | ? | 無 | 無 | |||||||
2)? 磁頭尋道命令(FD_SEEK)
把磁頭定位到制定位置,在讀寫前執行
| 階段 | 序 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 說明 |
| cmd | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0x0F |
| 1 | 0 | 0 | 0 | 0 | 0 | HD | US1 | US2 | 磁頭號、驅動器號 | |
| 2 | C | 磁道號 | ||||||||
| 執行 | ? | ? | 磁頭移動到制定磁道 | |||||||
| 結果 | ? | 無 | 無 | |||||||
3)? 讀扇區數據命令(FD_READ)
| 階段 | 序 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 說明 |
| cmd | 0 | MT | MF | SK | 0 | 0 | 1 | 1 | 0 | 0xE6(MT=MF=SK=1) |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | US1 | US2 | 驅動器號 | |
| 2 | C | 磁道號track | ||||||||
| 3 | H | 磁頭號head | ||||||||
| 4 | R | 起始扇區號start sector | ||||||||
| 5 | N | 扇區字節數 | ||||||||
| 6 | EOT | 磁道最大扇區號 | ||||||||
| 7 | GPL | 扇區建間隔長度(3) | ||||||||
| 8 | DTL | N=0時,制定扇區字節書 | ||||||||
| 執行 | ? | ? | 從軟盤讀取扇區 | |||||||
| 結果 | 1 | ST0 | 狀態字節0 | |||||||
| 2 | ST1 | 狀態字節1 | ||||||||
| 3 | ST2 | 狀態字節2 | ||||||||
| 4 | C | 磁道號track | ||||||||
| 5 | H | 磁頭號head | ||||||||
| 6 | R | 起始扇區號 | ||||||||
| 7 | N | 扇區字節數 | ||||||||
注:
MT:多磁道操作。MT=1表示允許多磁道操作
MF:記錄方式。MF=1表示選用MFM記錄方式,否則是FM記錄方式d
SK:是否跳過有刪除標志的扇區。SK=1表示跳過。
返回的返回的狀態ST0、ST1和ST2的含義如下:
ST0:
| 位 | 名稱 | 說明 |
| 7 | ST0_INTR | 中斷原因。00-正常結束;01-異常結束;10-命令無效;11-軟盤驅動器狀態改變 |
| 6 | ||
| 5 | ST0_SE | 尋道操作或重新校正操作結束(seek end) |
| 4 | ST0_ECE | 設備檢查錯誤(0磁道校正錯誤)(Equip. Check Error) |
| 3 | ST0_NR | 軟盤未就緒(Not Ready) |
| 2 | ST0_HA | 磁頭地址。中斷時磁頭地址(Head Address) |
| 1 | ST0_DS | 驅動器號(Driver Select) |
| 0 |
?
ST1:
| 位 | 名稱 | 說明 |
| 7 | ST1_EOC | 范文超過磁道最大扇區號(End of Cylinder) |
| 6 | ? | Reserve |
| 5 | ST1_CRC | CRC校驗出錯 |
| 4 | ST1_OR | 數據傳輸超時(Over Run) |
| 3 | ? | Reserve |
| 2 | ST1_ND | 未找到制定扇區(No Data) |
| 1 | ST1_WP | 寫保護(Write Protect) |
| 0 | ST1_MAM | 未找到扇區地址標志ID(Miss Address Mask) |
?
ST2:
| 位 | 名稱 | 說明 |
| 7 | ? | Reserve |
| 6 | ST2_CM | SK=0時,讀數據遇到刪除標志(Control Mark) |
| 5 | ST2_CRC | CRC校驗出錯 |
| 4 | ST2_WC | 扇區ID信息的磁道號C不不符(Wrong Cylinder) |
| 3 | ST2_SEH | 檢索條件滿足(Scan Equal Hit) |
| 2 | ST2_SNS | 檢索條件不滿足(Scan Not Satisfied) |
| 1 | ST2_BC | 磁道壞(Bad Cylinder) |
| 0 | ST2_MAM | 未找到扇區地址標志ID(Miss Address Mask) |
?
4)? 寫扇區數據命令(FD_WRITE)
| 階段 | 序 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 說明 |
| cmd | 0 | MT | MF | 0 | 0 | 0 | 1 | 0 | 1 | 0xC5(MT=MF=1) |
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | US1 | US2 | 磁頭號、驅動器號 | |
| 2 | C | 磁道號track | ||||||||
| 3 | H | 磁頭號head | ||||||||
| 4 | R | 起始扇區號start sector | ||||||||
| 5 | N | 扇區字節數 | ||||||||
| 6 | EOT | 磁道最大扇區號 | ||||||||
| 7 | GPL | 扇區建間隔長度(3) | ||||||||
| 8 | DTL | N=0時,制定扇區字節書 | ||||||||
| 執行 | ? | ? | 向軟盤寫入扇區 | |||||||
| 結果 | 1 | ST0 | 狀態字節0 | |||||||
| 2 | ST1 | 狀態字節1 | ||||||||
| 3 | ST2 | 狀態字節2 | ||||||||
5)? 檢測中斷狀態命令(FD_SENSEI)
| 階段 | 序 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 說明 |
| cmd | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0x08 |
| 執行 | ? | ? | ? | |||||||
| 結果 | 1 | ST0 | 狀態字節0 | |||||||
| 2 | ? | 磁頭所在磁道號 | ||||||||
6)? 設定驅動器參數命令(FD_SPECIFY)
| 階段 | 序 | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 說明 |
| cmd | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0x03 |
| 1 | SRT(單位2ms) | HUT(單位32ms) | 馬達速度、磁頭卸載時間 | |||||||
| 2 | HLT(單位4ms) | ND | 磁頭加載時間,非DMA模式 | |||||||
| 執行 | ? | ? | 設置控制器 | |||||||
| 結果 | ? | 無 | 無 | |||||||
?
1.1.1.4 ???????? DIR:數字輸入寄存器DIR寄存器只有D7位有效,用于表示軟盤更換狀態,其余用于硬盤控制器。
1.1.1.5 ???????? DCR:磁盤控制寄存器DCR僅是用戶D0與D1位,用于表示數據傳輸率。
00-500kpbs, 01-300kpbs, 10-250kpbs。
1.1.2 ? 保護模式下代碼實現 1.1.2.1 ???????? 初始化1)? Reset
?
1)? 設置磁盤數據傳輸速度
outb(FD_DCR, 0); // 500kpbs
2)? Output_byte函數
用于FDC命令的輸出,FDC的每條命令需要確保上條命令已經完成
?
3)? 設置驅動器參數
?
?
1.1.2.2 ???????? 讀扇區?
?
程序很清楚,不再多說,寫命令于此類似。
唯一不清楚的是SetDMA函數。
我們在設置DOR時設置的DMA工作方式為enable,也就是說數據會通過DMA方式傳送,因此必須設置DMA控制器。
?
1.1.2.3 ???????? DMA傳輸該函數由linux0.11移植而來,可參照DMA控制器手冊進行設置。不看也可以,注釋寫得很清楚,拿過來用就是了
總結
以上是生活随笔為你收集整理的bios x86保护模式下的软盘操作floppy的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实模式与保护模式
- 下一篇: 利用BIOS 中断INT 0x10显示字