2.9 初始化进程0

来源:互联网 发布:量化程序员 招聘 编辑:程序博客网 时间:2024/06/05 20:22

2.9 初始化进程0

进程0是Linux操作系统中运行的第一个进程,也是Linux操作系统父子进程创建机制的第一个父进程。下面讲解的内容对进程0能够在主机中正常运算的影响最为重要和深远,主要包含如下三方面的内容。

1)系统先初始化进程0。进程0管理结构task_struct的母本(init_task = {INIT_TASK,})已经在代码设计阶段事先设计好了,但这并不代表进程0已经可用了,还要将进程0的task_struct中的LDT、TSS与GDT相挂接,并对GDT、task[64]以及与进程调度相关的寄存器进行初始化设置。

2)Linux 0.11作为一个现代操作系统,其最重要的标志就是能够支持多进程轮流执行,这要求进程具备参与多进程轮询的能力。系统这里对时钟中断进行设置,以便在进程0运行后,为进程0以及后续由它直接、间接创建出来的进程能够参与轮转奠定基础。

3)进程0要具备处理系统调用的能力。每个进程在运算时都可能需要与内核进行交互,而交互的端口就是系统调用程序。系统通过函数set_system_gate将system_call与IDT相挂接,这样进程0就具备了处理系统调用的能力了。这个system_call就是系统调用的总入口。

进程0只有具备了以上三种能力才能保证将来在主机中正常地运行,并将这些能力遗传给后续建立的进程。

这三点的实现都是在sched_init()函数中实现的,具体代码如下:

  1. //代码路径:init/main.c:  
  2. void main(void)  
  3. {  
  4.     …  
  5.     sched_init();  
  6.     …  
  7. }  
  8. //代码路径:kernel/sched.c:  
  9.     …  
  10. #define LATCH (1193180/HZ)  //每个时间片的振荡次数  
  11.     …  
  12. union task_union {   // task_struct与内核栈的共用体  
  13.     struct task_struct task;  
  14.     char stack[PAGE_SIZE]; // PAGE_SIZE是4 KB  
  15. };  
  16. static union task_union init_task= {INIT_TASK,};//进程0的task_struct  
  17.     …  
  18. //初始化进程槽task[NR_TASKS]的第一项为进程0,即task[0]为进程0占用  
  19. struct task_struct * task[NR_TASKS]= {&(init_task.task), };  
  20.     …  
  21.  
  22. void sched_init(void)  
  23. {  
  24.     int i;  
  25.     struct desc_struct * p;  
  26.  
  27.     if (sizeof(struct sigaction) != 16)  
  28.          panic("Struct sigaction MUST be 16 bytes");  
  29.     set_tss_desc(gdt?+?FIRST_TSS_ENTRY,&(init_task.task.tss));//设置TSS0  
  30.     set_ldt_desc(gdt?+?FIRST_LDT_ENTRY,&(init_task.task.ldt));//设置LDT0  
  31.     pgdt?+?2+FIRST_TSS_ENTRY; //从GDT的6项,即TSS1开始向上全部清零,并且将进程槽从   
  32.     for(i=1;i<NR_TASKS;i++) { //1往后的项清空。0项为进程0所用  
  33.          task[i]= NULL;  
  34.          p->a=p->b=0;  
  35.          p++;  
  36.          p->a=p->b=0;  
  37.          p++;  
  38.     }  
  39. /* Clear NT, so that we won't have troubles with that later on */  
  40.     __asm__("pushfl;andl $0xffffbfff,(%esp);popfl");  
  41.     ltr(0); //重要!将TSS挂接到TR寄存器  
  42.     lldt(0); //重要!将LDT挂接到LDTR寄存器  
  43.     outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 *///设置定时器  
  44.     outb_p(LATCH & 0xff , 0x40); /* LSB */ //每10毫秒一次时钟中断  
  45.     outb(LATCH >> 8 , 0x40); /* MSB */  
  46.     set_intr_gate(0x20,&timer_interrupt); //重要!设置时钟中断,进程调度的基础  
  47.     outb(inb_p(0x21)&~0x01,0x21);  //允许时钟中断  
  48.     set_system_gate(0x80,&system_call);  //重要!设置系统调用总入口  
  49. }  
  50.  
  51. //代码路径:include\linux\sched.h://   //嵌入汇编参看trap_init的注释  
  52.     …  
  53. #define FIRST_TSS_ENTRY 4 //参看图2-15中GDT的4项,即TSS0入口  
  54. #define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY?+?1)//同上,5项即LDT0入口  
  55. #define _TSS(n) ((((unsigned long) n)<<4)?+?(FIRST_TSS_ENTRY<<3))  
  56. #define _LDT(n) ((((unsigned long) n)<<4)?+?(FIRST_LDT_ENTRY<<3))  
  57. #define ltr(n) __asm__("ltr %%ax"::"a" (_TSS(n)))  
  58. #define lldt(n) __asm__("lldt %%ax"::"a" (_LDT(n)))  
  59.     …  
  60.  
  61. //代码路径:include\asm\system.h:  
  62.     …  
  63. #define set_intr_gate(n,addr) \  
  64.     _set_gate(&idt[n],14,0,addr)  
  65.  
  66. #define set_trap_gate(n,addr) \  
  67.     _set_gate(&idt[n],15,0,addr)  
  68.  
  69. #define set_system_gate(n,addr) \  
  70.     _set_gate(&idt[n],15,3,addr)  
  71.     …  
  72. #define _set_tssldt_desc(n,addr,type) \  //嵌入汇编参看trap_init的注释  
  73.  
  74. __asm__ ("movw $104,%1\n\t" \  //将104,即1101000存入描述符的第1、2字节  
  75.           "movw %%ax,%2\n\t" \ //将tss或ldt基地址的低16位存入描述符的第  
  76.  //3、4字节  
  77.           "rorl $16,%%eax\n\t" \  //循环右移16位,即高、低字互换  
  78.           "movb %%al,%3\n\t" \  //将互换完的第1字节,即地址的第3字节存入第5字节  
  79.           "movb $" type ",%4\n\t" \ //将0x89或0x82存入第6字节  
  80.           "movb $0x00,%5\n\t" \  //将0x00存入第7字节  
  81.           "movb %%ah,%6\n\t" \ //将互换完的第2字节,即地址的第4字节存入第8字节  
  82.           "rorl $16,%%eax" \ //复原eax   
  83.           ::"a" (addr), "m" (*(n)), "m" (*(n?+?2)), "m" (*(n?+?4)), \  
  84.           "m" (*(n?+?5)), "m" (*(n?+?6)), "m" (*(n?+?7)) \  
  85.          //"m" (*(n))是gdt第n项描述符的地址开始的内存单元  
  86.          //"m" (*(n?+?2)) 是gdt第n项描述符的地址向上第3字节开始的内存单元  
  87.          //其余依此类推  
  88.           )  
  89. //n:gdt的项值,addr:tss或ldt的地址,0x89对应tss,0x82对应ldt  
  90. #define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x89")  
  91. #define set_ldt_desc(n,addr) _set_tssldt_desc(((char *) (n)),addr,"0x82")  
  92.  
  93. //代码路径:include/linux/sched.h:  
  94.     …  
  95. struct tss_struct {  
  96.     long back_link; /* 16 high bits zero */  
  97.     long esp0;  
  98.     long ss0;  /* 16 high bits zero */  
  99.     long esp1;  
  100.     long ss1;  /* 16 high bits zero */  
  101.     long esp2;  
  102.     long ss2;  /* 16 high bits zero */  
  103.     long cr3;  
  104.     long eip;  
  105.     long eflags;  
  106.     long eax,ecx,edx,ebx;  
  107.     long esp;  
  108.     long ebp;  
  109.     long esi;  
  110.     long edi;  
  111.     long es;  /* 16 high bits zero */  
  112.     long cs;  /* 16 high bits zero */  
  113.     long ss;  /* 16 high bits zero */  
  114.     long ds;  /* 16 high bits zero */  
  115.     long fs;  /* 16 high bits zero */  
  116.     long gs;  /* 16 high bits zero */  
  117.     long ldt;  /* 16 high bits zero */  
  118.     long trace_bitmap; /* bits: trace 0, bitmap 16-31 */  
  119.     struct i387_struct i387;  
  120. };  
  121.  
  122. struct task_struct {  
  123. /* these are hardcoded - don't touch */  
  124.     long state; /* -1 unrunnable, 0 runnable, >0 stopped */  
  125.     long counter;  
  126.     long priority;  
  127.     long signal;  
  128.     struct sigaction sigaction[32];  
  129.     long blocked; /* bitmap of masked signals */  
  130. /* various fields */  
  131.     int exit_code;  
  132.     unsigned long start_code,end_code,end_data,brk,start_stack;  
  133.     long pid,father,pgrp,session,leader;  
  134.     unsigned short uid,euid,suid;  
  135.     unsigned short gid,egid,sgid;  
  136.     long alarm;  
  137.     long utime,stime,cutime,cstime,start_time;  
  138.     unsigned short used_math;  
  139. /* file system info */  
  140.     int tty;  /* -1 if no tty, so it must be signed */  
  141.     unsigned short umask;  
  142.     struct m_inode * pwd;  
  143.     struct m_inode * root;  
  144.     struct m_inode * executable;  
  145.     unsigned long close_on_exec;  
  146.     struct file * filp[NR_OPEN];  
  147. /* ldt for this task 0 - zero 1 - cs 2 - ds&ss */  
  148.     struct desc_struct ldt[3];  
  149. /* tss for this task */  
  150.     struct tss_struct tss;  
  151. };  
  152.  
  153. /*进程0的task_struct  
  154.  *  INIT_TASK is used to set up the first task table, touch at  
  155.  * your own risk!. Base=0limit=0x9ffff (=640kB)  
  156.  */  
  157. #define INIT_TASK \  
  158. /* state etc */ { 0,15,15, \ //就绪态,15个时间片  
  159. /* signals */ 0,{{},},0, \  
  160. /* ec,brk... */ 0,0,0,0,0,0, \  
  161. /* pid etc.. */ 0,-1,0,0,0, \ //进程号0  
  162. /* uid etc */ 0,0,0,0,0,0, \  
  163. /* alarm */ 0,0,0,0,0,0, \  
  164. /* math */ 0, \  
  165. /* fs info */ -1,0022,NULL,NULL,NULL,0, \  
  166. /* filp */ {NULL,}, \  
  167.     { \  
  168.          {0,0}, \  
  169. /* ldt */ {0x9f,0xc0fa00}, \  
  170.          {0x9f,0xc0f200}, \  
  171.     }, \  
  172. /*tss*/ {0,PAGE_SIZE?+?(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\  
  173.      0,0,0,0,0,0,0,0, \  //eflags的值,决定了cli这类指令只能在0特权级使用  
  174.      0,0,0x17,0x17,0x17,0x17,0x17,0x17, \  
  175.      _LDT(0),0x80000000, \  
  176.          {} \  
  177.     }, \  
  178. }  
0 0
原创粉丝点击