zoukankan      html  css  js  c++  java
  • 第六章

    原文:http://www.cnblogs.com/wanghj-dz/archive/2011/05/20/2051641.html

    进程的进程表、进程体、GDT、TSS的关系,以及进程表的初始化

    关系见P252,图6-9

    进程表与GDT的关系:

    进程表里的LDT Selector对应GDT中的一个描述符,而这个描述符所指向的内存空间就存在与进程表内。

    进程表与进程体的关系:

    进程表是进程的描述,进程运行过程中如果被中断,各个寄存器的值都会被保存进进程表中。使用到进程表堆栈。

    但是,在我们的第一个进程开始前并不需要初始化太多内容,只需知道进程的入口地址就足够了。同时需要设置esp,指向进程表。

    GDT与TSS的关系:

    GDT中需要有一个描述符来对应TSS,需要事先初始化这个描述符。

    ------------------------------------------------------------

    进程结构体,结构体PROCESS   proc.h

    typedef  struct s_proc{

       STACK_FRAME    regs;                //寄存器

       t_16                  ldt_ sel ;           //LDT选择子

       DESCRIPTOR      ldts[LDT_SIZE]  //LDTs

       t_32                   pid                   //进程号

       char                    P_name[16]     //名字

    }PROCESS;

    ----------------------------------------------------------

    进程结构体有了,下面我们在global.c中声明一个进程表

    PUBLIC PROCESS   proc_table[NR_TASKS]

    好了,进程表有了下面我们来初始化它。当NR_TASKS=1时,就相当于定义了一个proc_table.

    ----------------------------------------------------------

    进程表初始化:main.c

    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));
    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));
    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;

    //cs指向LDT中的第一个描述符 (3) 通过cs中的这个描述符跳转到内核代码段
    p_proc->regs.ds  = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    p_proc->regs.es  = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    p_proc->regs.fs  = ((8 * 1) & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
    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))

    LDT基址指向proc_table[0].ldts ,LDT基址下面就是选择子,所以LDT的选择子在proc_table[0].ldts中。LDT选择子的初始化在main.c中。

    -------------------------------------------------------------------------------------------------

    GDT与TSS 

    会发现没有初始化的只有TSS了,在protect.c中的init_Prot()中初始化TSS以及对应的描述符。

    memset(&tss, 0, sizeof(tss));
     tss.ss0  = SELECTOR_KERNEL_DS;
     init_descriptor(&gdt[INDEX_TSS],
       vir2phys(seg2phys(SELECTOR_KERNEL_DS), &tss),
       sizeof(tss) - 1,
       DA_386TSS);
     tss.iobase = sizeof(tss); /* 没有I/O许可位图 */

    ————————————————————————————————————————————————————

    笔者见解:

  • 相关阅读:
    HomeBrew安装MongoDB如何启动
    Express + Mongoose 极简入门
    Express + Mongoose 极简入门
    浅谈 PHP 与手机 APP 开发(API 接口开发)
    浅谈 PHP 与手机 APP 开发(API 接口开发)
    统计与分布之伯努利分布与二项分布
    统计分布之泊松分布
    统计与分布之高斯分布
    Python 2 和 3 的区别及兼容技巧
    组合与排列
  • 原文地址:https://www.cnblogs.com/shenlian/p/2055657.html
Copyright © 2011-2022 走看看