请注意,这些#defines并非选择符本身,而只是选择符中的INDEX域,因此它们正是全局描述符表中的索引。例如,内核代码的选择符(GCODE_SEL)的值为0x08。
下一步是初始化中断描述符表(Interrupt Descriptor Table, IDT)。
这张表在发生软件或硬件中断时会被处理器引用。例如,执行系统调用时,用户应用程序提交INT 0x80 指令。这是一个软件中断,处理器用索引值0x80在中断描述符表中查找记录。这个记录指向处理这个中断的例程。在这个特定情形中,这是内核的系统调用关口。
译者注: Intel 80386支持“调用门,可以使得用户程序只通过一条call指令就调用内核中的例程。可是FreeBSD并未采用这种机制,也许是因为使用软中断接口可免去动态链接的麻烦吧。
另外还有一个附带的好处:在仿真Linux时,当遇到FreeBSD内核不支持的而又并非关键性的系统调用时,内核只会显示一些出错信息,这使得程序能够继续运行;而不是在真正执行程序之前的初始化过程中就因为动态链接失败而不允许程序运行。中断描述符表最多可以有256 (0x100)条记录。内核分配NIDT条记录的内存给中断描述符表,这里NIDT=256,是最大值:sys/i386/i386/Machdep.c:
static struct gate_descriptor idt0[NIDT];
struct gate_descriptor *idt = &idt0[0]; /* 中断描述符表 */
每个中断都被设置一个合适的中断处理程序。系统调用关口INT 0x80也是如此:sys/i386/i386/machdep.c:
setidt(0x80, &IDTVEC(int0x80_syscall),
SDT_SYS386TGT, SEL_UPL, GSEL(GCODE_SEL, SEL_KPL));
所以当一个用户应用程序提交INT 0x80指令时,全系统的控制权会传递给函数_Xint0x80_syscall,这个函数在内核代码段中,将被以管理员权限执行。然后,控制台和DDB(调试器)被初始化:sys/i386/i386/machdep.c:
标签: