2

我们在基于 MCU 的定制硬件上开发了 USB 复合设备(CDC 和 MSD 类)。该磁盘是一个 RAM 磁盘(24 kb 空间),在通电时,它由 MCU 供应商固件格式化(FAT 12)。不幸的是,该设备被视为可引导磁盘,典型的 BIOS 会尝试引导它。但是,我们知道将不同的 USB 磁盘连接到不同的 PC 会产生不同的结果,这取决于磁盘的 FAT 类型和 BIOS 行为(显然每个 BIOS 在 HDD 之前都有 USB 启动)。我们的目标是拥有一个无法启动的U 盘(FAT12 格式)

我们尝试了许多解决方案,但没有一个奏效。在我们看来,BIOS 似乎不仅仅是检查有效引导扇区的存在,将第一个扇区复制到地址 0x7C00 并跳转到该地址,从而将控制权交给 x86 ASM 引导代码。事实上,我们已经用 Linux 格式化了一个商业 U 盘,命令如下:

mkdosfs -F 12 /dev/sda1

这个 USB 记忆棒现在有一个 FAT12 卷启动记录,我们还没有发现在尝试从它启动时卡住的 BIOS

因此,我们将其引导扇区复制到我们的设备中,并且我们希望它可以用作商业 USB 记忆棒。不:BIOS 在尝试引导磁盘时挂起。下面是上面Linux命令生成的引导扇区的反汇编。

;Jump instructions
0x00007c00 eb 3c                            jmp    0x00007c3e
0x00007c02 90                               nop

;VBR segment
0x00007c03 6d                               
0x00007c04 6b 66 73 2e                      
0x00007c08 66 61                              

..............

;Boot code
0x00007c3e 0e                               push   %cs
0x00007c3f 1f                               pop    %ds
0x00007c40 be 5b 7c                         mov    $0x7c5b,%si
0x00007c43 ac                               lods   %ds:(%si),%al
0x00007c44 22 c0                            and    %al,%al
0x00007c46 74 0b                            je     0x00007c53
0x00007c48 56                               push   %si
0x00007c49 b4 0e                            mov    $0xe,%ah
0x00007c4b bb 07 00                         mov    $0x7,%bx
0x00007c4e cd 10                            int    $0x10
0x00007c50 5e                               pop    %si
0x00007c51 eb f0                            jmp    0x00007c43
0x00007c53 32 e4                            xor    %ah,%ah
0x00007c55 cd 16                            int    $0x16
0x00007c57 cd 19                            int    $0x19
0x00007c59 eb fe                            jmp    0x00007c59

;String to be displayed followed by zeros

0x00007c5b 54                               
0x00007c5c 68 69 73                         

..........

;Boot signature
0x00007dfe 55                               
0x00007dff aa                               

显然,上面的代码打印出字符串“This is not a bootable disk. Please insert a bootable floppy and press any key to try again”,然后调用INT16H和INT19H。

例如,为什么我正在写入的 PC 的 BIOS 会打印:“尝试从 USB 磁盘启动”,然后跳转到我的硬盘,而我们设备中写入的相同汇编代码却没有?也就是说,它写“请插入...”?有一个代码可以替代它并且永远不会尝试启动我的自定义 USB 磁盘吗?

另外,在读取第一个扇区之前,BIOS 是否会与 USB 设备进行一些特殊的通信,例如,从设备描述符中获取一些信息,以便了解它是否可以用作启动盘?

谢谢大家。

4

2 回答 2

2

最终,可能没有任何东西可以阻止您的自定义 USB 设备在可能插入的任何 PC 上用作启动设备。但是,您可以做几件事来应对大多数情况,第一是在引导扇区末尾没有 0xAA55 签名,第二是调用引导扇区的 INT 0x18 以要求 BIOS 尝试下一个启动装置。

BIOS 如何引导 USB 设备

这里的基本问题是 USB 大容量存储设备的 BIOS 引导没有标准。BIOS 如何准确地确定 USB 设备是否可引导因 BIOS 实现而异。然而,所有实现都将遵循两个基本步骤。

首先是确定是否将 USB 设备模拟为“软盘”、“硬盘”、“cdrom”、“zip”或其他类型的驱动器。对于您的设备,它应该归结为在软盘或硬盘驱动器仿真之间进行选择。做出此选择的各种标准是可能的,例如驱动器的大小、其是否报告自己为可移动以及使用的命令集。特别是驱动软盘仿真可以支持的大小有一个上限,我相信大约 530MB,这个大小通常用于确定设备类型。某些 BIOS 还可以配置为在其设置中强制使用某种设备类型。

下一步是确定设备是否可启动。这意味着至少读取驱动器的第一个扇区,因为如果无法读取,则无法启动。然后 BIOS 可能会尝试确定引导扇区是否有效。如果它正在模拟硬盘驱动器,它应该始终检查是否存在 0xAA55 签名,但如果它正在模拟软盘,它可能会或可能不会执行此检查。如果它正在模拟硬盘驱动器,它可能还会检查有效的 MBR 样式分区,如果正在模拟软盘,它可能会检查有效的 FAT BIOS 参数块 (BPB)。

因此,在引导扇区末尾没有 0xAA55 幻数会阻止 USB 设备至少在某些情况下被用作引导设备。然而,BIOS 很可能会选择为您的设备使用软盘仿真,并且许多 BIOS 除了验证其可读性之外不会对引导扇区进行任何验证。但是,如果您可以让您的 USB 设备假装它比实际大得多,超出软盘仿真所支持的范围,那么它应该更有可能使用硬盘驱动器仿真。

调用 INT 0x18

但是,即使 BIOS 确实加载并执行设备的引导扇区,也不会丢失所有内容。您可以调用 INT 0x18,它最初用于在原始 IBM PC 上启动盒式 BASIC,但被 BIOS 引导规范重新定义为失败引导尝试的恢复向量。在现代 PC 上,包括任何支持启动 USB 设备的 PC,调用它会告诉 BIOS 尝试下一个启动设备。(自 MBR 发明以来,在标准 MBR 实现中的引导失败后实际上调用了 INT 0x18,因此它实际上并不像听起来那样不寻常。)

这是调用 INT 0x18 的引导扇区的源代码,我用于在可用的各种 PC 上进行测试:

    .code16

    .text

    jmp start
    nop
    .org    0x03    # insure a two byte long JMP insn was used

    .org    0x3e    # skip over FAT BIOS Parameter Block
start:
    xor %ax, %ax
    mov %ax, %ss
    mov $0x7c00, %sp

    call    print_message

    .ascii  "\r\nOOPS... The BIOS tried to boot the custom device.\r\n"
    .byte   0

    xor %ax, %ax
    int $0x16       # read from keyboard

    # Try using the BIOS Boot Specification's recovery vector so
    # that BIOS tries another boot device. On an a real 5150 IBM PC
    # this starts cassette BASIC.  On a PC that doesn't support the
    # BBS then it may print an error message, do nothing or crash.

    int $0x18

    call    print_message

    # INT 0x18 didn't work, didn't start BASIC and didn't crash.
    # Print an error message to user and invoke the INT 0x19
    # reboot vector.

    .ascii  "\r\nRemove the custom device and press any key to reboot"
    .ascii  " the computer.\r\n"
    .byte   0

    xor %ax, %ax
    int $0x16       # read from keyboard

    int $0x19       # reboot

infinite_loop:
    jmp infinite_loop

print_message:
    pop %si
loop_message:
    lods    %cs:(%si), %al
    test    %al,%al
    jz  end_message
    mov $0xe, %ah
    mov $0x7, %bx
    int $0x10       # print a character
    jmp loop_message
end_message:
    jmp *%si

    .org    0x1FF
    .byte   00      # note no 55 aa signature

您应该能够修改此代码以用于您的设备。确保从设备的 BPB 中复制 FAT12 BPB(偏移量 0x003 和 0x03e 之间的字节)。您可能希望删除 INT 0x16 的第一次调用,该调用在调用 INT 0x18 之前等待按键。要组装和链接代码,您可以使用以下命令:

as -o myfat12.o myfat12.s
ld --oformat=binary -o myfat12.bin -Ttext=0x7c00 myfat12.o

要将 BPB 从您的设备复制到使用上述命令创建的引导扇区中,您可以使用以下命令:

dd conv=notrunc if=/dev/sda of=myfat12.bin bs=1 skip=3 seek=3 count=59

在我的测试中,上面的代码运行良好,但在一种情况下,BIOS 只是一遍又一遍地尝试相同的引导设备。在另一种情况下,PC(一台 15 岁的 Pentium 4)在尝试从 USB 闪存驱动器启动代码时崩溃,但不是从实际的 USB 软盘启动代码。崩溃可能与我用来尽可能接近地复制您的设备的不寻常的 24k FAT12 BPB 有关。

第二个“删除自定义设备...”消息从未在我的测试中打印出来。引导块从一开始就没有被执行,或者调用 0x18 做了一些事情并且从未返回。如果 INT 0x18 没有任何帮助,您可能希望将这些说明移至第一条消息。

于 2017-09-19T19:20:00.140 回答
0

尝试调用 INT 18H,这是由 BIOS 引导规范(Compaq、Phoenix、Intel 1996)指定的以尝试下一个引导设备。

或者,它可能需要使用 INT 13H 自行加载下一个磁盘的引导扇区。

于 2017-09-18T08:00:16.857 回答