【问题标题】:int 13h 42h doesn't load anything in Bochsint 13h 42h 不会在 Bochs 中加载任何内容
【发布时间】:2017-10-02 19:58:08
【问题描述】:

我将引导加载程序从 CHS 更改为 LBA,因此我将 int 13h 02h 替换为 int 13h 42h。它在 QEMU 中正常工作,但是,我在使用 Bochs 和我的笔记本电脑运行它时遇到了麻烦。

我使用 dd if=main.bin of=/dev/sdb bs=512 将引导加载程序写入 USB 闪存驱动器。笔记本电脑加载 Intel UNDI 并给我以下错误:No bootable device - insert boot disk and press any key

所以我尝试使用 Bochs 对其进行调试,并注意到 Bochs 将此二进制文件识别为可引导文件。但是,int 13h 执行后没有加载任何内容。

然后我尝试从这个闪存驱动器加载我的旧电脑,它工作正常!它加载程序并正确执行它。 QEMU 给了我同样的结果。

这是引导加载程序代码:

org 0x7c00
bits 16

boot:
    cli
    ; Overlap CS and DS
    mov ax, cs
    mov ds, ax
    mov es, ax
    ; Setup 4K stack before this bootloader
    mov ax, 0x07c0
    mov ss, ax
    mov sp, 4096
    ; Load next sectors
    mov si, DAP
    mov ah, 42h
    ; DL didn't changed
    int 13h
    ; Start
    jmp bootend

; Disk address packet
DAP:
    db 10h, 0
    dw %1 ; Number of sectors to be loaded
    dd bootend
    dq 1

; Fill the rest of bootsector with zeroes and end it
times 510 - ($ - boot) db 0
dw 0xAA55
bootend:

bochsrc:

megs: 32
romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xfffe0000
vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest
floppya: 1_44=main.bin, status=inserted
boot: a
panic: action=ask
log: bochsout.txt
mouse: enabled=0
keyboard: type=mf, serial_delay=200, paste_delay=100000
display_library: x, options="gui_debug"

【问题讨论】:

    标签: x86 nasm bootloader bios bochs


    【解决方案1】:

    LBA 磁盘访问可用性

    并非所有 BIOS 都支持扩展磁盘读写功能(尽管在现代硬件上几乎都支持)。并非所有 BIOS 都支持通过Int 13h/AH=42h 对软盘进行扩展磁盘读取。 BOCHS 也是如此。您可以通过Int 13/AH=41h/BX=55AAh 测试驱动器上是否可以使用扩展磁盘功能。这会进行扩展磁盘安装检查。

    如果您想使用扩展磁盘读取和 LBA 在 BOCHS 上测试您的代码,您必须创建一个硬盘映像并修改 BOCHS 以从它启动,而不是软盘。 BOCHS 支持的最小硬盘映像大小是 CHS = 1/16/63,即 512*16*63 = 516096 字节或 1008 个扇区,每个扇区 512 字节。

    您可以将bochsrc.txt 修改为:

    megs: 32
    romimage: file=/usr/share/bochs/BIOS-bochs-latest, address=0xfffe0000
    vgaromimage: file=/usr/share/bochs/VGABIOS-lgpl-latest
    boot: c
    ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
    ata0-master: type=disk, path="disk.img", mode=flat, cylinders=0, heads=0, spt=0, model="Generic 1234", biosdetect=auto, translation=auto
    panic: action=ask
    log: bochsout.txt
    mouse: enabled=0
    keyboard: type=mf, serial_delay=200, paste_delay=100000
    display_library: x, options="gui_debug"
    

    我使用名为disk.img 的磁盘映像。您可以使用以下命令创建它并将生成的扇区放入其中:

    nasm -f bin main.asm -o main.bin
    

    创建一个 516096 字节的图像:

    dd if=/dev/zero of=disk.img count=1008 bs=512
    

    将引导扇区放在disk.img 的开头而不截断文件:

    dd if=main.bin of=disk.img conv=notrunc
    

    我有更多关于使用 DD 在这个Stackoverflow answer 中创建磁盘映像的信息。


    一般代码观察

    虽然磁盘映像是 BOCHS 问题的一部分,但您确实存在一些编码问题。您不能假设 CS 的值将设置为当控制从 BIOS 转移到引导加载程序时您认为的值。请参阅我的General Bootloader Tips 了解更多信息。如果您希望 DSES 为零(这是您使用 org 0x7c00 所需要的),您应该将代码的开头修改为:

    org 0x7c00
    bits 16
    
    boot:
        cli
    
        xor ax, ax     ; Explicitly set DS and ES to 0
        mov ds, ax
        mov es, ax
    

    为了测试你的代码,我在bootend 之后添加了这个:

    bootend:
    
        ; Print MDP to upper left of screen in white on light magenta
        mov ax, 0xb800
        mov es, ax
        mov word [es:0x0000], 0x57<<8 | 'M'
        mov word [es:0x0002], 0x57<<8 | 'D'
        mov word [es:0x0004], 0x57<<8 | 'P'
    
        ; Infinite loop so we don't have the CPU wander memory
        cli
    endloop:
        hlt
        jmp endloop
    

    我不确定这一行是错字还是您在将汇编文件传递给 NASM 之前对它们使用了某种类型的预处理器。通常这一行会是% 符号在1 之前的问题:

    dw %1 ; Number of sectors to be loaded
    

    NASM 只会直接支持这个:

    dw 1  ; Number of sectors to be loaded
    

    真实硬件/USB/笔记本电脑问题

    如果您尝试使用 USB 在真实硬件上启动,那么即使您通过上述更改使其在 BOCHS 中工作,您也可能会遇到另一个问题。如果您的 BIOS 设置为进行 USB FDD 仿真(而不是 USB HDD 或其他),您可能需要在引导加载程序的开头添加 Boot Parameter Block(BPB)。你可以像这样创建一个假的:

    org 0x7c00
    bits 16
    
    boot:
        jmp main
        TIMES 3-($-$$) DB 0x90   ; Support 2 or 3 byte encoded JMPs before BPB.
    
        ; Dos 4.0 EBPB 1.44MB floppy
        OEMname:           db    "mkfs.fat"  ; mkfs.fat is what OEMname mkdosfs uses
        bytesPerSector:    dw    512
        sectPerCluster:    db    1
        reservedSectors:   dw    1
        numFAT:            db    2
        numRootDirEntries: dw    224
        numSectors:        dw    2880
        mediaType:         db    0xf0
        numFATsectors:     dw    9
        sectorsPerTrack:   dw    18
        numHeads:          dw    2
        numHiddenSectors:  dd    0
        numSectorsHuge:    dd    0
        driveNum:          db    0
        reserved:          db    0
        signature:         db    0x29
        volumeID:          dd    0x2d7e5a1a
        volumeLabel:       db    "NO NAME    "
        fileSysType:       db    "FAT12   "
    
    main:
        cli
    
        xor ax, ax     ; Explicitly set DS and ES to 0
        mov ds, ax
        mov es, ax
        [rest of your code here]
    

    如果您要修改代码以使布局高于 Unix/Linux file 命令可能能够转储它认为构成磁盘映像中的 MBR 的 BPB 数据。运行命令file disk.img,你可能会得到这样的输出:

    disk.img:DOS/MBR 引导扇区,代码偏移量 0x3c+2,OEM-ID “mkfs.fat”,根条目 224,扇区 2880(卷


    带有 Int 13h 扩展检查的完整示例

    以下代码将检查 BIOS 中的 Int 13h 扩展是否可用,并且还将确定 DL 中的驱动器是否支持 Int 13h 扩展。如果出现故障,代码将打印相应的错误。 print_string 函数用于使用 BIOS TTY 输出向控制台显示字符串,print_hex_word 函数用于以十六进制显示引导驱动器号。

    org 0x7c00
    bits 16
    
    section .text
    boot:
        jmp main
        TIMES 3-($-$$) DB 0x90   ; Support 2 or 3 byte encoded JMPs before BPB.
    
        ; Dos 4.0 EBPB 1.44MB floppy
        OEMname:           db    "mkfs.fat"  ; mkfs.fat is what OEMname mkdosfs uses
        bytesPerSector:    dw    512
        sectPerCluster:    db    1
        reservedSectors:   dw    1
        numFAT:            db    2
        numRootDirEntries: dw    224
        numSectors:        dw    2880
        mediaType:         db    0xf0
        numFATsectors:     dw    9
        sectorsPerTrack:   dw    18
        numHeads:          dw    2
        numHiddenSectors:  dd    0
        numSectorsHuge:    dd    0
        driveNum:          db    0
        reserved:          db    0
        signature:         db    0x29
        volumeID:          dd    0x2d7e5a1a
        volumeLabel:       db    "NO NAME    "
        fileSysType:       db    "FAT12   "
    
    main:
        cli
        cld                   ; String instructions forward movement
    
        xor ax, ax
        mov ds, ax
        mov es, ax
        ; Setup 4K stack before this bootloader
        mov ss, ax
        mov sp, 0x7c00
    
        ; Display a banner to know our bootloader is executing
        mov si, msg_booting
        call print_string
    
        ; Check that Int 13h Extensions are available
        ; http://www.ctyme.com/intr/rb-0706.htm
    
        mov ah, 0x41          ; Int 13h/AH=41h: Check if extensions present
        mov bx, 0x55aa
        int 0x13
        jc  ext_drv_none      ; CF set - no extensions available for drive
        cmp bx, 0xaa55        ; Is BX 0xaa55?
        jnz ext_none          ;     If not, int 13h extensions not supported
                              ;     by BIOS at all.
    
        ; Int 13h extensions supported by BIOS and drive at this point
        ; Load next sectors
        mov si, DAP
        mov ah, 42h
        ; DL didn't changed
        int 13h
        ; Start
        jmp bootend
    
    ; Error: BIOS doesn't support Int 13h extensions
    ext_none:
        mov si, err_no_extensions
        call print_string
        jmp error_end
    
    ; Error: BIOS supports Int 13h extensions but not for drive in DL
    ext_drv_none:
        mov si, err_no_drv_ext_support
        call print_string
    
        ; Print the boot drive number in hex
        xor dh, dh            ; Zero extended drive number to all of DX
        push word 0x00        ; Attribute and page number to write to
        push dx               ; The value to write as hex
        call print_hex_word
    
    
    error_end:
        cli
    .loop:
        hlt
        jmp .loop
    
    ; Print 16 bit value passed on stack as first parameter
    ; in hexadecimal. Use page number and foreground color
    ; passed in second parameter. This routine will work on 8086+
    ; processors. This code takes advantage of packed BCD to
    ; determine the ASCII values to print. This code could have
    ; used compare and branch to do the same or a translation table.
    
    print_hex_word:
        push bp
        mov bp, sp      ; BP=SP, on 8086 can't use sp in memory operand
        push dx         ; Save all registers we clobber
        push cx
        push bx
        push ax
    
        mov cx, 0x0404  ; CH = number of nibbles to process = 4 (4*4=16 bits)
                        ; CL = Number of bits to rotate each iteration = 4 (a nibble)
        mov dx, [bp+4]  ; DX = word parameter on stack at [bp+4] to print
        mov bx, [bp+6]  ; BX = page / foreground attr is at [bp+6]
    
    .loop:
        rol dx, cl      ; Roll 4 bits left. Lower nibble is value to print
        mov ax, 0x0e0f  ; AH=0E (BIOS tty print),AL=mask to get lower nibble
        and al, dl      ; AL=copy of lower nibble
        add al, 0x90    ; Work as if we are packed BCD
        daa             ; Decimal adjust after add.
                        ;    If nibble in AL was between 0 and 9, then CF=0 and
                        ;    AL=0x90 to 0x99
                        ;    If nibble in AL was between A and F, then CF=1 and
                        ;    AL=0x00 to 0x05
        adc al, 0x40    ; AL=0xD0 to 0xD9
                        ; or AL=0x41 to 0x46
        daa             ; AL=0x30 to 0x39 (ASCII '0' to '9')
                        ; or AL=0x41 to 0x46 (ASCII 'A' to 'F')
        int 0x10        ; Print ASCII character in AL
        dec ch
        jnz .loop       ; Go back if more nibbles to process
    
        pop ax          ; Restore registers
        pop bx
        pop cx
        pop dx
        pop bp
        ret
    
    ; Print string pointed to by DS:SI using
    ; BIOS TTY output via int 10h/AH=0eh
    
    print_string:
        push ax
        push si
        mov ah, 0Eh       ; int 10h 'print char' function
    
    .repeat:
        lodsb             ; Get character from string
        test al, al
        je .done      ; If char is zero, end of string
        int 10h           ; Otherwise, print it
        jmp .repeat
    .done:
        pop si
        pop ax
        ret
    
    ; Disk address packet
    DAP:
        db 10h, 0
        dw 1 ; Number of sectors to be loaded
        dd bootend
        dq 1
    
    msg_booting:            db "Booting... ", 0x00
    err_no_extensions:      db "Int 13h extensions not supported by BIOS", 0x00
    err_no_drv_ext_support: db "Int 13h Extensions not supported on drive 0x", 0x00
    
    ; Fill the rest of bootsector with zeroes and end it
    times 510 - ($ - boot) db 0
    dw 0xAA55
    bootend:
    
        mov ax, 0xb800
        mov es, ax
        mov word [es:0x0000], 0x57<<8 | 'M'
        mov word [es:0x0002], 0x57<<8 | 'D'
        mov word [es:0x0004], 0x57<<8 | 'P'
        cli
        hlt
    

    使用上面的信息制作硬盘映像,当我在 BOCHS 中运行它时,我得到以下输出:

    如果我在 BOCHS 中将同一映像作为软盘(磁盘 A:) 启动,则错误消息现在告诉我 Int 13h 扩展不适用于驱动器 0x0000:

    如果您发现需要读取不支持 Int 13h 扩展的设备,您将不得不回退到 reading (AH=02)/writing (AH= 03).

    【讨论】:

    • 感谢您的完整回答!但是,我没有成功地遵循它。当我将 BPB 添加到引导扇区的开头时,QEMU 不会将此二进制文件识别为可引导的。我像你一样创建了硬盘映像,但 Bochs 为 ata0-slave 写了unknown type 'none'。也许我应该为 ata0 尝试另一种类型?附言抱歉评论不完整,写的时候不小心按了回车
    • 构建:nasm -f bin -i "../lib/" main.asm -o main.bindd if=/dev/zero of=main.img count=1008 bs=512dd if=main.bin of=main.img conv=notrunc 运行:qemu-system-i386 -s -m 32 -drive format=raw,file=main.bin(也尝试过file=main.img)当我删除 BPB 时,QEMU 运行正常。另外,我刚刚从 bochsrc 中删除了 ata0-slave,现在 Bochs 运行了,但似乎 int 13h 42h 即使使用硬盘也无法正常工作,所以我会检查 Bochs 是否支持扩展磁盘读取。
    猜你喜欢
    • 2015-07-16
    • 2014-09-16
    • 2015-02-18
    • 2011-09-09
    • 1970-01-01
    • 1970-01-01
    • 2011-11-17
    • 2016-04-23
    • 2012-12-16
    相关资源
    最近更新 更多