Phoenix BIOS 跳过 MBR 代码,ACTUAL BIOS 标准是什么?

Phoenix BIOS skips MBR code, what is the ACTUAL BIOS standard?

我想学习汇编程序以使用最少的裸代码获得任何 x86 兼容机器运行 在开机时在屏幕上显示硬编码文本。 我关心与 x86/IBM 机器的完全兼容性。

我遵循了有关简单引导代码的教程,但从我的笔记本电脑上的 USB 物理上 运行 它们惨遭失败。就好像我的笔记本甚至没有接触到 MBR 代码。 我花了两个星期的时间阅读了大量的文章,但这些文章让我一无所获。我学到了很多关于 BIOS 参数块、分区条目、this old Phoenix BIOS specification 和 UEFI 的知识。

我的笔记本电脑可以使用我的可启动 FreeDOS USB 正确启动。 这是我的带有 MBR 的 FreeDOS USB 的第一个扇区: Nice and full of real useful codey-code

我尝试从带有 UEFI 的台式计算机启动它并且成功了。 我尝试从带有 Phoenix BIOS 的笔记本电脑启动它,它成功了。

然后我擦除所有引导指令: Nice and full of NOTHING but one partition entry

我试图从同一台装有 UEFI 的台式机启动它,但它按预期失败了。 我尝试从带有 Phoenix BIOS 的笔记本电脑上启动它,它成功了。我发誓。

我想知道为什么有一个 BIOS 可以自己解决问题并跳过 MBR 指令,如果有更多类似的,我在哪里可以找到它们的文档,这样我就可以使我的引导代码完全兼容所有 BIOS。

我笔记本的BIOS版本是1.08,EC版是1.07。 我不想更新它。如果 FreeDOS 可以正常启动,那么我希望我的引导代码也可以正常启动。

此答案基于经验和有根据的猜测。没有实际硬件很难测试。我假设 OP 正在将他的引导扇区写入 MBR 而不是 VBR。


多年来创建的 BIOS 既愚蠢又聪明(恕我直言,有些太聪明了)。有些人试图根据是否存在 BIOS 参数块 and/or 分区 table 和 bootable 分区来区分可能是软盘驱动器还是硬盘驱动器。不幸的是,这不是标准化的,许多 BIOS 制造商只针对按 Windows.

分区的磁盘测试他们的代码

一些认为他们看到有效分区的 BIOS table 将采用 HDD 仿真并尝试从活动分区加载卷引导记录 (VBR),而不是在 MBR 上执行代码。我怀疑这就是机器上的情况,尽管将代码清零并保留分区 table,但它似乎仍在启动。执行的代码可能直接来自VBR。

如果使用充当硬盘驱动器(而不是软盘)的设备,您可以创建一个带有分区 table 的 MBR,其中唯一的活动分区从驱动器的开头开始(CHS=0,0 ,1 或 LBA=0);被标记为 bootable;并且具有非零分区类型。如果您遇到一台打算直接加载 VBR 的机器,那么此方法会诱使它加载 MBR 作为 VBR。

示例代码应该在您的 USB 上作为您似乎正在测试的机器上的 HDD 介质启动,如下所示:

bits 16
org 0x7c00

boot_start:
    xor ax, ax                  ; DS=0 since we use ORG 0x7c00. 0x0000<<4+0x7c00=0x7c00
    mov ds, ax
    mov es, ax

    ; If you will be reading data into memory outside of 0x7c00 to 0x7dff
    ; then you want to set the stack SS:SP - uncomment these lines
    ; mov ss, ax                ; Stack at 0x0000:0x7c00
    ; mov sp, 0x7c00            ;     Just below bootloader

    cld                         ; Forward movement of string instructions
                                ;     (MOVSB, SCASB, etc)

    mov si, HelloWorldMsg       ; Print hello world
    call print_string

end_loop:                       ; Loop forever to terminate
    hlt
    jmp end_loop

; Function: print_string
;           Display a string to the console on display page 0
;
; Inputs:   SI = Offset of address to print
; Clobbers: AX, BX, SI

print_string:
    mov ah, 0x0e                ; BIOS tty Print
    xor bx, bx                  ; Set display page to 0 (BL)
    jmp .getch
.repeat:
    int 0x10                    ; print character
.getch:
    lodsb                       ; Get character from string
    test al,al                  ; Have we reached end of string?
    jnz .repeat                 ;     if not process next character
.end:
    ret

HelloWorldMsg:   db "Hello, world!", 0x0d, 0x0a, 0

times 446-($-$$) db 0   ; Pad with 0s up until first partition entry
part1_entry:
db 0x80                 ; 0x80 = Active boot partition, 0x00=inactive
db 0x00, 0x01, 0x00     ; CHS of first absolute sector (MBR) of hard drive
                        ;     Head=0, Sector=1, Cylinder=0
db 0x0c                 ; Partition type (has to be non-zero)
                        ;     0x0c = Win 95 FAT32 (LBA)
db 0x00, 0x01, 0x00     ; CHS of last absolute sector (MBR) of hard drive
                        ;     Head=0, Sector=1, Cylinder=0
                        ;     We are effectively saying Size of partition is 1 sector
dd 0x0                  ; LBA of first absolute sector (0=MBR)
dd 0x1                  ; Number of sectors in partition. We set it to 1 but if you
                        ;     wish you could set it to the number of sectors on the disk

times 510-($-$$) db 0   ; Pad remainder of boot sector up to boot signature. This zeroes
                        ;     partition entries 2,3,4 effectively making them inactive

dw 0xAA55               ; The standard PC boot signature after partition table

您可以使用以下方法构建 MBR:

nasm -f bin boot.asm -o boot.bin

如果成功放置在媒体上,此代码应打印:

Hello, world!