JOS Bootloader无MBR签名仍可加载的机制及MBR签名意义问询
关于JOS Bootloader无MBR签名仍可加载的技术解答
背景
我跟随麻省理工学院(MIT)的操作系统课程学习操作系统开发时发现:osdev wiki等多数教程中的Bootloader代码末尾都会使用Master Boot Record (MBR)签名(0xAA55),但JOS代码仓库中的Bootloader代码(boot/boot.S)并未使用该签名,却仍能被正常加载。以下是JOS Bootloader的核心代码片段:
#include <inc/mmu.h> # Start the CPU: switch to 32-bit protected mode, jump into C. # The BIOS loads this code from the first sector of the hard disk into # memory at physical address 0x7c00 and starts executing in real mode # with %cs=0 %ip=7c00. .set PROT_MODE_CSEG, 0x8 # kernel code segment selector .set PROT_MODE_DSEG, 0x10 # kernel data segment selector .set CR0_PE_ON, 0x1 # protected mode enable flag .globl start start: .code16 # Assemble for 16-bit mode cli # Disable interrupts cld # String operations increment # Set up the important data segment registers (DS, ES, SS). xorw %ax,%ax # Segment number zero movw %ax,%ds # -> Data Segment movw %ax,%es # -> Extra Segment movw %ax,%ss # -> Stack Segment # Enable A20: # For backwards compatibility with the earliest PCs, physical # address line 20 is tied low, so that addresses higher than # 1MB wrap around to zero by default. This code undoes this. seta20.1: inb $0x64,%al # Wait for not busy testb $0x2,%al jnz seta20.1 movb $0xd1,%al # 0xd1 -> port 0x64 outb %al,$0x64 seta20.2: inb $0x64,%al # Wait for not busy testb $0x2,%al jnz seta20.2 movb $0xdf,%al # 0xdf -> port 0x60 outb %al,$0x60 # Switch from real to protected mode, using a bootstrap GDT # and segment translation that makes virtual addresses # identical to their physical addresses, so that the # effective memory map does not change during the switch. lgdt gdtdesc movl %cr0, %eax orl $CR0_PE_ON, %eax movl %eax, %cr0 # Jump to next instruction, but in 32-bit code segment. # Switches processor into 32-bit mode. ljmp $PROT_MODE_CSEG, $protcseg .code32 # Assemble for 32-bit mode protcseg: # Set up the protected-mode data segment registers movw $PROT_MODE_DSEG, %ax # Our data segment selector movw %ax, %ds # -> DS: Data Segment movw %ax, %es # -> ES: Extra Segment movw %ax, %fs # -> FS movw %ax, %gs # -> GS movw %ax, %ss # -> SS: Stack Segment # Set up the stack pointer and call into C. movl $start, %esp call bootmain # If bootmain returns (it shouldn't), loop. spin: jmp spin # Bootstrap GDT .p2align 2 # force 4 byte alignment gdt: SEG_NULL # null seg SEG(STA_X|STA_R, 0x0, 0xffffffff) # code seg SEG(STA_W, 0x0, 0xffffffff) # data seg gdtdesc: .word 0x17 # sizeof(gdt) - 1 .long gdt # address gdt
针对上述现象,以下是两个核心问题的解答:
1. BIOS如何识别并加载未带有MBR签名的Bootloader代码?
BIOS的启动校验逻辑并非在所有场景下都严格执行MBR签名检查:
- 虚拟机环境的宽松处理:JOS实验常用的QEMU、Bochs等虚拟机BIOS,为了方便开发调试,默认跳过了MBR签名的校验步骤——只要磁盘第一个扇区(LBA 0)有512字节的数据,就直接加载到物理地址0x7c00并移交控制权。
- 现代物理BIOS的兼容模式:很多物理机BIOS在处理本地硬盘启动时,也会放宽校验:即使没有0xAA55签名,只要第一个扇区的代码是可执行的,就会尝试运行。只有在处理可移动介质(如U盘、光盘)时,才会严格校验签名。
- 二进制文件的填充特性:JOS的boot.S编译链接后,生成的二进制文件刚好填满512字节(未使用的字节会被链接器填充为0或随机值),BIOS加载时直接读取完整的512字节,并不会因为末尾没有签名就拒绝执行。
2. 在BIOS启动的场景下,MBR签名的核心意义是什么?
MBR签名(0xAA55)是PC启动规范中定义的合法性校验标记,核心作用有两个:
- 区分有效引导程序与无效数据:早期PC磁盘的第一个扇区(MBR)包含引导代码(前446字节)和分区表(后64字节),最后两个字节的签名是BIOS判断该扇区是否为合法引导程序的依据。如果没有该签名,BIOS会认为这是无效的磁盘数据,转而尝试其他启动介质,或抛出“Missing operating system”类错误。
- 避免异常执行:防止BIOS误加载空磁盘、损坏的分区表或其他非引导数据到内存执行,避免系统出现崩溃、死机等异常情况。
内容的提问来源于stack exchange,提问作者user15980977
相关产品推荐
相关产品推荐

