初始化進(jìn)程控制塊數(shù)組的操作是在init_proc_list()內(nèi)完成的,它只被cbegin()函數(shù)調(diào)用,其實(shí)它的工作很簡(jiǎn)單,就是將進(jìn)程控制塊中的各個(gè)項(xiàng)初始化成初始值。并且將相應(yīng)進(jìn)程的LDT在GDT中的描述符初始化。這樣當(dāng)啟動(dòng)一個(gè)進(jìn)程的時(shí)候,只需要在進(jìn)程自己的LDT和TSS中填入適當(dāng)?shù)闹导纯桑恍枰頃?huì)LDT和TSS在GDT中的描述符內(nèi)容。
1 //初始化init和sys進(jìn)程
2 //主要包括進(jìn)程pid、進(jìn)程名、ldt、tss以及init進(jìn)程在gdt中對(duì)應(yīng)的項(xiàng)的初始化
3 static void init_proc01()
4 {
5 struct seg_struct ldt_temp[3] = {{0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00},
6 {0xffff, 0x0000, 0x00, 0xfa, 0xcf, 0x00},
7 {0xffff, 0x0000, 0x00, 0xf2, 0xcf, 0x00}};
8
9 //pid為0
10 //進(jìn)程名為"init"
11 proc_list[0].pid = 0;
12 proc_list[0].ppid = -1;
13 proc_list[0].state = PROC_RUNNING;
14 proc_list[0].priority = 15;
15 proc_list[0].time_slices = proc_list[0].priority;
16 proc_list[0].running_time = 0;
17 strcpy(proc_list[0].name, "init");
18 //ldt共包括三項(xiàng),0->空,1->cs,2->ds&ss
19 proc_list[0].ldt[0] = ldt_temp[0];
20 proc_list[0].ldt[1] = ldt_temp[1];
21 proc_list[0].ldt[2] = ldt_temp[2];
22 proc_list[0].tss.back_link = 0;
23 proc_list[0].tss.esp0 = KSTACKTOP(0); //內(nèi)核態(tài)堆棧頂
24 proc_list[0].tss.ss0 = KERNEL_SS_SELECTOR;
25 proc_list[0].tss.esp1 = 0;
26 proc_list[0].tss.ss1 = 0;
27 proc_list[0].tss.esp2 = 0;
28 proc_list[0].tss.ss2 = 0;
29 proc_list[0].tss.cr3 = (uint32)page_dir; //頁(yè)目錄表地址
30 proc_list[0].tss.eip = 0;
31 proc_list[0].tss.eflags = 0;
32 proc_list[0].tss.eax = 0;
33 proc_list[0].tss.ecx = 0;
34 proc_list[0].tss.edx = 0;
35 proc_list[0].tss.ebx = 0;
36 proc_list[0].tss.esp = 0;
37 proc_list[0].tss.ebp = 0;
38 proc_list[0].tss.esi = 0;
39 proc_list[0].tss.edi = 0;
40 proc_list[0].tss.es = 0x17; //指向ldt中的選擇子
41 proc_list[0].tss.cs = 0x0f; //指向ldt中的選擇子
42 proc_list[0].tss.ss = 0x17; //指向ldt中的選擇子
43 proc_list[0].tss.ds = 0x17; //指向ldt中的選擇子
44 proc_list[0].tss.fs = 0x17; //指向ldt中的選擇子
45 proc_list[0].tss.gs = 0x17; //指向ldt中的選擇子
46 proc_list[0].tss.ldt = LDT_SELECTOR(0);
47 proc_list[0].tss.trace_bitmap = 0x80000000;
48
49 set_tss_seg(FIRST_TSS_INDEX, &(proc_list[0].tss));
50 set_ldt_seg(FIRST_LDT_INDEX, proc_list[0].ldt);
51
52 //pid為1
53 //進(jìn)程名為"sys"
54 proc_list[1].pid = 1;
55 proc_list[1].ppid = 0;
56 proc_list[1].state = PROC_RUNNING;
57 proc_list[1].priority = 15;
58 proc_list[1].time_slices = proc_list[1].priority;
59 proc_list[1].running_time = 0;
60 strcpy(proc_list[1].name, "sys");
61 //ldt共包括三項(xiàng),0->空,1->cs,2->ds&ss
62 proc_list[1].ldt[0] = ldt_temp[0];
63 proc_list[1].ldt[1] = ldt_temp[1];
64 proc_list[1].ldt[2] = ldt_temp[2];
65 proc_list[1].tss.back_link = 0;
66 proc_list[1].tss.esp0 = KSTACKTOP(1); //內(nèi)核態(tài)堆棧頂
67 proc_list[1].tss.ss0 = KERNEL_SS_SELECTOR;
68 proc_list[1].tss.esp1 = 0;
69 proc_list[1].tss.ss1 = 0;
70 proc_list[1].tss.esp2 = 0;
71 proc_list[1].tss.ss2 = 0;
72 proc_list[1].tss.cr3 = (uint32)page_dir; //頁(yè)目錄表地址
73 proc_list[1].tss.eip = (uint32)sys;
74 proc_list[1].tss.eflags = 0x1202;
75 proc_list[1].tss.eax = 0;
76 proc_list[1].tss.ecx = 0;
77 proc_list[1].tss.edx = 0;
78 proc_list[1].tss.ebx = 0;
79 proc_list[1].tss.esp = USTACKTOP(1);
80 proc_list[1].tss.ebp = USTACKTOP(1);
81 proc_list[1].tss.esi = 0;
82 proc_list[1].tss.edi = 0;
83 proc_list[1].tss.es = 0x17; //指向ldt中的選擇子
84 proc_list[1].tss.cs = 0x0f; //指向ldt中的選擇子
85 proc_list[1].tss.ss = 0x17; //指向ldt中的選擇子
86 proc_list[1].tss.ds = 0x17; //指向ldt中的選擇子
87 proc_list[1].tss.fs = 0x17; //指向ldt中的選擇子
88 proc_list[1].tss.gs = 0x17; //指向ldt中的選擇子
89 proc_list[1].tss.ldt = LDT_SELECTOR(1);
90 proc_list[1].tss.trace_bitmap = 0x80000000;
91
92 set_tss_seg(FIRST_TSS_INDEX + 2, &(proc_list[1].tss));
93 set_ldt_seg(FIRST_LDT_INDEX + 2, proc_list[1].ldt);
94 }
95
96 void init_proc_list()
97 {
98 int i;
99 for (i = 0; i < NR_PROCS; ++i)
100 {
101 proc_list[i].pid = -1;
102 proc_list[i].ppid = -1;
103 proc_list[i].state = PROC_STOPPED;
104 proc_list[i].priority = 0;
105 proc_list[i].time_slices = 0;
106 proc_list[i].running_time = 0;
107 memset(proc_list[i].name, 0, PROC_NAME_LEN);
108 memset(proc_list[i].ldt, 0, 3 * sizeof(struct seg_struct));
109 memset(&(proc_list[i].tss), 0, sizeof(TSS));
110 set_tss_seg(FIRST_TSS_INDEX + i * 2, &(proc_list[i].tss));
111 set_ldt_seg(FIRST_LDT_INDEX + i * 2, proc_list[i].ldt);
112 }
113
114 //啟動(dòng)的第一個(gè)進(jìn)程是進(jìn)程鏈表proc_list中第一個(gè)進(jìn)程,為init進(jìn)程
115 current = proc_list;
116 }
117
注意到在process.c文件中有一個(gè)current變量,它是proc_struct類型指針,是全局變量,這從linux借鑒過(guò)來(lái),用于指向當(dāng)前正在運(yùn)行的進(jìn)程。
下面著重看init_proc01()函數(shù)。
它的作用是在proc_list[0]和proc_list[1]中填入適當(dāng)?shù)闹担詾閱?dòng)進(jìn)程init(0號(hào)進(jìn)程)和sys(1號(hào)進(jìn)程)做準(zhǔn)備。
我們只研究init進(jìn)程控制塊的填入過(guò)程:
進(jìn)程id為0,父進(jìn)程id為-1(因?yàn)樗撬羞M(jìn)程的父進(jìn)程,它沒(méi)有父進(jìn)程),優(yōu)先級(jí)為15,因此初始時(shí)間片為15。仔細(xì)研究ldt_temp[]發(fā)現(xiàn)ldt中的cs段描述符屬性為:地址空間為0-4G,DPL=3,說(shuō)明是用戶級(jí)別進(jìn)程代碼段;ds段描述符屬性為:地址空間為0-4G,DPL=3,說(shuō)明是用戶級(jí)別數(shù)據(jù)段。再看tss中各字段的填入過(guò)程,重要的幾個(gè)字段分別是:esp0、ss0、cr3、eip、eflags、esp、ebp、以及es、cs、ss、ds、fs、gs以及l(fā)dt,對(duì)于init進(jìn)程,由于我們會(huì)在后面手工啟動(dòng),所以有些字段可以不填,但是對(duì)于其他進(jìn)程的初始化,這些字段都是必須填寫(xiě)合適并完整的。
最后看手工啟動(dòng)進(jìn)程init的函數(shù),該函數(shù)非常重要,啟動(dòng)init之后我們的操作系統(tǒng)便有了質(zhì)的飛躍。
1 void start_proc0()
2 {
3 //初始化init進(jìn)程
4 init_proc01();
5
6 uint32 ss = 0x17;
7 uint32 esp = USTACKTOP(0);
8 uint32 eflags = 0x1202; //init進(jìn)程可以使用I/O命令,同時(shí)要求init進(jìn)程允許中斷
9 uint32 cs = 0x0f;
10 uint32 eip = (uint32)init;
11
12 /**********************************************************
13 * 下面調(diào)試了很久!!!!!!!!!!!!!!!!!
14 * 不能將enable_hwint(CLOCK_IV);語(yǔ)句放到緊挨sti()的前面
15 * 因?yàn)閑nable_hwint(CLOCK_IV)是c語(yǔ)句宏,展開(kāi)之后會(huì)
16 * 用到堆棧,就會(huì)把剛push進(jìn)去的ss、esp、eflags、cs、eip
17 * 給覆蓋掉!!!!!!!!!!!!!!!!!!!!!!
18 * 將enable_hwint()放到init_clock()里面
19 **********************************************************/
20
21 //加載init進(jìn)程對(duì)應(yīng)的tss
22 //加載init進(jìn)程對(duì)應(yīng)的ldt
23 ltr(TSS_SELECTOR(0));
24 lldt(LDT_SELECTOR(0));
25 push(ss); //push ss
26 push(esp); //push esp
27 push(eflags); //push eflags
28 push(cs); //push cs
29 push(eip); //push eip
30 init_segr(); //初始化ds、es、gs、fs四個(gè)段寄存器, 使其指向ldt中的數(shù)據(jù)段描述符
31 sti(); //打開(kāi)中斷,從現(xiàn)在開(kāi)始內(nèi)核態(tài)將允許中斷
32 iretd(); //iretd這條指令之后第一個(gè)進(jìn)程init進(jìn)程便開(kāi)始運(yùn)行了
33 }
34
手工啟動(dòng)進(jìn)程的過(guò)程我們采用minix的做法,在內(nèi)核棧中我們偽造一個(gè)現(xiàn)場(chǎng),使得其看似是正在運(yùn)行進(jìn)程init然后發(fā)生時(shí)鐘中斷后的現(xiàn)場(chǎng),這樣的現(xiàn)場(chǎng)應(yīng)該是這樣的:
進(jìn)程init的ss、esp、eflags、cs、eip應(yīng)該已經(jīng)被壓入棧中,寄存器tr應(yīng)該存有進(jìn)程init在GDT中的tss選擇子,寄存器ldtr應(yīng)該存有進(jìn)程init在GDT中的ldt選擇子,各個(gè)段寄存器應(yīng)該是指向ldt中的選擇子。如果這些都準(zhǔn)備好了那就和時(shí)鐘中斷處理程序返回前沒(méi)什么兩樣了,這樣就可以打開(kāi)中斷,然后使用一條iret指令就可以了。iret指令會(huì)依次從堆棧中彈出eip、cs、eflags、esp、ss,然后切換到進(jìn)程init的用戶態(tài)繼續(xù)執(zhí)行代碼,這樣我們的第一個(gè)init進(jìn)程就啟動(dòng)起來(lái)了!!!
posted on 2012-02-14 19:34
myjfm 閱讀(348)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
操作系統(tǒng)