有关于mm/pmm.c中GDT表的建立
匿名2023/07/31 19:52:03提问
    特权级lab1student
332

在Lab1的实验中需要了解GDT表的建立,于是我在mm/pmm.c文件中找到了如下的定义:

/* *
 * Global Descriptor Table:
 *
 * The kernel and user segments are identical (except for the DPL). To load
 * the %ss register, the CPL must equal the DPL. Thus, we must duplicate the
 * segments for the user and the kernel. Defined as follows:
 *   - 0x0 :  unused (always faults -- for trapping NULL far pointers)
 *   - 0x8 :  kernel code segment
 *   - 0x10:  kernel data segment
 *   - 0x18:  user code segment
 *   - 0x20:  user data segment
 *   - 0x28:  defined for tss, initialized in gdt_init
 * */
static struct segdesc gdt[] = {
    SEG_NULL,
    [SEG_KTEXT] = SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_KERNEL),
    [SEG_KDATA] = SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_KERNEL),
    [SEG_UTEXT] = SEG(STA_X | STA_R, 0x0, 0xFFFFFFFF, DPL_USER),
    [SEG_UDATA] = SEG(STA_W, 0x0, 0xFFFFFFFF, DPL_USER),
    [SEG_TSS]    = SEG_NULL,
};

老师在课堂和MOOC中均提到,uCore将x86提供的段机制看作是直接映射,在页机制未启用的前提下,达到了逻辑地址=线性地址=物理地址的效果。观察上面的代码,除了第一个SEG_NULL是硬件需要之外,其他的五个SEG有四个都将地址映射到了0x00000000-0xFFFFFFFF,也就是说:当访存的逻辑地址唯一确定的时候,对应的线性地址就确定了,而对该逻辑地址的权限则由CS或是DS等寄存器决定,因此也可以通过观察CS的值确定当前到底是用户态还是内核态。

那么为什么还需要这6个段呢?在课下与陈老师的讨论中,得知这样做的目的是权限控制

举个例子,当CS为用户态时,如果试图执行某些特权指令或是内核态中断,就会触发x86的13号一般保护异常(  http://ilinuxkernel.com/?p=1388 )。 在lab1的challenge实验中,建立IDT表的时候,需要把T_SWITCH_TOK特权级别设置为DPL_USER,这样一来,在用户态执行lab1_switch_to_kernel的int指令时,就不会触发一般保护异常了。

至于SEG_NULL和SEG_TSS,前者应该是x86硬件需求,后者是之后的lab中会用到的用户用户态和内核态栈切换存储寄存器的临时区域,是动态建立的。

但其实写到这里,我还是有一个不太理解的地方,那就是既然之后会有页机制来进行权限控制,为什么还要在这里重复进行检查呢,这一步是多余的吗(即段表只设置NULL和KERNEL可以吗)?

希望同学一起讨论一下,如果我有新的理解再更新。

回答(1
    推荐问答
      Simple Empty
      暂无数据