我们在基于MCU的定制硬件上开发了USB复合设备(CDC和MSD类)。磁盘是RAM磁盘(24kb空间),上电时,MCU供应商固件格式化(FAT 12)。不幸的是,该设备被视为可引导磁盘,典型的BIOS尝试引导它。但是,我们知道将各种USB磁盘连接到不同的PC会产生不同的结果,这取决于磁盘FAT类型和BIOS行为(显然每个BIOS都有先于USB的USB启动)。 我们的目标是拥有无法启动的 USB磁盘(FAT12格式化)。
我们尝试了很多解决方案,但都没有效果。 在我们看来,BIOS似乎不只是检查是否存在有效的引导扇区,将第一个扇区复制到地址0x7C00并跳转到该地址,从而控制x86 ASM引导代码。实际上,我们使用以下命令格式化了一个带有Linux的商用USB记忆棒:
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
显然,上面的代码打印字符串“这不是可引导的磁盘。请插入可引导的软盘并按任意键再试一次”,然后调用INT16H和INT19H。
为什么我正在编写的PC中的BIOS打印出来:“尝试从USB磁盘启动”然后跳转到我的硬盘驱动器,而在我们的设备中写入的相同汇编代码却没有?也就是说,它写道“请插入......”?有一个代码可以替代它,永远不会尝试启动我的自定义USB磁盘?
此外,在读取第一个扇区读取之前,BIOS是否与USB设备进行了一些特殊通信,例如,设备描述符中的某些内容是为了了解它是否可以用作启动盘?
提前谢谢大家。
答案 0 :(得分:1)
最终,可能无法阻止您的自定义USB设备在其可能插入的任何PC上用作启动设备。但是,你可以做的事情应该涵盖大多数情况,第一个是在引导扇区结束时没有0xAA55签名,第二个是调用INT 0x18引导扇区,要求BIOS尝试下一个启动装置。
这里的基本问题是USB大容量存储设备的BIOS启动没有标准。在BIOS实现之间,确定USB设备是否可启动的确切程度如何。然而,所有实现都将遵循两个基本步骤。
首先是确定是否将USB设备模拟为"软盘","硬盘"," cdrom"," zip&# 34;或其他类型的驱动器。对于您的设备,它应该归结为在软盘或硬盘驱动器仿真之间进行选择。可以使用各种标准来进行此选择,例如驱动器的大小,是否可以将其自身报告为可移动的以及使用的命令集。特别是驱动器软盘仿真可以支持的大小的上限,我相信大约530MB,并且这个大小通常用于确定设备类型。某些BIOS也可以配置为在其设置中强制使用某种设备类型。
下一步是确定设备是否可引导。这意味着至少读取驱动器的第一个扇区,因为如果无法读取它,则无法启动它。然后BIOS可以尝试确定引导扇区是否有效。如果它正在模拟硬盘驱动器,则应始终检查是否存在0xAA55签名,但如果它正在模拟软盘,它可能会也可能不会执行此检查。如果它正在模拟硬盘驱动器,它也可能会检查有效的MBR样式分区,如果要模拟软盘,它可能会检查有效的FAT BIOS参数块(BPB)。
因此,在引导扇区末尾没有0xAA55幻数会阻止USB设备至少在某些情况下被用作引导设备。但是,最有可能的是BIOS会选择对您的设备使用软盘仿真,并且许多BIOS除了验证它的可读性外,还不会对引导扇区进行任何验证。但是,如果你的USB设备假装它比实际大得多,超出了软盘仿真所支持的范围,那么它应该更有可能使用硬盘仿真。
但是,即使BIOS确实加载并执行了设备的引导扇区,所有内容也不会丢失。您可以调用INT 0x18,它最初用于在原始IBM PC上启动盒式磁带BASIC,但由BIOS Boot Specification重新定义为失败启动尝试的恢复向量。在现代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没有做任何有用的事情,您可能希望将这些指令移动到第一条消息。
答案 1 :(得分:0)
尝试调用INT 18H,这是由BIOS Boot Specification(Compaq,Phoenix,Intel 1996)指定的,以尝试下一个启动设备。
或者,可能需要使用INT 13H自行加载下一个磁盘的引导扇区。