初始化進程控制塊數組的操作是在init_proc_list()內完成的,它只被cbegin()函數調用,其實它的工作很簡單,就是將進程控制塊中的各個項初始化成初始值。并且將相應進程的LDT在GDT中的描述符初始化。這樣當啟動一個進程的時候,只需要在進程自己的LDT和TSS中填入適當的值即可,不需要理會LDT和TSS在GDT中的描述符內容。
1 //初始化init和sys進程
2 //主要包括進程pid、進程名、ldt、tss以及init進程在gdt中對應的項的初始化
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 //進程名為"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共包括三項,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); //內核態堆棧頂
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; //頁目錄表地址
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 //進程名為"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共包括三項,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); //內核態堆棧頂
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; //頁目錄表地址
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 //啟動的第一個進程是進程鏈表proc_list中第一個進程,為init進程
115 current = proc_list;
116 }
117
注意到在process.c文件中有一個current變量,它是proc_struct類型指針,是全局變量,這從linux借鑒過來,用于指向當前正在運行的進程。
下面著重看init_proc01()函數。
它的作用是在proc_list[0]和proc_list[1]中填入適當的值,以為啟動進程init(0號進程)和sys(1號進程)做準備。
我們只研究init進程控制塊的填入過程:
進程id為0,父進程id為-1(因為它是所有進程的父進程,它沒有父進程),優先級為15,因此初始時間片為15。仔細研究ldt_temp[]發現ldt中的cs段描述符屬性為:地址空間為0-4G,DPL=3,說明是用戶級別進程代碼段;ds段描述符屬性為:地址空間為0-4G,DPL=3,說明是用戶級別數據段。再看tss中各字段的填入過程,重要的幾個字段分別是:esp0、ss0、cr3、eip、eflags、esp、ebp、以及es、cs、ss、ds、fs、gs以及ldt,對于init進程,由于我們會在后面手工啟動,所以有些字段可以不填,但是對于其他進程的初始化,這些字段都是必須填寫合適并完整的。
最后看手工啟動進程init的函數,該函數非常重要,啟動init之后我們的操作系統便有了質的飛躍。
1 void start_proc0()
2 {
3 //初始化init進程
4 init_proc01();
5
6 uint32 ss = 0x17;
7 uint32 esp = USTACKTOP(0);
8 uint32 eflags = 0x1202; //init進程可以使用I/O命令,同時要求init進程允許中斷
9 uint32 cs = 0x0f;
10 uint32 eip = (uint32)init;
11
12 /**********************************************************
13 * 下面調試了很久!!!!!!!!!!!!!!!!!
14 * 不能將enable_hwint(CLOCK_IV);語句放到緊挨sti()的前面
15 * 因為enable_hwint(CLOCK_IV)是c語句宏,展開之后會
16 * 用到堆棧,就會把剛push進去的ss、esp、eflags、cs、eip
17 * 給覆蓋掉!!!!!!!!!!!!!!!!!!!!!!
18 * 將enable_hwint()放到init_clock()里面
19 **********************************************************/
20
21 //加載init進程對應的tss
22 //加載init進程對應的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四個段寄存器, 使其指向ldt中的數據段描述符
31 sti(); //打開中斷,從現在開始內核態將允許中斷
32 iretd(); //iretd這條指令之后第一個進程init進程便開始運行了
33 }
34
手工啟動進程的過程我們采用minix的做法,在內核棧中我們偽造一個現場,使得其看似是正在運行進程init然后發生時鐘中斷后的現場,這樣的現場應該是這樣的:
進程init的ss、esp、eflags、cs、eip應該已經被壓入棧中,寄存器tr應該存有進程init在GDT中的tss選擇子,寄存器ldtr應該存有進程init在GDT中的ldt選擇子,各個段寄存器應該是指向ldt中的選擇子。如果這些都準備好了那就和時鐘中斷處理程序返回前沒什么兩樣了,這樣就可以打開中斷,然后使用一條iret指令就可以了。iret指令會依次從堆棧中彈出eip、cs、eflags、esp、ss,然后切換到進程init的用戶態繼續執行代碼,這樣我們的第一個init進程就啟動起來了!!!
posted on 2012-02-14 19:34
myjfm 閱讀(338)
評論(0) 編輯 收藏 引用 所屬分類:
操作系統