Bootloader 在真实硬件上启动时收到磁盘读取错误,但在 vmware、qemu 和 bochs 上没有启动

问题描述 投票:0回答:1

我已经写了一段时间的 x86 引导加载程序,并且已经验证我的引导加载程序可以在 bochs 和 qemu 以及 vmware 上工作。但是,我在真实硬件(Thinkpad T400)上收到错误代码为 0x0880 的磁盘读取错误,但在 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

我最初认为错误是 BIOS 不支持

int 0x13 ah=42h
扩展,因为我听说有些 BIOS 不支持磁盘扩展,相反我必须使用 CHS 方法(我不想使用 CHS)。但是,在添加检查
ah=42h
读取支持的功能时,没有任何变化,表明BIOS确实支持它。

我还搜索了为什么我的代码不能在真实硬件上运行的原因并遵循了所有这些(例如:确保 DS 为零,清除方向标志等)

我想就如何解决这个问题提出一些建议。

assembly x86 nasm bootloader osdev
1个回答
5
投票

有些 BIOS 不允许使用

int 13h/ah=42h
一次读取超过 127 个扇区。我建议将
KERNEL_SIZE_SECTORS
设置为 127 而不是 128.

在其他地方(但我没有遇到过)有人建议,有些 BIOS 需要您在执行磁盘读取之前将 ES 设置为与 DAP 的段字段中指定的值相同的值。在您的情况下,建议在启动读取之前将 ES 设置为 0x07c0 以匹配磁盘地址包 (DAP) 中的段值。

© www.soinside.com 2019 - 2024. All rights reserved.