[英]Read a write a sector from hard drive with int 13h
我有一個簡單的程序。 它必須從硬盤驅動器(而不是mbr)讀取第一個扇區,並將其寫入0扇區(mbr)。 但它不起作用。 我認為它與錯誤的DAP有關。 謝謝。
[bits 16]
[org 0x7c00]
;clear screen
start:
mov ax, 0x3
int 0x10
;reset the hard drive
xor ah, ah
mov dl, 0x80
int 0x13
jnz error
;read the second sector
mov si, DAP
mov ah, 0x42
int 0x13
mov si, data
call print_string
jmp $
DAP:
db 0x10 ;size of DAP
db 0x0 ;zero
db 0x1 ;number of sectors to read
db 0x0 ;zero
;point to memory
dw 0x0 ;offset
dw 0x0 ;segment
dq 0x1 ;disk address
DAP2:
db 0x10
db 0x0
db 0x1
db 0x0
dw 0x0
dw 0x0
dd 0x0
dd 0x0
print_string:
mov ax, 0xb800
mov es, ax
xor di, di
mov cx, 8
rep movsw
ret
data: db 'H',2,'e',2,'l',2,'l',2
error:db 'E',2,'r',2,'r',2
times 510 - ($ - $$) db 0
dw 0xaa55
UPD:新代碼
[bits 16]
[org 0x7c00]
;clear screen
start:
; mov ah, 0
; push ax
; pop ds
mov ax, 0x3
int 0x10
;reset the hard drive
xor ah, ah
mov dl, 0x80
int 0x13
jc error
;read the second sector
mov si, DAP
mov ah, 0x42
int 0x13
mov si, data
call print_string
jmp $
DAP:
db 0x10 ;size of DAP
db 0x0 ;zero
db 0x1 ;number of sectors to read
db 0x0 ;zero
;point to memory
dw 0x0 ;offset
dw 0x8c00 ;segment
dq 0x1 ;disk address
DAP2:
db 0x10
db 0x0
db 0x1
db 0x0
dw 0x0
dw 0x8c00
dq 0x2
print_string:
mov ax, 0xb800
mov es, ax
xor di, di
mov si, 0x8c00
mov cx, 8
rep movsw
ret
data: db 'H',2,'e',2,'l',2,'l',2
error:db 'E',2,'r',2,'r',2
endp:
times 510 - ($ - $$) db 0
dw 0xaa55
PS我正在使用Bochs。
有點嗜屍; 希望你的裝配技能在此期間得到改善。 但為了以防萬一......
引用@Alexey Frunze,“你需要注意你正在做的事情”。 除了其他答案中詳述的錯誤之外,以下是我的一些觀察:
您的代碼似乎是一個引導加載程序。 您假設BIOS將您的代碼加載到0x0000:0x7C00
,但您無法確定它實際上不會將其加載到0x07C0:0000
或任何其他等效地址。 閱讀細分 。
您無法初始化任何段寄存器。 您可能會因為您的仿真器很友好而正確使用它,並正確地將cs
, ds
和es
初始化為0x0000
。
您可以像這樣解決這兩個問題:
[bits 16]
[org 0x7C00]
jmp 0x0000:start_16 ; ensure cs == 0x0000
start_16:
; initialise essential segment registers
xor ax, ax
mov ds, ax
mov es, ax
如果發生錯誤,您可以直接跳轉到字符串,而不是可執行代碼。 Lord只知道如果發生這種情況,計算機會做什么。
檢查驅動器復位的返回值(CF),但不檢查讀取本身。 如果讀取失敗,您應該重置驅動器並再次嘗試讀取。 如果驅動器打嗝,請在循環中執行一些嘗試(例如,3)。 如果驅動器重置失敗,可能是更嚴重的問題,你應該保釋。
我建議使用int 0x13, ah = 0x02
。 您正在使用可能並非所有系統都支持的擴展BIOS功能(仿真器支持可能很復雜,更不用說在某些現代硬件上發現的懶惰BIOS實現)。 你處於真實模式 - 你不需要做任何花哨的事情。 最好進入保護模式,其長期目標是編寫PM驅動程序來處理磁盤I / O.
只要您保持實模式,這里就是一個獨立的功能,它將使用簡單的BIOS功能從磁盤讀取一個或多個扇區。 如果您事先不知道您需要哪個扇區,則必須添加額外的檢查以處理多軌讀取 。
; read_sectors_16
;
; Reads sectors from disk into memory using BIOS services
;
; input: dl = drive
; ch = cylinder[7:0]
; cl[7:6] = cylinder[9:8]
; dh = head
; cl[5:0] = sector (1-63)
; es:bx -> destination
; al = number of sectors
;
; output: cf (0 = success, 1 = failure)
read_sectors_16:
pusha
mov si, 0x02 ; maximum attempts - 1
.top:
mov ah, 0x02 ; read sectors into memory (int 0x13, ah = 0x02)
int 0x13
jnc .end ; exit if read succeeded
dec si ; decrement remaining attempts
jc .end ; exit if maximum attempts exceeded
xor ah, ah ; reset disk system (int 0x13, ah = 0x00)
int 0x13
jnc .top ; retry if reset succeeded, otherwise exit
.end:
popa
retn
您的打印功能采用彩色監視器(通過寫入0xB8000的視頻內存)。 再次,你是在真實模式。 把事情簡單化。 使用BIOS服務:
; print_string_16
;
; Prints a string using BIOS services
;
; input: ds:si -> string
print_string_16:
pusha
mov ah, 0x0E ; teletype output (int 0x10, ah = 0x0E)
mov bx, 0x0007 ; bh = page number (0), bl = foreground colour (light grey)
.print_char:
lodsb ; al = [ds:si]++
test al, al
jz .end ; exit if null-terminator found
int 0x10 ; print character
jmp .print_char ; repeat for next character
.end:
popa
retn
load_sector_2:
mov al, 0x01 ; load 1 sector
mov bx, 0x7E00 ; destination (might as well load it right after your bootloader)
mov cx, 0x0002 ; cylinder 0, sector 2
mov dl, [BootDrv] ; boot drive
xor dh, dh ; head 0
call read_sectors_16
jnc .success ; if carry flag is set, either the disk system wouldn't reset, or we exceeded our maximum attempts and the disk is probably shagged
mov si, read_failure_str
call print_string_16
jmp halt ; jump to a hang routine to prevent further execution
.success:
; do whatever (maybe jmp 0x7E00?)
read_failure_str db 'Boot disk read failure!', 13, 10, 0
halt:
cli
hlt
jmp halt
您的引導加載程序不會設置堆棧。 我提供的代碼使用堆棧來防止寄存器丟棄。 在引導加載程序(<0x7C00)之前有大約30KiB可用,因此您可以在引導加載程序的開頭附近執行此操作:
xor ax, ax
cli ; disable interrupts to update ss:sp atomically (AFAICT, only required for <= 286)
mov ss, ax
mov sp, 0x7C00
sti
唷! 要消化很多。 請注意,我試圖保持獨立功能的靈活性,因此您可以在其他16位實模式程序中重復使用它們。 我建議你嘗試編寫更多的模塊化代碼,並堅持這種方法,直到你更有經驗。
例如,如果您已經設置了使用擴展讀取功能,那么您可能應該在堆棧上編寫一個接受DAP或指向一個DAP的函數。 當然,你會浪費代碼空間在那里推送數據,但是一旦它存在,你可以簡單地調整后續讀取的必要字段,而不是讓大量的DAP占用內存。 堆棧空間可以在以后回收。
不要灰心,匯編需要時間,並且對細節有着極大的關注......在工作時抨擊這些東西並不容易,所以我的代碼可能會出錯! :)
首先,您需要檢查cf
而不是zf
以查看BIOS調用是否成功。 糾正你的jnz error
。
其次,您似乎依賴於ds
等於0.它不能保證為0.將其設置為0。
對於同上flags.df
,它不能保證為0它設置為0檢查的文件rep
, movs*
和cld
。
第三,你要求BIOS讀取扇區並將其寫入內存中的物理地址0。 通過這樣做,您將覆蓋中斷向量表(從那里開始並占用1KB)並損壞系統,需要重新啟動。 選擇一個更好的地址。 最好的是在內存中的bootsector結束之后。 但是您還需要確保堆棧不存在,因此您還需要將堆棧設置為已知位置。
你需要注意你正在做的事情。
最小的NASM BIOS示例,它使用代碼加載扇區並跳轉到它,而不進行錯誤檢查和DAP:
use16
org 0x7C00
; For greater portability you should
; do further initializations here like setup the stack and segments.
; Load stage 2 to memory.
mov ah, 0x02
mov al, 1
; This may not be necessary as many BIOS setup is as an initial state.
mov dl, 0x80
mov ch, 0
mov dh, 0
mov cl, 2
mov bx, stage2
int 0x13
jmp stage2
; Magic bytes.
times ((0x200 - 2) - ($ - $$)) db 0x00
dw 0xAA55
stage2:
; Print 'a'.
mov ax, 0x0E61
int 0x10
cli
hlt
; Pad image to multiple of 512 bytes.
times ((0x400) - ($ - $$)) db 0x00
編譯並運行:
nasm -f bin -o main.img main.asm
qemu-system-i386 main.img
預期結果: a
打印到屏幕上,然后程序停止。
在Ubuntu 14.04上測試過。
在我的GitHub上使用鏈接描述文件和更正確的初始化(段寄存器,堆棧)的Saner GAS示例。
load:
; Load sectors routine : bootdrv-drive , snum-sectors to load
;ES:BX where to load ex: mov ax,0000h mov es,ax mov bx, 7c00h
push bx
push ds
mov verify,0h
.reset:
cmp verify,5h
je Err1
add verify,1h
mov ax, 0 ; Reset Disk
mov dl, [BootDrv] ; Drive to reset
int 13h ;
jc .reset ; Failed -> Try again
pop ds
pop bx
mov verify,0h
.read:
cmp verify,5h
je Err1
add verify,1h
mov ah, 2 ; Interrupt 13h,2 => Read disk sectors
mov al, snum ; how many sectors to read
mov cx, fsect ; cl-first sector to be r/w ch-track containing sector
mov dh, head ; head=0
mov dl, [BootDrv] ; Drive=boot drive
int 13h ; Read! ES:BX = data from disk
jc .read ; failed -> Try again
retn
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.