// 把在监控程序中建立的临时全局描述符表直接拷贝到内核中建立的正式的描述符表中,
// 因为监控程序和内核是在同一个代码段内,其实这里的minix 内核是看成一个进程处理
// 的, MINIX2.0 内核包括驱动程序在内,主要是为了访问的方便,因为一个进程内的函
// 数是可以随便访问这个进程内的数据的,同样同一个代码段内的更是一样,这样我们就
// 不用再在这里重新填充同一个段内的全局描述符表,而直接拷贝过来就可以了。当然还
// 是不能完全使用,之后还要在 cstart 中调用函数 Prot_init() 重新升级这个表,填
// 入更具体更详细的表项。
// 有关保护模式的内容我们就不再介绍,具体内容请参考文献 [ ] 。
06073 ! Copy the monitor global descriptor table to the address space of
06074 ! kernel and switch over to it. Prot_init() can then update it with
06075 ! immediate effect.
06076 sgdt (_gdt+GDT_SELECTOR) ! get the monitor gdtr
// 获得 monitor 程序使用全局描述符表寄存器的值,将其保存到操作系统使用的全局描述
// 符表 gdt[] 的第一项中,也就是全局描述符表的地址和权限信息。 GDT_SELECTOR 为全
// 局描述符表 gdt[] 的选择符。
06077 mov esi, (_gdt+GDT_SELECTOR+2) ! absolute address of GDT
// 获得 gdt[] 表的绝对地址
06078 mov ebx, _gdt ! address of kernel GDT
// gdt[] 表的地址
06079 mov ecx, 8*8 ! copying eight descriptors
06080 copygdt: // 一个描述符表项 8 个字节,共 8 个表项,总共 64 个字节
06081 eseg movb al, (esi)
06082 movb (ebx), al
06083 inc esi
06084 inc ebx
06085 loop copygdt
06086 mov eax, (_gdt+DS_SELECTOR+2) ! base of kernel data
// 内核数据段基地址
06087 and eax, 0x00FFFFFF ! only 24 bits
// 内核数据段空间最大为 4 M
06088 add eax, _gdt ! eax = vir2phys(gdt)
// 把 gdt[] 表的基地址从虚拟地址转换成物理地址,前面 gdt[] 内存储的地址为数据段
// 空间内的虚拟地址,也就是以此空间开始处为零所得到的地址,这样我们把它加上gdt[]
// 的物理地址,就得到了内核数据段的物理地址。
06089 mov (_gdt+GDT_SELECTOR+2), eax ! set base of GDT
// 我们知道全局描述符表的第一项中存储的就是全局描述符表的物理地址,访问权限等其
// 他属性信息,这样我们就可以在全局描述符表的第一项中重新设置 gdt[] 的基地址。
06090 lgdt (_gdt+GDT_SELECTOR) ! switch over to kernel GDT
06091
// lgdt是保护模式下专门用来加载全局描述符表到全局描述符表寄存器的指令。这里因为
// 已经处于保护模式,所以全局描述符表还是使用在监控程序下的样子,只不过是地址变
// 了而已,是操作系统自己定义的全局描述符表:gdt[] 。下面的代码设置了启动所使用
// 的参数和内核段所使用的段寄存器,这里使用的栈段是 06486 k_stktop:,为内核栈
// 段。
4
http://www.paper.edu.cn