[英]Reading data from from floppy disk problems
這是代碼的工作版本,但我對此有疑問
dl
時read:
它無法讀取磁盤但是當它在重置中替換dl
時reset:
它成功重置,所以哪個驅動器被重置而軟盤驅動器 = 0popa
之前將pusha
放在 print_string 中,在運行程序后將 popa 放在ret
之前的 print_done 中時,它只打印bootmsg
S
我不知道為什么Hello World
也不是S
編輯:我正在使用 qemu
program_intialization:
org 0x7C00 ;load program at 0x7C00
push dx ;save drive number to stack appeared to be 231 not 0
jmp program_start ;go to program_start
print_string:
cld ;clear direction flag to increase si after copying the value of the address pointed by it
lodsb ;copy [si] into al then increase si
or al,al ;check if al is null
jz print_done ;if null then go to print_done
mov ah,0x0E ;else copy 0x0E to ah which is the video output code
int 0x10 ;then interrupt the program with 0x10 the video routine code which will print the character in al
jmp print_string ;and print the next character until null is found
print_done:
mov al,0x0A ;copy the code of line feed into al
mov ah,0x0E ;copy 0x0E to ah which is the video output code
int 0x10 ;interrupt the program with 0x10 the video routine code which will print the character in al (the line feed)
mov al,0x0D ;copy the code of carriage return into al
mov ah,0x0E ;copy 0x0E to ah which is the video output code
int 0x10 ;interrupt the program with 0x10 the video routine code which will print the character in al (the carriage return)
ret ;return to the place the function is called from
program_start:
xor ax,ax ;intialize ax to 0
mov ds,ax ;intialize ds to 0
mov es,ax ;intialize es to 0
mov si,bootmsg ;copy bootmsg address to si
call print_string ;print bootmsg
reset:
mov si,rstmsg ;copy reset adress to si
call print_string ;print reset
mov ah,0 ;drive reset code
pop dx ;get drive number into dl
push dx ;save drive number again
int 0x13 ;reset drive
jc reset ;if failed try again
mov ax,0x0F00 ;copy 0x0F00 to ax
mov es,ax ;copy 0x0F00 to es
xor bx,bx ;make bx = 0x0000
mov si,scs ;if success
call print_string ;print scs
read:
mov si,rdmsg ;copy reset adress to si
call print_string ;print reset
pop dx ;get the drive number into dl
mov ah,0x02 ;copy disk read code to ah
mov al,1 ;read 1 sector
mov ch,0 ;on track 0
mov cl,2 ;read sector number 2
mov dh,0 ;head number 0
int 0x13 ;read from disk to memory address es:bx (0xF000)
jc read ;if failed try again
mov si,scs ;if success
call print_string ;print scs
end:
mov si,0xF000 ;which is es:bx
call print_string0 ;print Hello World read from memory 0xF000
cli ;clear all interupts
hlt ;halt the system
bootmsg db "Bootloader v0.1",0
rstmsg db "Trying to reset Floppy Disk",0
rdmsg db "Trying to read Floppy Disk",0
scs db "Operation Successful",0
times 510 - ($-$$) db 0 ;fill the rest of bootsector with 00
dw 0xAA55 ;boot magic number
msg db "Hello World",0 ;add hello world to the next sector (512bytes) which will be read
org 0x7C00 push dx;save drive number to stack
您正在使用堆棧而不知道它在 memory 中的位置以及它有多少空間供您使用,這與您的pusha
/ popa
問題有關。
; reset: pop dx;get drive number into dl push dx;save drive number again
; read: pop dx;get the drive number into dl
在重置中,您將 DriveCode 保留在堆棧中。 但是,在閱讀中,您不會將 DriveCode 放回去。 當失敗時,讀取嘗試重復操作,DriveCode 不能再從堆棧中彈出,一些隨機值將替換它!
當我在代碼的
popa
之前將pusha
放在print_string中,在運行程序后將popa放在ret
之前的 print_done 中時,它只打印bootmsg
這是您會編寫的代碼:
print_string:
PUSHA <<< added
cld
lodsb
or al,al
jz print_done
mov ah,0x0E
int 0x10
jmp print_string ;and print the next character until null is found
print_done:
mov al,0x0A
mov ah,0x0E
int 0x10
mov al,0x0D
mov ah,0x0E
int 0x10
POPA <<< added
ret
每次打印一個字符時,代碼都會跳回到print_string的起點,在那里另一組寄存器被壓入堆棧(因為pusha
指令被重復)。 對於具有 15 個字符的bootmsg文本,這將發生 16 次。 當最終找到終止零時, popa
指令將只執行一次,在堆棧上留下大量不需要的字節。 ret
指令沒有有意義的地址可以返回,程序崩潰。
將 0x0F00 替換為 0x1000 並將 0xF000 替換為 0x10000 時,它不會打印 Hello World 但會打印
S
我不知道為什么
在代碼中,您來自:
mov ax,0x0F00
mov es,ax
xor bx,bx
...
mov si,0xF000 ;which is es:bx
call print_string0 ;print Hello World read from memory 0xF000
到:
mov ax,0x1000
mov es,ax
xor bx,bx
...
mov si,0x10000 ;which is es:bx
call print_string0 ;print Hello World read from memory 0x10000
您是正確的,設置ES=0x1000
對應於線性地址 0x10000 (65536)。 但是,像mov si, 0x10000
這樣的指令不會在SI
寄存器中加載該特定地址,因為它太大而無法放入字長寄存器(允許值范圍為 0 到 65535)。 大多數匯編器不會對此抱怨,只是將截斷的值存儲在寄存器中,在 casu 0 中。你說它打印的“S”來自 memory 中的第一個字節。
將 0x0F00 替換為 0x1000 並將 0xF000 替換為 es:bx(但它必須等於 0x10000)時,它既不是
Hello World
也不是S
如果您將mov si,0xF000
替換為push es
push bx
pop si
pop ds
,它會工作正常,因為print_string例程從DS:SI
運行,您必須以這種方式使用它。
BIOS 返回軟盤驅動器 = 231 而不是 0,因為我讀到軟盤應該是 = 0,所以當在讀取中用 0 替換
dl
時read:
它無法讀取磁盤但是當它在重置中替換dl
時reset:
它成功重置,所以哪個驅動器被重置而軟盤驅動器 = 0
鑒於上述錯誤和誤解,我最好的猜測可能是您根本沒有收到驅動器代碼 231,但可能找錯了地方。
我肯定會保留 BIOS 提供的值,而不是強制使用DL=0
之類的值。
這是您的代碼的改進版本:
org 0x7C00
cld ; Gets DriveCode later
xor ax, ax
mov ds, ax
mov ss, ax
mov sp, 0x7C00
mov [0x7C00], dl
mov si, bootmsg
call print_string
reset:
mov si, rstmsg
call print_string
mov dl, [0x7C00] ; DriveCode
mov ah, 0 ;drive reset code
int 0x13 ;reset drive
jc reset ;if failed try again
mov si, scs
call print_string
read:
mov si, rdmsg
call print_string
mov ax, 0x0F00
mov es, ax
xor bx, bx
mov dh, 0 ;head number 0
mov dl, [0x7C00] ;get the drive number into dl
mov cx, 0x0002 ;on track 0 read sector number 2
mov ax, 0x0201
int 0x13 ;read from disk to memory address es:bx (0xF000)
jc read ;if failed try again
mov si, scs
call print_string
end:
mov si, 0xF000 ;which is es:bx
call print_string0 ;print Hello World read from memory 0xF000
cli ;clear all interrupts
hlt ;halt the system
jmp end
print_string:
pusha
mov bx, 7
print_more:
lodsb
or al, al
jz print_done
mov ah, 0x0E
int 0x10
jmp print_more
print_done:
mov ax, 0x0E0A
int 0x10
mov al, 0x0E0D
int 0x10
popa
ret
bootmsg db "Bootloader v0.1",0
rstmsg db "Trying to reset Floppy Disk",0
rdmsg db "Trying to read Floppy Disk",0
scs db "Operation Successful",0
times 510 - ($-$$) db 0 ;fill the rest of bootsector with 00
dw 0xAA55 ;boot magic number
msg db "Hello World",0 ;add hello world to the next sector
ps:不要忘記刪除call print_string0
中的拼寫錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.