【问题标题】:Why does int 10h not work after reading sectors with int 13h?为什么用 int 13h 读取扇区后 int 10h 不起作用?
【发布时间】:2019-09-05 18:30:19
【问题描述】:

我想编写一个简单的引导加载程序。但是,从磁盘读取 2 个扇区后,我的引导扇区无法打印 int 10h 的字符串,ah=0Eh

在我调用 int 13h, ah=02h 之前它可以工作

我的代码:

;-------------------------------------------------------------------------------
; boot.asm - First boot sector
;-------------------------------------------------------------------------------

org 0x7c00
bits 16

    jmp     word _start

;-------------------------------------------------------------------------------
; BIOS Parameter Block (FAT32)
;-------------------------------------------------------------------------------

BS_OEMName:                     db              "TestOS  "
BPB_BytesPerSector:             dw              512
BPB_SectorsPerCluster:          db              1
BPB_ReservedSectors:            dw              4
BPB_FATCount:                   db              2
BPB_RootEntryCount:             dw              0
BPB_TotalSectors16:             dw              0
BPB_Media:                      db              0xf0
BPB_FATSize16:                  dw              0
BPB_SectorsPerTrack:            dw              18
BPB_HeadCount:                  dw              2
BPB_HiddenSectors:              dd              0
BPB_TotalSectors32:             dd              2880
BPB_FATSize32:                  dd              23
BPB_ExtendedFlags:              dw              0x0000
BPB_FileSystemVersion:          dw              0
BPB_RootCluster:                dd              2
BPB_FSInfo:                     dw              3
BPB_BackupBootSector:           dw              0
BPB_Reserved:                   times 12 db     0
BS_DriveNum:                    db              0x00
BS_Reserved1:                   db              0x0
BS_BootSignature:               db              0x29
BS_VolumeID:                    dd              0x12345678
BS_VolumeLabel:                 db              "TestOS     "
BS_FileSystemType:              db              "FAT32   "

;-------------------------------------------------------------------------------

_start:
; Initialize segment registers and set up stack at 0x7c00 (grows downwards)
    cli
    xor     ax, ax
    mov     ds, ax
    mov     es, ax
    mov     ss, ax
    mov     sp, 0x7a00
    sti

; Save drive number in DL
    mov     [BS_DriveNum], dl

; Copy this boot sector from 0x7c00 to 0x7a00
    mov     si, 0x7c00
    mov     di, 0x7a00
    mov     cx, 512
    cld
    rep movsb

; Jump to the new location
    jmp     0x0000:(_continue - 0x200)

_continue:

; Reset boot disk (try it 3 times before error message is printed)
    mov     cx, 4
_reset:
    sub     cx, 1
    cmp     cx, 0
    je      _error
    mov     ah, 0
    mov     dl, [BS_DriveNum]
    int     0x13
    jc      _reset

; Load second boot sector into memory at 0x7c00 (try it 3 times before error message is printed)
    mov     cx, 4
_load:
    sub     cx, 1
    cmp     cx, 0
    je      _error
    mov     ah, 0x02
    mov     al, 2
    mov     ch, 0
    mov     cl, 3
    mov     dh, 0
    mov     dl, [BS_DriveNum]
    mov     bx, 0x7c00
; IT STILL WORKS HERE <--------
    int     0x13
; IT DOESN'T WORK ANYMORE <--------
    jc      _load

    mov     si, error_msg
    call    print

; Jump to the second boot sector

; End of program
_end:
    hlt
    jmp     _end

_error:
    mov     si, error_msg
    call    print

    jmp     _end

;-------------------------------------------------------------------------------
; Prints a zero-terminated string onto the screen
; SI = string to write
;-------------------------------------------------------------------------------

print:
    pusha
.print_lbl:
    lodsb
    cmp     al, 0
    je      .finished
    mov     ah, 0x0e
    mov     bl, 0
    int     0x10
    jmp     .print_lbl

.finished:
    popa

    ret

;-------------------------------------------------------------------------------

error_msg:              db              "Operating system not found", 0xa, 0xd, "Press Ctrl+Alt+Del to reboot", 0x0

; Fill the rest of the 512 bytes with 0, byte 510 and 511
; contains 0xaa55 (boot signature for BIOS)

times 510 - ($ - $$) db 0
dw 0xaa55

我搜索了谷歌来解决这个问题,但之前没有其他人遇到过这个问题。

我用bochs调试了一下,发现...

  1. 我可以通过将字符写入 b800:0000 来在屏幕上打印一些东西

  2. 正确读取了 2 个扇区。我用 bochs 在 0x7c00 处转储了内存,它显示了正确的值

  3. 我的引导加载程序没有处于无限循环中,因为使用 bochs 进行调试表明它在读取 2 个扇区后执行指令

我不知道如何解决这个问题。谁能帮帮我?

【问题讨论】:

  • 您使用了org 7c00h,但随后将代码复制到其他地方并用加载的扇区覆盖了原始代码。当然,除了复制的代码仍然引用原始代码,因此它不会工作。
  • 以后有没有可能在代码中重新定义org指令?如果我尝试它,nasm 会说错误
  • 如果在读取第二个扇区时出现错误,您的代码将陷入无限循环,因为您用于计算重试次数 (CX) 的寄存器被覆盖。您可能最好使用 0x7a00 的 org 并在跳转到重新定位的引导扇区后保存 DL。
  • 您可以使用org 0 并更改分段。
  • 我会试试这个

标签: assembly x86 nasm bootloader bios


【解决方案1】:

TL;DR 正如@jester 所指出的,您的代码的主要问题是您使用了org 0x7c00,这意味着所有绝对引用都相对于0x7c00。当您复制到 0x7a00 时,您生成的代码仍然引用 0x7c??地址。当您在 0x7c00 处覆盖内存时,对 error_msgBS_DriveNum 等标签的引用指向已被替换的数据,并且它失败了。


有几种方法可以解决此问题:

  1. 最简单的解决方法是确保在跳转到 _continue 之前执行的代码是位置无关的(目前是),并将 org 0x7c00 更改为 org 0x7a00。您还需要将jmp 0x0000:(_continue - 0x200) 更改为jmp 0x0000:_continue

  2. 使用 org 0x0000 并根据您需要访问的段加载具有适当值 0x07c0 和 0x07a0 的段。通过具有 0x0000 的原点,生成的代码和数据相对于段的开头(您可以更改),而不是内存的开头。

  3. 您可以使用 NASM 的 segment 指令通过 vstart(虚拟内存地址)选项更改代码的原点。您可以使用带有start(加载内存地址)选项的segment 指令来更改放置引导签名的文件偏移量。

代码中的其他问题:

  • 正如@RossRidge 指出的,如果在磁盘操作后发生错误(设置了进位标志),它将进入无限循环,因为您使用 CX 寄存器,该寄存器也用于执行 Int 13h/AH =02h。您还可以将 CX 用于磁盘重置重试计数器和磁盘操作。
  • 一般而言,您可以避免检查 Int 13h/AH=0 磁盘重置时的任何错误,并删除该操作的重试循环。如果先前的磁盘操作失败,您应该只需要重置磁盘。在真实硬件上重试磁盘操作 3 次是正常的。
  • 当您的代码成功将新代码和数据读取到 0x7c00 时,它会显示一条错误消息。它可能应该打印一条磁盘读取成功的消息。

使用选项1的代码:

;-------------------------------------------------------------------------------
; boot.asm - First boot sector
;-------------------------------------------------------------------------------

org 0x7a00
bits 16

    jmp     word _start

;-------------------------------------------------------------------------------
; BIOS Parameter Block (FAT32)
;-------------------------------------------------------------------------------

BS_OEMName:                     db              "TestOS  "
BPB_BytesPerSector:             dw              512
BPB_SectorsPerCluster:          db              1
BPB_ReservedSectors:            dw              4
BPB_FATCount:                   db              2
BPB_RootEntryCount:             dw              0
BPB_TotalSectors16:             dw              0
BPB_Media:                      db              0xf0
BPB_FATSize16:                  dw              0
BPB_SectorsPerTrack:            dw              18
BPB_HeadCount:                  dw              2
BPB_HiddenSectors:              dd              0
BPB_TotalSectors32:             dd              2880
BPB_FATSize32:                  dd              23
BPB_ExtendedFlags:              dw              0x0000
BPB_FileSystemVersion:          dw              0
BPB_RootCluster:                dd              2
BPB_FSInfo:                     dw              3
BPB_BackupBootSector:           dw              0
BPB_Reserved:                   times 12 db     0
BS_DriveNum:                    db              0x00
BS_Reserved1:                   db              0x0
BS_BootSignature:               db              0x29
BS_VolumeID:                    dd              0x12345678
BS_VolumeLabel:                 db              "TestOS     "
BS_FileSystemType:              db              "FAT32   "

;-------------------------------------------------------------------------------

_start:
; Initialize segment registers and set up stack at 0x7c00 (grows downwards)
    cli
    xor     ax, ax
    mov     ds, ax
    mov     es, ax
    mov     ss, ax
    mov     sp, 0x7a00
    sti

; Save drive number in DL
    mov     [BS_DriveNum], dl

; Copy this boot sector from 0x7c00 to 0x7a00
    mov     si, 0x7c00
    mov     di, 0x7a00
    mov     cx, 512
    cld
    rep movsb

; Jump to the new location
    jmp     0x0000:(_continue)

_continue:

; Reset boot disk (try it 3 times before error message is printed)
    mov     si, 4

_reset:
    mov     ah, 0
    mov     dl, [BS_DriveNum]
    int     0x13

; Load second boot sector into memory at 0x7c00 (try it 3 times before error message is printed)
_load:
    dec     si
    je      _error
    mov     ah, 0x02
    mov     al, 2
    mov     ch, 0
    mov     cl, 3
    mov     dh, 0
    mov     dl, [BS_DriveNum]
    mov     bx, 0x7c00
    int     0x13
    jc      _load

    mov     si, loaded_msg
    call    print

; Jump to the second boot sector
    jmp     0x0000:0x7c00

; End of program
_end:
    hlt
    jmp     _end

_error:
    mov     si, error_msg
    call    print

    jmp     _end

;-------------------------------------------------------------------------------
; Prints a zero-terminated string onto the screen
; SI = string to write
;-------------------------------------------------------------------------------

print:
    pusha
.print_lbl:
    lodsb
    cmp     al, 0
    je      .finished
    mov     ah, 0x0e
    mov     bl, 0
    int     0x10
    jmp     .print_lbl

.finished:
    popa

    ret

;-------------------------------------------------------------------------------

loaded_msg:             db              "Operating system loaded", 0xa, 0xd, 0x0
error_msg:              db              "Operating system not found", 0xa, 0xd, "Press Ctrl+Alt+Del to reboot", 0x0

; Fill the rest of the 512 bytes with 0, byte 510 and 511
; contains 0xaa55 (boot signature for BIOS)

times 510 - ($ - $$) db 0
dw 0xaa55

使用选项2的代码:

;-------------------------------------------------------------------------------
; boot.asm - First boot sector
;-------------------------------------------------------------------------------

org 0x00
bits 16

    jmp     word _start

;-------------------------------------------------------------------------------
; BIOS Parameter Block (FAT32)
;-------------------------------------------------------------------------------

BS_OEMName:                     db              "TestOS  "
BPB_BytesPerSector:             dw              512
BPB_SectorsPerCluster:          db              1
BPB_ReservedSectors:            dw              4
BPB_FATCount:                   db              2
BPB_RootEntryCount:             dw              0
BPB_TotalSectors16:             dw              0
BPB_Media:                      db              0xf0
BPB_FATSize16:                  dw              0
BPB_SectorsPerTrack:            dw              18
BPB_HeadCount:                  dw              2
BPB_HiddenSectors:              dd              0
BPB_TotalSectors32:             dd              2880
BPB_FATSize32:                  dd              23
BPB_ExtendedFlags:              dw              0x0000
BPB_FileSystemVersion:          dw              0
BPB_RootCluster:                dd              2
BPB_FSInfo:                     dw              3
BPB_BackupBootSector:           dw              0
BPB_Reserved:                   times 12 db     0
BS_DriveNum:                    db              0x00
BS_Reserved1:                   db              0x0
BS_BootSignature:               db              0x29
BS_VolumeID:                    dd              0x12345678
BS_VolumeLabel:                 db              "TestOS     "
BS_FileSystemType:              db              "FAT32   "

;-------------------------------------------------------------------------------

_start:
; Initialize segment registers and set up stack at 0x7c00 (grows downwards)
    cli
    mov     ax, 0x7c0
    mov     ds, ax
    mov     ss, ax

    xor     ax, ax
    mov     sp, 0x7a00
    sti

; Save drive number in DL
    mov     [BS_DriveNum], dl

; Copy this boot sector from 0x7c00 to 0x7a00
    mov     ax, 0x7a0
    mov     es, ax
    xor     si, si
    xor     di, di
    mov     cx, 512
    cld
    rep movsb

; Jump to the new location
    jmp     0x07a0:(_continue)

_continue:

    mov     ax, 0x7c0
    mov     es, ax
    mov     ax, 0x7a0
    mov     ds, ax

; Load second boot sector into memory at 0x7c00 (try it 3 times before error message is printed)
    mov     si, 4

; Reset boot disk
_reset:
    mov     ah, 0
    mov     dl, [BS_DriveNum]
    int     0x13

_load:
    dec     si
    je      _error
    mov     ah, 0x02
    mov     al, 2
    mov     ch, 0
    mov     cl, 3
    mov     dh, 0
    mov     dl, [BS_DriveNum]
    xor     bx, bx
    int     0x13
    jc      _load

    mov     si, loaded_msg
    call    print

; Jump to the second boot sector
    jmp     0x0000:0x7c00

; End of program
_end:
    hlt
    jmp     _end

_error:
    mov     si, error_msg
    call    print

    jmp     _end

;-------------------------------------------------------------------------------
; Prints a zero-terminated string onto the screen
; SI = string to write
;-------------------------------------------------------------------------------

print:
    pusha
.print_lbl:
    lodsb
    cmp     al, 0
    je      .finished
    mov     ah, 0x0e
    mov     bl, 0
    int     0x10
    jmp     .print_lbl

.finished:
    popa

    ret

;-------------------------------------------------------------------------------

loaded_msg:             db              "Operating system loaded", 0xa, 0xd, 0x0
error_msg:              db              "Operating system not found", 0xa, 0xd, "Press Ctrl+Alt+Del to reboot", 0x0

; Fill the rest of the 512 bytes with 0, byte 510 and 511
; contains 0xaa55 (boot signature for BIOS)

times 510 - ($ - $$) db 0
dw 0xaa55

使用选项 3 的代码:

BOOT_ORG EQU 0x7c00

;-------------------------------------------------------------------------------
; boot.asm - First boot sector
;-------------------------------------------------------------------------------

org BOOT_ORG
bits 16

    jmp     word _start

;-------------------------------------------------------------------------------
; BIOS Parameter Block (FAT32)
;-------------------------------------------------------------------------------

BS_OEMName:                     db              "TestOS  "
BPB_BytesPerSector:             dw              512
BPB_SectorsPerCluster:          db              1
BPB_ReservedSectors:            dw              4
BPB_FATCount:                   db              2
BPB_RootEntryCount:             dw              0
BPB_TotalSectors16:             dw              0
BPB_Media:                      db              0xf0
BPB_FATSize16:                  dw              0
BPB_SectorsPerTrack:            dw              18
BPB_HeadCount:                  dw              2
BPB_HiddenSectors:              dd              0
BPB_TotalSectors32:             dd              2880
BPB_FATSize32:                  dd              23
BPB_ExtendedFlags:              dw              0x0000
BPB_FileSystemVersion:          dw              0
BPB_RootCluster:                dd              2
BPB_FSInfo:                     dw              3
BPB_BackupBootSector:           dw              0
BPB_Reserved:                   times 12 db     0
BS_DriveNum:                    db              0x00
BS_Reserved1:                   db              0x0
BS_BootSignature:               db              0x29
BS_VolumeID:                    dd              0x12345678
BS_VolumeLabel:                 db              "TestOS     "
BS_FileSystemType:              db              "FAT32   "

;-------------------------------------------------------------------------------

_start:
; Initialize segment registers and set up stack at 0x7c00 (grows downwards)
    cli
    xor     ax, ax
    mov     ds, ax
    mov     es, ax
    mov     ss, ax
    mov     sp, 0x7a00
    sti

; Save drive number in DL
    mov     [BS_DriveNum], dl

; Copy this boot sector from 0x7c00 to 0x7a00
    mov     si, 0x7c00
    mov     di, 0x7a00
    mov     cx, 512
    cld
    rep movsb

; Jump to the new location
    jmp     0x0000:_continue

; The code and data past this point will have an origin point (vstart)
; relative to 0x7a00. Align=1 for no padding.

section bootreloc vstart=(($-$$)+0x7a00) align=1
_continue:

; Load second boot sector into memory at 0x7c00 (try it 3 times before error message is printed)
    mov     si, 4

; Reset boot disk
_reset:
    mov     ah, 0
    mov     dl, [BS_DriveNum]
    int     0x13

_load:
    dec     si
    jz      _error
    mov     ah, 0x02
    mov     al, 2
    mov     ch, 0
    mov     cl, 3
    mov     dh, 0
    mov     dl, [BS_DriveNum]
    mov     bx, 0x7c00
    int     0x13
    jc      _load

    mov     si, loaded_msg
    call    print

; Jump to the second boot sector

    jmp     0x0000:0x7c00

; End of program
_end:
    hlt
    jmp     _end

_error:
    mov     si, error_msg
    call    print

    jmp     _end

;-------------------------------------------------------------------------------
; Prints a zero-terminated string onto the screen
; SI = string to write
;-------------------------------------------------------------------------------

print:
    pusha
.print_lbl:
    lodsb
    cmp     al, 0
    je      .finished
    mov     ah, 0x0e
    mov     bl, 0
    int     0x10
    jmp     .print_lbl

.finished:
    popa

    ret

;-------------------------------------------------------------------------------

loaded_msg:             db              "Operating system loaded", 0xa, 0xd, 0x0
error_msg:              db              "Operating system not found", 0xa, 0xd, "Press Ctrl+Alt+Del to reboot", 0x0

; Set position to 510 bytes from BOOT_ORG so that bytes 510 and 511
; in te disk image will contain 0xaa55 (boot signature for BIOS)

section bootsig start=(BOOT_ORG+510)
dw 0xaa55

【讨论】:

    猜你喜欢
    • 2013-11-20
    • 2014-09-16
    • 2011-04-08
    • 2020-02-22
    • 1970-01-01
    • 2013-11-02
    • 2017-05-02
    • 2016-10-28
    相关资源
    最近更新 更多