hz = HZ;
TUNABLE_INT_FETCH("kern.hz", &hz);
TUNABLE__FETCH用来获取环境变量的值:/usr/src/sys/sys/kernel.h
#define TUNABLE_INT_FETCH(path, var) getenv_int((path), (var))
Sysctlkern.hz是系统时钟频率。同时,这些sysctl项被init_param1()设定:
kern.maxswzone, kern.maxbcache, kern.maxtsiz, kern.dfldsiz, kern.dflssiz,
kern.maxssiz, kern.sgrowsiz。然后init386() 准备全局描述符表(Global Descriptors Table, GDT)。
在x86上每个任务都运行在自己的虚拟地址空间里,这个空间由"段址:偏移量"的数对指定。
举个例子,当前将要由处理器执行的指令在 CS:EIP,那么这条指令的线性虚拟地址就是“代码段虚拟段地址CS + EIP。为了简便,段起始于虚拟地址0,终止于界限4G字节。所以,在这个例子中,指令的线性虚拟地址正是EIP的值。段寄存器,如CS、DS等是选择符,即全局描述符表中的索引(更精确的说,索引并非选择符的全部,而是选择符中的INDEX部分)。译者注: 对于80386,选择符有16位,INDEX部分是其中的高13位。
FreeBSD的全局描述符表为每个CPU保存着15个选择符:sys/i386/i386/Machdep.c:
union descriptor gdt[NGDT * MAXCPU]; /* 全局描述符表 */
sys/i386/include/segments.h:
/*
* 全局描述符表(GDT)中的入口
*/
#define GNULL_SEL 0 /* 空描述符 */
#define GCODE_SEL 1 /* 内核代码描述符 */
#define GDATA_SEL 2 /* 内核数据描述符 */
#define GPRIV_SEL 3 /* 对称多处理(SMP)每处理器专有数据 */
#define GPROC0_SEL 4 /* Task state process slot zero and up, 任务状态进程 */
#define GLDT_SEL 5 /* 每个进程的局部描述符表 */
#define GUSERLDT_SEL 6 /* 用户自定义的局部描述符表 */
#define GTGATE_SEL 7 /* 进程任务切换关口 */
#define GBIOSLOWMEM_SEL 8 /* BIOS低端内存访问(必须是这第8个入口) */
#define GPANIC_SEL 9 /* 会导致全系统异常中止工作的任务状态 */
#define GBIOSCODE32_SEL 10 /* BIOS接口(32位代码) */
#define GBIOSCODE16_SEL 11 /* BIOS接口(16位代码) */
#define GBIOSDATA_SEL 12 /* BIOS接口(数据) */
#define GBIOSUTIL_SEL 13 /* BIOS接口(工具) */
#define GBIOSARGS_SEL 14 /* BIOS接口(自变量,参数) */
标签: