1.进程0的创建
1.1 构造进程0的ldt与tss --> 在include/linux/sched.h中
-
152 /*
-
153 * INIT_TASK is used to set up the first task table, touch at
-
154 * your own Base=0, limit=0x9ffff (=640kB)
-
155 */
-
156 #define INIT_TASK
-
157 /* state etc */ { 0,15,15,
-
158 /* signals */ 0,{{},},0,
-
159 /* ec,brk... */ 0,0,0,0,0,0,
-
160 /* pid etc.. */ 0,0,0,0,
-
161 /* suppl grps*/ {NOGROUP,},
-
162 /* proc links*/ &init_task.task,0,0,0,
-
163 /* uid etc */ 0,0,0,0,0,0,
-
164 /* timeout */ 0,0,0,0,0,0,0,
-
165 /* rlimits */ { {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff},
-
166 {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff},
-
167 {0x7fffffff, 0x7fffffff}, {0x7fffffff, 0x7fffffff}},
-
168 /* flags */ 0,
-
169 /* math */ 0,
-
170 /* fs info */ -1,0022,NULL,NULL,NULL,NULL,0,
-
171 /* filp */ {NULL,},
-
172 { -->ldt
-
173 {0,0}, -->selector=0x07
-
174 {0x9f,0xc0fa00}, -->selector=0x0F,进程0的代码段,[0-640K],DPL=3,TYPE=0x0a,(0x9F+1)*4096/1024=(636+4)K
-
175 {0x9f,0xc0f200}, -->selector=0x17,进程0的数据段,[0-640K],DPL=3,TYPE=0x02
-
176 },
-
177 {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir, --> tss
-
178 0,0,0,0,0,0,0,0,
-
179 0,0,0x17,0x17,0x17,0x17,0x17,0x17,
-
180 _LDT(0),0x80000000, -->gtd[5]是进程0的ldt
-
181 {}
-
182 },
-
183 }
上图出自《Linux内核完全注释V3.0.pdf》P122
1.2 把上面的数组放进数组中 --> 在kernel/sched.c中
-
67 static union task_union init_task = {INIT_TASK,}
1.3 挂接进程0的tss与ldt -->在kernel/sched.c中
-
418 void sched_init(void)
-
419 {
-
420 int i;
-
421 struct desc_struct * p;
-
422
-
423 if (sizeof(struct sigaction) != 16)
-
424 panic("Struct sigaction MUST be 16 bytes");
-
425 set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss)); -->将进程0的tss与gdt[4]连接
-
426 set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt)); -->将进程0的ldt与gdt[5]连接
-
427 p = gdt+2+FIRST_TSS_ENTRY;
-
428 for(i=1;i<NR_TASKS;i++) {
-
429 task[i] = NULL;
-
430 p->a=p->b=0;
-
431 p++;
-
432 p->a=p->b=0;
-
433 p++;
-
434 }
-
435 /* Clear NT, so that we won't have troubles with that later on */
-
436 __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); -->保证iret切换任务时EFLAGE的N位必须为1
-
437 ltr(0); -->加载tr,注意这儿lldt与ltr都是加载selector
-
438 lldt(0); -->加载ldt,然后根据selector找到相应的内容去加载真正的地址
-
439 outb_p(0x36,0x43); /* binary, mode 3, LSB/MSB, ch 0 */
-
440 outb_p(LATCH & 0xff , 0x40); /* LSB */
-
441 outb(LATCH >> 8 , 0x40); /* MSB */
-
442 set_intr_gate(0x20,&timer_interrupt);
-
443 outb(inb_p(0x21)&~0x01,0x21);
-
444 set_system_gate(0x80,&system_call);
-
445 }
1.4 set_ldt_desc --> 在include/asm/system.h中
在gdt[n+常数]处嵌入ldt,将参数addr填到基地址中
-
#define _set_tssldt_desc(n,addr,0x82)
-
__asm__ ("movw $104,%1" -->BYTE[0-1]:TSS与LDT段限长=104
-
"movw %%ax,%2" -->BYTE[2-3]:段基址[0-15]
-
"rorl $16,%%eax" -->将eax的高16位与低16位交换
-
"movb %%al,%3" -->BYTE[4]: al是段基址的[16-23]
-
"movb $0x82,%4" -->BYTE[5]: P=1 DPL=0 S=0 TYPE=2(数据段) TYPE=9(代码段)
-
"movb $0x00,%5" -->BYTE[6]: 置0 G=0,DB=0,AVL=0
-
"movb %%ah,%6" -->BYTE[7]: ah是段基址的[24-31]
-
"rorl $16,%%eax" -->将eax的高16位与低16位再交换一次,即把eax恢复成原值
-
::"a" (addr), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)),
-
"m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7))
-
)
-
2. 进程0的启动 --> 在include/asm/system.h中
由特权级0 切换到特权级3
-
#define move_to_user_mode()
-
__asm__ ("movl %%esp,%%eax"
-
"pushl $0x17" -->SS=等于任务0的LDT数据段选择子=0x17,index=2,Ti=1(LDT),RPL=3
-
"pushl %%eax" -->ESP=任务0的堆栈
-
"pushfl" -->EFLAGS=任务0的标志寄存器
-
"pushl $0x0f" -->CS=任务0的LDT代码段选择子=0xF,index=1, TI=1(LDT),RPL=3
-
"pushl $1f" -->EIP=任务0的代码指针,就是下面的标号1
-
"iret" -->iret之后就切换到任务0中去了,就是跳到下面的标号1去执行了
-
"1: movl $0x17,%%eax"
-
"mov %%ax,%%ds"
-
"mov %%ax,%%es" -->这几行就是把ds,es,fs,gs指向进程0的数据段
-
"mov %%ax,%%fs"
-
"mov %%ax,%%gs"
-
:::"ax")
a. 关于iret
intel手册中IRET只会将EIP,CS,EFLAGS弹出,但是当有特权级的切换时,SS:ESP也被弹出
iret之后的出栈顺序是固定的,如下:
EIP --> CS --> EFLAGS --> ESP --> SS
b. 这儿只是改变了SS堆栈特权级,ESP的内容没有改变
附录1. 关于段限长
以下出自:[笔记] 当段限长是0的时候意味着什么
%B6%CE%CF%DE%B3%A4
问题: 当代码段描述符中,段限长为0的时候,代码段多长?
答:当段限长为0的时候,代码段的长度并不是零,而是1个长度单位。长度单位取决于颗粒度。
当颗粒度为0的时候,段的长度单位是字节,限长0代表段的长度是1字节,即段中可以存储1个字节的内容
当颗粒度为1的时候,段的长度单位是4KB,限长0代表段的长度是4KB,即段中可以存储4KB的内容
抽象出,当段限长为n的时候,段的长度是(n+1)个长度单位。
例如,4.9节中的例子,代码段的限长是0x7FF,颗粒度是1。
则,段的长度是(0x7FF + 1) = (0x800) = 2^11个长度单位 =2^11 * 4KB = 8 * (2^10) KB = 8 MB
颗粒度表示用什么方式来计算长度。
颗粒度为0,表示用字节来计算。
颗粒度为1,表示用页数来计算,因为每页大小为4KB
阅读(1065) | 评论(0) | 转发(0) |