簡體   English   中英

從軟盤讀取數據問題

[英]Reading data from from floppy disk problems

這是代碼的工作版本,但我對此有疑問

  • BIOS 返回軟盤驅動器 = 231 而不是 0,因為我讀到軟盤應該是 = 0,所以當在讀取中用 0 替換dlread:它無法讀取磁盤但是當它在重置中替換dlreset:它成功重置,所以哪個驅動器被重置而軟盤驅動器 = 0
  • 當我在代碼的popa之前將pusha放在 print_string 中,在運行程序后將 popa 放在ret之前的 print_done 中時,它只打印bootmsg
  • 將 0x0F00 替換為 0x1000 並將 0xF000 替換為 0x10000 時,它不會打印 Hello World 但會打印S我不知道為什么
  • 將 0x0F00 替換為 0x1000 並將 0xF000 替換為 es:bx(但它必須等於 0x10000)時,它既不是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 替換dlread:它無法讀取磁盤但是當它在重置中替換dlreset:它成功重置,所以哪個驅動器被重置而軟盤驅動器 = 0

鑒於上述錯誤和誤解,我最好的猜測可能是您根本沒有收到驅動器代碼 231,但可能找錯了地方。
我肯定會保留 BIOS 提供的值,而不是強制使用DL=0之類的值。


這是您的代碼的改進版本:

  • 堆疊在引導扇區下方
  • memory(引導扇區的第一個字節)中存儲的驅動器號
  • 子程序脫離執行路徑
  • 一些代碼大小優化
        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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM