公告

Gentoo交流群:87709706 欢迎您的加入

#1 2022-12-29 22:23:17

batsom
管理团队
注册时间: 2022-08-03
帖子: 429
个人网站

进程表的定义与初始化

PROCESS* p_proc=proc_table;

    p_proc--->ldt_sel=SELECTOR_LDT_FIRST;                                             

    //设置进程表中进程的ldt_sel,ldt_sel被赋值SELECTOR_LDT_FIRST,这个宏的定义在代码6-1-中

    memcpy(&p_proc->ldts[0], &gdt[SELECTOR_KERNEL_CS >> 3], sizeof(DESCRIPTOR));  //将SELECTOR_KERNEL_CS所指的描述符拷贝到进程PCB的ldts[0]处
    p_proc->ldts[0].attr1 = DA_C | PRIVILEGE_TASK << 5;                              // change the DPL
    memcpy(&p_proc->ldts[1], &gdt[SELECTOR_KERNEL_DS >> 3], sizeof(DESCRIPTOR)); //将SELECTOR_KERNEL_DS所指的描述符拷贝到进程PCB的ldts[1]处
    p_proc->ldts[1].attr1 = DA_DRW | PRIVILEGE_TASK << 5;                          // change the DPL

    //LDT中共有两个描述符,分别被初始化为内核代码段和内核数据段,只是改变了一下DPL,以让其运行在低特权级下(2)
    p_proc->regs.cs  = ((8 * 0) & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;    //8*0和8*1是选择子,而且是进程PCB中的LDT描述符的选择子。
//cs指向LDT中的第一个描述符 (3) 通过cs中的这个描述符跳转到内核代码段
//LDT选择子是从0开始的。一个描述符相隔8个字节,所以要乘以8
    p_proc->regs.ds  = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;    //根据选择子的属性确定是全局选择子还是LDT选择子。
    p_proc->regs.es  = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;    //本例会根据cs中的选择子自动到进程PCB中读取LDT描述符
    p_proc->regs.fs  = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;    //本例比较特殊的地方是进程LDT描述符在进程PCB中,没有固定的LDT段
    p_proc->regs.ss  = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;

    //ds,es,fs,ss指向LDT中的第二个描述符
    p_proc->regs.gs  = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | RPL_TASK;

    //gs指向显存,只是其RPL发生改变
    p_proc->regs.eip = (u32)TestA;

    //eip指向TestA,这表明进程将从TestA的入口地址开始运行
    p_proc->regs.esp = (u32) task_stack + STACK_SIZE_TOTAL;

    //esp指向单独的堆栈,堆栈大小为STACK_SIZE_TOTAL
    p_proc->regs.eflags = 0x1202; // IF=1, IOPL=1, bit 2 is always 1.

    //eflags=0x1202,恰巧设置了IF位,并把IOPL设为1,这样,进程就可以使用I/O指令,并且中断会在iretd执行时,被打开。

    //代码中使用到的宏,基本在protect.h中

    p_proc_ready = proc_table;




这里要记得把LDT跟GDT是联系在一起的,别忘了填充GDT中进程的LDT的描述符。protect.c

init_descriptor(

   &gdt[INDEX_LDT_FIRST],                                                           //设置填充地址位置(GDT中的LDT描述符 )
   vir2phys(seg2phys(SELECTOR_KERNEL_DS),  proc_table[0].ldts),  //LDT基址,这个GDT中的LDT基址指向proc_table[0].ldts       (1)
   LDT_SIZE * sizeof(DESCRIPTOR) - 1,                                           //LDT大小

   DA_LDT);                                                                                   //LDT属性

   seg2phys(SELECTOR_KERNEL_DS)把段地址转换为物理地址,把DS右移几位。

   vir2phys为宏定义,在protect.h中

   #define vir2phys(seg_base, vir)      (u32)(((u32)seg_base) + (u32)(vir))

离线

页脚