首页 文章

Bootloader在真实硬件上打印垃圾

提问于
浏览
5

我正在尝试编写自己的bootloader . 虽然它在QEMU,Bochs和VirtualBox中运行良好,但我似乎无法在笔记本电脑上运行 .

在我的笔记本电脑上,引导加载程序与所有模拟器的行为完全不同,挂起看似随机的地方,拒绝打印,甚至跳过一些 jmp $ 指令 .

虽然我对“真实硬件”有很多麻烦,但我认为它们都有一个原因 .

以下代码是一个短引导加载程序,应该打印“TEST”消息3次,然后跳转到同一位置挂起:

[BITS 16]                                                                          
[ORG 0x7C00]                                                                                                    
    jmp 0x0000:start_16  ; In case bootloader is at 0x07C0:0x0000                                                             
start_16:                                                                          
    xor ax, ax                                                                 
    mov ds, ax                                                                 
    mov es, ax                                                                 
    cli                             ; Disable interrupts                       
    mov ss, ax                                                                 
    mov sp, 0x7C00                                                             
    sti                             ; Enable interrupts                        
    cld                             ; Clear Direction Flag                     
    ; Store the drive number                                                   
    mov [drive_number], dl                                                     
    ; Print message(s)                                                         
    mov si, msg                                                                
    call print_string                                                          
    mov si, msg                                                                
    call print_string                                                          
    mov si, msg                                                                
    call print_string                                                          

    jmp $   ; HALT                                                                                   

; print_string                                                                     
;       si      = string                                                           
print_string:                                                                      
    pusha                                                                      
    mov ah, 0x0E                                                               
.repeat:                                                                           
    lodsb                                                                      
    cmp al, 0x00                                                               
    je .done                                                                   
    int 0x10                                                                   
    jmp short .repeat                                                          
.done:                                                                             
    popa                                                                       
    ret                                                                        

; Variables                                                                        
drive_number db 0x00                                                               
msg db 'TEST', 0x0D, 0x0A, 0x00                                                    
times 510-($-$$) db 0x00                                                           
db 0x55                                                                            
db 0xAA

Compile and emulate the code with:

$ nasm -f bin bootloader.asm
$ qemu-system-x86_64 bootloader

在模拟器上,它打印“TEST”三次并挂起,在我的笔记本电脑上,它打印“TEST”,然后是3个奇怪的字符:

Bootloader output on my laptop.

来自http://wiki.osdev.org的大多数引导加载程序代码也不起作用 . 例如,http://wiki.osdev.org/Babystep2中的所有代码片段都不能在我的笔记本电脑上运行 .

我的代码出了什么问题?我该如何解决?


其他信息

如果我删除了2个不必要的 mov si, msg ,则会打印"TEST"消息 twice .

Laptop:

  • 华硕Vivobook S200,

  • CPU:Intel i3-3217U

  • BIOS:American Megatrends,版本210 .

  • 计算机可以与任何其他引导加载程序(如Grub)一起使用 .

Assembly and writing:

$ nasm -f bin bootloader.asm
$ qemu-system-x86_64 bootloader # TEST 1 
$ sudo dd if=/dev/zero of=/dev/sdd bs=1M count=1 # clean the USB 
$ sudo dd if=bootloader of=/dev/sdd conv=fsync # write to USB 
$ qemu-system-x86_64 /dev/sdd # TEST 2

编辑1

Ross Ridge在评论中注意到 Ω♣| 是引导加载程序的前3个字节 .

编辑2

更新了打印功能和字符串:

print_string:                                                                      
    pusha                                                                          
.repeat:                                                                        
    mov ah, 0x0E                                                                
    xor bx, bx                                                                  
    cld                             ; Clear Direction Flag                      
    lodsb                                                                       
    cmp al, 0x00                                                                
    je .done                                                                    
    int 0x10                                                                    
    jmp short .repeat                                                           
.done:                                                                          
    popa                                                                        
    ret 

msg db 'TEST', 0x00

Output

一个 TEST . 另外两个缺失 .

编辑3

正如Ross Ridge所建议的,已经添加了 dumpregs 以便更好地进行调试 . int 0x10 确实 not 修改任何寄存器 . 经过一些测试后,我已经将 dumpregs 函数移到 drive_number 赋值和 jmp $ 之后 . 代码应打印1行寄存器转储并暂停 . 相反,它继续:
dumpregs around drive_number assignment

完整代码:https://gist.github.com/anonymous/0ddc146f73ff3a13dd35

编辑4

使用以下方法反汇编当前的bootloader:

$ ndisasm -b16 bootload2 -o 0x7c00

https://gist.github.com/anonymous/c9384fbec25513e3b815

2 回答

  • 4

    它现在看起来像BIOS可能修改BIOS parameter block,它错误地认为是加载到内存中的bootsector的一部分 . 它可能感觉需要,因为它在引导时为USB设备提供的几何结构可能与引导程序及其假定的BPB写入设备时使用的几何结构不同 . 由于在bootsector开始时存在跳转指令是应用程序测试BPB存在的方法之一,因此您可以尝试在bootsector的开头插入一些其他指令(但不是NOP) . 例如:

    [BITS 16]                                                                          
    [ORG 0x7C00]
        xor ax,ax                                                                                                
        jmp 0x0000:start_16  ; In case bootloader is at 0x07C0:0x0000                                                             
    start_16:
    

    请注意,远跳似乎不是normal indicators of the presence of a BPB之一 . 事实上,它存在's pretty conclusive evidence that a BPB isn' t,因为BPB从偏移量4开始,远跳跃指令长5个字节 .

    如果这不起作用,您可以尝试为BPB保留空间,如下所示:

    [BITS 16]                                                                          
    [ORG 0x7C00]
        jmp start
        nop
        resb 8 + 25
    start:                                                                                          
        jmp 0x0000:start_16  ; In case bootloader is at 0x07C0:0x0000                                                             
    start_16:
    

    这里有一些代码可用于转储寄存器以帮助调试问题:

    dumpregs:
        push    es
        pusha
        push    0xb800
        pop es  
        mov di, [vidmem_ptr]
        mov bp, sp
        mov cx, 8
    dump_loop:
        dec bp
        dec bp
        mov ax, [bp + 16]
        call    printhex2
        inc di
        inc di
        loop    dump_loop
        mov [vidmem_ptr], di
        popa
        pop es
        ret
    
    printhex2:
        push    ax
        mov al, ah
        call    convhex1
        pop ax
    convhex1:
        aam 16
        ; DB    0D4h, 16
        xchg    al, ah
        call    convhex
        mov al, ah
    convhex:
        cmp al, 10
        jb  lessthan_10
        add al, 'A' - '0' - 10
    lessthan_10:
        add al, '0'
        stosb
        mov al, 7
        stosb
        ret
    
    vidmem_ptr dw 5 * 80 * 2 ; start at row 5
    

    它使用直接视频写入来转储所有通用寄存器 . 它使用PUSHA / POPA寄存器命令:AX CX DX BX SP BP SI DI

    如果通过调用此函数将原始代码中的INT 0x10指令括起来,则应获得如下输出:

    Screenshot of boot with debug output

    特别要确保左侧的8个数字与右侧的8个数字匹配,用于每行调试输出 . 您正在使用的BIOS调用不应该更改任何寄存器 .

  • 2

    我以前见过类似的症状 . 场景可能是这样的:

    a)您正在从USB闪存启动笔记本电脑

    b)BIOS查看设备的第一个扇区,并尝试确定它是否应将其视为软盘或硬盘驱动器 . 它无法找到有效的分区表,因此它决定将其视为软盘 .

    c)BIOS尝试“有用”并修补BPB中的某些字段 .

    d)您没有BPB,因此您的代码和/或数据被破坏,导致奇怪的事情发生(代码中的微小变化会导致不同的奇怪事情发生) .

    可悲的是,我自己没有这样做的硬件 . 我不知道为什么BIOS假设有一个BPB,或者它假设有多种不同的“BPB格式”,或者它认为它可能是什么修补或为什么它认为有必要修补任何东西 . 我只知道有些BIOS会将偏移量为0x1C至0x1F的字节和偏移量为0x24的字节进行废弃 .

相关问题