Bootloader receives a disk read error when booting on real hardware but not on vmware, qemu, and bochs

huangapple go评论71阅读模式
英文:

Bootloader receives a disk read error when booting on real hardware but not on vmware, qemu, and bochs

问题

我已经编写了一个x86引导加载程序一段时间,已经验证了我的引导加载程序在bochs、qemu和vmware上都能正常工作。然而,在真实硬件(Thinkpad T400)上,我遇到了一个磁盘读取错误,错误代码为0x0880,但在qemu上没有这个问题。

最初我认为这个错误是由于BIOS不支持int 0x13 ah=42h扩展引起的,因为我听说有些BIOS不支持磁盘扩展,而必须使用CHS方法(我不想使用CHS)。但是,当添加了检查ah=42h读取支持的函数后,没有任何变化,这表明BIOS支持这个功能。

我还搜索了一些可能导致我的代码在真实硬件上不工作的原因,并尝试了所有这些方法(例如,确保DS寄存器为零,清除方向标志等)。

我想请教一些建议,以解决这个问题。

注意:我只提供代码部分的翻译,不提供回答问题的翻译。以下是代码部分的翻译:

[bits 16]
[extern kernel]
[global isr_stub_table]
[global IDT_load]

[extern FortressLoader_IdtInit]
[extern FortressLoader_ChecmMemMap]

[extern X86TTY_Init]
[extern X86TTY_Clear]
[extern printf]

[global FortressLoader_HeapStart]
[global FortressLoader_HeapEnd]

[global startKernel]

section .boot
global boot

KERNEL_SIZE_SECTORS equ 128

jmp boot
TIMES 3-($-$$) DB 0x90

; ...(以下是你的汇编代码的一部分,包括引导加载程序和其他函数)...

如果你需要更多关于如何解决这个问题的帮助,请随时提问。

英文:

I have been writing a x86 bootloader for some while, and have verified that my bootloader works on both bochs and qemu, along with vmware. However, I get a disk read error with an error code of 0x0880 on real hardware (Thinkpad T400), but not on qemu.

[bits 16]
[extern kernel]
[global isr_stub_table]
[global IDT_load]

[extern FortressLoader_IdtInit]
[extern FortressLoader_ChecmMemMap]

[extern X86TTY_Init]
[extern X86TTY_Clear]
[extern printf]

[global FortressLoader_HeapStart]
[global FortressLoader_HeapEnd]

[global startKernel]

section .boot
global boot

KERNEL_SIZE_SECTORS equ 128

jmp boot
TIMES 3-($-$$) DB 0x90

OEMname:           db    "mkfs.fat"
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    0x65
volumeID:          dd    0x2d7e5a1a
volumeLabel:       db    "NO NAME    "
fileSysType:       db    "FAT12   "

boot:
    cld                        ;Clear direction flag
    
    xor    ax, ax
    mov    ds, ax 
    mov    es, ax
    mov    ss, ax
    mov    fs, ax
    mov    gs, ax
    mov    sp, 0x7c00
    mov    di, 0x7c00

    cli

    mov    ah, 0x41             ;Check to make sure 13h extensions
    mov    bx, 55AAh            ;CONT: are enabled by the BIOS
    int    0x13                 ;Call the disky wisky interrupt 🥺

    jc     dskDrvNope           ;Print no disk support msg
    cmp    bx, 0xAA55           ;Check if 13h supported by BIOS
    jnz    dskDrvNoExtAtALl

    mov    bx, diskNoError      ;
    call   print


    mov    [disk], dl
    mov    ax, 0x2401
    int    0x15
 
    mov    ax, 0x3              ;Set the VGA mode, unknown at boot
    int    0x10
 
    mov    ah, 42h
    mov    dl, [disk]
    mov    si, dap
    int    0x13
 
    jc     disk_err             ;Jump if disk read error
    jmp    disk_target          ;

dskDrvNope:
    mov    bx, disk_no_extensions
    call   print
    hlt
dskDrvNoExtAtALl:
    mov    bx, disk_no_extatall
    call   print
    hlt

print:
    pusha
start:
    mov    al, [bx] 
    cmp    al, 0 
    je     done
 
    mov    ah, 0x0e
    int    0x10 
 
    add    bx, 1
    jmp    start
 
done:
    popa
    ret
 
print_nl:
    pusha  
 
    mov    ah, 0x0e
    mov    al, 0x0a
    int    0x10
    mov    al, 0x0d
    int    0x10
 
    popa
    ret
 
print_hex:
    pusha
 
    mov    cx, 0
 
hex_loop:
    cmp    cx, 4
    je     end
 
    mov    ax, dx
    and    ax, 0x000f
    add    al, 0x30 
    cmp    al, 0x39
    jle    step2
    add    al, 7
 
step2:
    mov    bx, HEX_OUT + 5
    sub    bx, cx
    mov    [bx], al
    ror    dx, 4
 
    add    cx, 1
    jmp    hex_loop
 
end:
    mov    bx, HEX_OUT
    call   print
 
    popa
    ret
 
disk_err:                      ;Label for any disk errors
    mov    bx, disk_read_error ;Print the disk error
    call   print
    call   print_nl
    mov    dh, ah              ;Load error code in ah register
    call   print_hex
    jmp    $
 
disk:
    db     0x0

dap:
    db     0x10
    db     0
    dw     KERNEL_SIZE_SECTORS
    dw     0                   ;
    dw     0x07e0              ;value recommended by a friend
    dq     1                   ;start second sector read
 
HEX_OUT:
    db     '0x0000',0
 
disk_read_error:    db "Disk read error!", 0
disk_no_extensions: db "no disk ah=42h", 0
disk_no_extatall:   db "no bios ah=42h", 0
diskNoError:        db "Using bios extensions", 0

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

%include "./fortressloader/memory.asm"
%include "./fortressloader/memmap.asm"
%include "./fortressloader/multiboot.asm"
 
GDT_START:
    dq     0x0
GDT_CODE: 
    dw     0xffff 
    dw     0x0 
    db     0x0 
    db     10011010b
    db     11001111b
    db     0x0
GDT_DATA:
    dw     0xFFFF
    dw     0x0
    db     0x0
    db     10010010b
    db     11001111b
    db     0x0
GDT_END:
GDT_POINTER
    dw     GDT_END - GDT_START - 1
    dd     GDT_START
 
CODE_SEG equ GDT_CODE - GDT_START
DATA_SEG equ GDT_DATA - GDT_START

disk_target
    call   BiosGetMemorySize64MB  
                               ;Load the memory size
    mov    [mbInfo+mbInfo.memoryHi], bx
    mov    [mbInfo+mbInfo.memoryLo], ax
    mov    word [mbInfo+mbInfo.bootDevice], 0x0
    mov    edi, 0x2000


    call   BiosGetMemoryMap
    mov    word [mbInfo+mbInfo.mmap_length], ax
    mov    word [mbInfo+mbInfo.mmap_addr], 0x2000

    cli                        ;Clear the interrupts
    lgdt   [GDT_POINTER]       ;Load the GDT using a gdt pointer
    mov    eax, cr0
    or     eax, 0x1
    mov    cr0, eax
    jmp    CODE_SEG:boot2

[bits 32]
startKernel:
boot2:
    mov    ax, DATA_SEG
    mov    ds, ax
    mov    es, ax
    mov    fs, ax
    mov    gs, ax
    mov    ss, ax
    mov    esi, loaded_msg
    mov    ebx, 0xb8000
.loop:                         ;Print a message using a loop
    lodsb
    or     al, al
    jz     load_kernel         ;Load kernel when msg finished
    or     eax,0x0F00
    mov    word [ebx], ax
    add    ebx,2
    jmp    .loop
load_kernel:
    mov    esp, kernel_stack_top
                               ;Load the stack to call C functions

    call   X86TTY_Init         ;Initialize the TTY
    call   X86TTY_Clear        ;Clear everything on the screen
    call   FortressLoader_IdtInit
                               ;Initialize the IDT    

    mov    eax, 0x1BADB002     ;Multiboot magic number
    mov    ebx, mbInfo
    mov    ebx, 0

    push   eax
    push   ebx

    call   kernel              ;Call the actual kernel
halt:    
    cli
    hlt

loaded_msg:db "Operating system loaded",0          
                               ;Message here to verify disk read
 
section .bss
align 4
kernel_stack_bottom: equ $     ;equ the current address for the stack
    resb             16384     ;Use 16kb for stack size
kernel_stack_top:              ;Top of the stack

section .text

My original belief for the error was that the int 0x13 ah=42h extensions were not supported by the BIOS, as I had heard that some BIOSes do not support the disk extensions and instead I would have to use the CHS method (I would prefer not to use CHS). However, when adding the functions to check for the ah=42h read support, nothing changes, indicating that the BIOS does support it.

I have also searched for reasons on why my code does not work on real hardware and followed all of them (ex: making sure DS is zero, clearing direction flag, etc)

I would like a few pointers on how to fix this issue.

答案1

得分: 5

一些 BIOS 不允许一次使用 int 13h/ah=42h 读取超过 127 个扇区的数据。我建议将 KERNEL_SIZE_SECTORS 设置为 127,而不是 128。

有人在其他地方提到过(但我没有亲身经历过)一些 BIOS 需要你在进行磁盘读取之前将 ES 寄存器设置为与 DAP(Disk Address Packet)中的段字段指定的值相同。在你的情况下,建议将 ES 设置为 0x07c0,以匹配 DAP 中的段值,然后再进行读取。

英文:

Some BIOSes don't allow the reading of more than 127 sectors at a time using int 13h/ah=42h. I'd recommend setting KERNEL_SIZE_SECTORS to 127 instead of 128.

It has been suggested elsewhere (but not something I have experienced) that there are BIOSes that need you to set ES to the same value as what is specified in the DAP's segment field before doing the disk read. In your case it might be advisable to set ES to 0x07c0 to match the segment value in the Disk Address Packet (DAP) before you initiate the read.

huangapple
  • 本文由 发表于 2023年2月24日 06:59:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75551169.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定