mov $SEL_SCODE,%dh # 段选择符
init.2: shr %bx # 是否处理这个中断?
jnc init.3 # 否
mov %ax,(%di) # 设置处理程序偏移量
mov %dh,0x2(%di) # 设置处理程序选择符
mov %dl,0x5(%di) # 设置 P:DPL:type
add $0x4,%ax # 下一个中断处理程序
所以,当客户调用 __exec()时,代码将被以最高权限执行。这使得内核可以修改保护模式数据结构,如分页表(page tables)、全局描述符表(GDT)、中断描述符表(IDT)等。
boot2 定义了一个重要的数据结构:struct bootinfo。这个结构由 boot2 初始化,然后被转送到loader,之后又被转入内核。这个结构的部分项目由boot2设定,其余的由loader设定。这个结构中的信息包括内核文件名、BIOS提供的硬盘柱面/磁头/扇区数目信息、BIOS提供的引导设备的驱动器编号,可用的物理内存大小,envp指针(环境指针)等。定义如下:
/usr/include/Machine/bootinfo.h
struct bootinfo {
u_int32_t bi_version;
u_int32_t bi_kernelname; /* 用一个字节表示 * */
u_int32_t bi_nfs_diskless; /* struct nfs_diskless * */
/* 以上为常备项 */
#define bi_endcommon bi_n_bios_used
u_int32_t bi_n_bios_used;
u_int32_t bi_bios_geom[N_BIOS_GEOM];
u_int32_t bi_size;
u_int8_t bi_memsizes_valid;
u_int8_t bi_bios_dev; /* 引导设备的BIOS单元编号 */
u_int8_t bi_pad[2];
u_int32_t bi_basemem;
u_int32_t bi_extmem;
u_int32_t bi_symtab; /* struct symtab * */
u_int32_t bi_esymtab; /* struct symtab * */
/* 以下项目仅高级bootloader提供 */
u_int32_t bi_kernend; /* 内核空间末端 */
u_int32_t bi_envp; /* 环境 */
u_int32_t bi_modulep; /* 预装载的模块 */
};
boot2 进入一个循环等待用户输入,然后调用load()。如果用户不做任何输入,循环将在一段时间后结束,load() 将会装载缺省文件(/boot/loader)。函数 ino_t lookup(char *filename)和int xfsread(ino_t inode, void *buf, size_t nbyte) 用来将文件内容读入内存。/boot/loader是一个ELF格式二进制文件,不过它的头部被换成了a.out格式中的struct exec结构。load()扫描loader的ELF头部,装载/boot/loader至内存,然后跳转至入口执行之:
sys/boot/i386/boot2/boot2.c:
__exec((CADdr_t)addr, RB_BOOTINFO | (opts & RBX_MASK),
MAKEBOOTDEV(dev_maj[dsk.type], 0, dsk.slice, dsk.unit, dsk.part),
0, 0, 0, VTOP(&bootinfo));
标签: