FreeBSD操作系统的boot2阶段

也许你想知道,为什么boot2是在boot0之后,而不是在boot1之后 。事实上,也有一个512字节的文件boot1存放在目录/boot里,那是用来从一张软盘引导系统的 。从软盘引导时,boot1起着boot0对硬盘引导相同的作用:它找到boot2并运行之 。
你可能已经看到有一文件/boot/mbr 。这是boot0的简化版本 。mbr中的代码不会显示菜单让用户选择,而只是简单的引导被标志的分区 。
实现boot2的代码存放在目录sys/boot/i386/boot2/里,对应的可执行文件在/boot里 。在/boot里的文件boot0和boot2不会在引导过程中使用,只有boot0cfg这样的工具才会使用它们 。boot0的内容应在MBR中才能生效 。boot2位于可引导的FreeBSD分区的开始 。这些位置不受文件系统控制,所以它们不可用ls之类的命令查看 。
boot2的主要任务是装载文件/boot/loader,那是引导过程的第三阶段 。在boot2中的代码不能使用诸如open()和read()之类的例程函数,因为内核还没有被加载 。而应当扫描硬盘,读取文件系统结构,找到文件/boot/loader,用BIOS的功能将它读入内存,然后从其入口点开始执行之 。
除此之外,boot2还可提示用户进行选择,loader可以从其它磁盘、系统单元、分区装载 。
boot2 的二进制代码用特殊的方式产生:
sys/boot/i386/boot2/Makefile
boot2: boot2.ldr boot2.bin ${BTX}/btx/btx
btxld -v -E ${ORG2} -f bin -b ${BTX}/btx/btx -l boot2.ldr
-o boot2.ld -P 1 boot2.bin这个Makefile片断表明btxld(8)被用来链接二进制代码 。BTX表示引导扩展器(BooT eXtender)是给程序(称为客户(clIEnt))提供保护模式环境、并与客户程序相链接的一段代码 。所以boot2是一个BTX客户,使用BTX提供的服务 。
工具btxld是链接器,它将两个二进制代码链接在一起 。btxld(8)和ld(1)的区别是ld通常将两个目标文件链接成一个动态链接库或可执行文件,而btxld则将一个目标文件与BTX链接起来,产生适合于放在分区首部的二进制代码,以实现系统引导 。
boot0执行跳转至BTX的入口点 。然后,BTX将处理器切换至保护模式,并准备一个简单的环境,然后调用客户 。这个环境包括:
虚拟8086模式 。这意味着BTX是虚拟8086的监视程序 。实模式指令,如pushf, popf, cli, sti, if,均可被客户调用 。
建立中断描述符表(Interrupt Descriptor Table, IDT),使得所有的硬件中断可被缺省的BIOS程序处理 。建立中断0x30,这是系统调用关口 。
两个系统调用exec和 exit的定义如下:
sys/boot/i386/btx/lib/btxsys.s:
.set INT_SYS,0x30# 中断号
#
# System call: exit
#
__exit: xorl 陎,陎 # BTX系统调用0x0
int $INT_SYS#
#
# System call: exec
#
__exec: movl $0x1,陎 # BTX系统调用0x1
int $INT_SYS#
BTX建立全局描述符表(Global Descriptor Table, GDT):
sys/boot/i386/btx/btx/btx.s:
gdt:.Word 0x0,0x0,0x0,0x0# 以空为入口
.word 0xffff,0x0,0x9a00,0xcf# SEL_SCODE
.word 0xffff,0x0,0x9200,0xcf# SEL_SDATA
.word 0xffff,0x0,0x9a00,0x0 # SEL_RCODE
.word 0xffff,0x0,0x9200,0x0 # SEL_RDATA
.word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
.word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
.word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS客户的代码和数据始于地址MEM_USR(0xa000),选择符(selector) SEL_UCODE指向客户的数据段 。选择符 SEL_UCODE 拥有第3级描述符权限(Descriptor Privilege Level, DPL),这是最低级权限 。但是INT 0x30 指令的处理程序存储于另一个段里,这个段的选择符SEL_SCODE (supervisor code)由有着管理级权限 。正如代码建立IDT(中断描述符表)时进行的操作那样:
mov $SEL_SCODE,%dh # 段选择符
init.2: shr %bx # 是否处理这个中断?
jnc init.3 # 否

推荐阅读