- 論壇徽章:
- 0
|
在MINIX3內(nèi)核被成功加載到內(nèi)存后,控制權(quán)會轉(zhuǎn)移到kernel/mpx.s文件,根據(jù)機器字長為16位或32位來分別加載mpx88.s或者mpx386.s文件并執(zhí)行。
此時,cs和ds寄存器已經(jīng)指向MINIX3內(nèi)核的相應段,而ss寄存器仍指向boot的棧段,該棧中結(jié)構(gòu)如下:(棧底)
aout結(jié)構(gòu)體的地址
boot參數(shù)的大小和地址
boot的CS和IP(16位),以便MINIX3結(jié)束后將控制權(quán)交還給boot
(棧頂)
|
對于32位PC機,MINIX3內(nèi)核會跳轉(zhuǎn)到mpx386.s文件的MINIX標簽處開始執(zhí)行:MINIX:
jmp over_flags ! 跳過下面兩個用于boot的數(shù)據(jù)
.data2 CLICK_SHIFT
flags:
.data2 0x01FD
nop
over_flags:
! 設置boot棧,以便MINIX3結(jié)束后交還控制權(quán)
movzx esp, sp ! 將boot棧擴展為32位
push ebp ! 將棧頂?shù)刂穫魉徒oebp
mov ebp, esp
push esi
push edi
cmp 4(ebp), 0 ! 如果boot的cs和ip均為0則不可交還控制權(quán)
jz noret
inc (_mon_return)
noret: mov (_mon_sp), esp ! 保存ESP的值
! 將boot的GDT拷貝到內(nèi)核地址空間,并加載
sgdt (_gdt+GDT_SELECTOR) ! 將GDT的描述結(jié)構(gòu)拷貝到內(nèi)存
! 低2字節(jié)為字節(jié)長,高4字節(jié)為基址
mov esi, (_gdt+GDT_SELECTOR+2) ! boot中GDT的基址
mov ebx, _gdt ! 內(nèi)核中GDT的基址
mov ecx, 8*8 ! 拷貝前8個描述符
copygdt:
eseg movb al, (esi) ! eseg說明操作數(shù)的段寄存器為es
movb (ebx), al
inc esi
inc ebx
loop copygdt
mov eax, (_gdt+DS_SELECTOR+2) ! 設置GDT基址
and eax, 0x00FFFFFF
add eax, _gdt
mov (_gdt+GDT_SELECTOR+2), eax
lgdt (_gdt+GDT_SELECTOR) ! 加載GDT
! 設置內(nèi)核段寄存器和棧
mov ebx, 8(ebp) ! boot參數(shù)地址
mov edx, 12(ebp) ! boot參數(shù)長度
mov eax, 16(ebp) ! a.out頭地址
mov (_aout), eax
mov ax, ds
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, k_stktop
! 調(diào)用start.c文件中的cstart函數(shù)來保存內(nèi)核信息
push edx
push ebx
push SS_SELECTOR
push DS_SELECTOR
push CS_SELECTOR
call _cstart
add esp, 5*4
! 重新加載GDT和IDT
lgdt (_gdt+GDT_SELECTOR)
lidt (_gdt+IDT_SELECTOR)
jmpf CS_SELECTOR:csinit ! 開始使用剛初始化好的表
csinit:
! 初始化段選擇子
o16 mov ax, DS_SELECTOR ! o16說明操作數(shù)為16位
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
o16 mov ax, TSS_SELECTOR ! 初始化任務狀態(tài)段(TSS)
ltr ax
push 0 ! 將eflags清0
popf
! 調(diào)用main.c文件中的main函數(shù)運行boot image
jmp _main |
其中,start.c文件中的cstart函數(shù)實現(xiàn)如下:PUBLIC void cstart(cs, ds, mds, parmoff, parmsize)
U16_t cs, ds; [color=#FF9900>// 內(nèi)核代碼段與數(shù)據(jù)段
U16_t mds; [color=#FF9900>// boot數(shù)據(jù)段
U16_t parmoff, parmsize; [color=#FF9900>// boot參數(shù)地址與長度
{
char params[128*sizeof(char *)];
register char *value;
extern int etext, end;
#if _WORD_SIZE != 2
[color=#FF9900>// 如果是386+則設置保護模式
machine.protected = 1;
#endif
[color=#FF9900>// 保存內(nèi)核代碼段和數(shù)據(jù)地址與長度
kinfo.code_base = seg2phys(cs);
kinfo.code_size = (phys_bytes) &etext;
kinfo.data_base = seg2phys(ds);
kinfo.data_size = (phys_bytes) &end;
[color=#FF9900>// 初始化保護模式下的描述符
prot_init();
[color=#FF9900>// 將boot參數(shù)拷貝到本地
kinfo.params_base = seg2phys(mds) + parmoff; [color=#FF9900>// boot參數(shù)地址
kinfo.params_size = MIN(parmsize,sizeof(params)-2); [color=#FF9900>// boot參數(shù)長度
phys_copy(kinfo.params_base, vir2phys(params), kinfo.params_size);
[color=#FF9900>// 源 目的 長度
[color=#FF9900>// 保存其他信息
kinfo.nr_procs = NR_PROCS;
kinfo.nr_tasks = NR_TASKS;
strncpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release)); [color=#FF9900>// 目的 源 長度
kinfo.release[sizeof(kinfo.release)-1] = '\0';
strncpy(kinfo.version, OS_VERSION, sizeof(kinfo.version));
kinfo.version[sizeof(kinfo.version)-1] = '\0';
kinfo.proc_addr = (vir_bytes) proc;
kinfo.kmem_base = vir2phys(0);
kinfo.kmem_size = (phys_bytes) &end;
[color=#FF9900>// 獲取CPU類型
machine.processor=atoi(get_value(params, "processor"));
#if _WORD_SIZE == 2
machine.protected = machine.processor >= 286;
#endif
if (!machine.protected) mon_return = 0;
[color=#FF9900>// 獲取總線類型
value = get_value(params, "bus");
if (value == NIL_PTR || strcmp(value, "at") == 0) {
machine.pc_at = TRUE;
} else if (strcmp(value, "mca") == 0) {
machine.pc_at = machine.ps_mca = TRUE;
}
[color=#FF9900>// 獲取顯示器類型
value = get_value(params, "video");
if (strcmp(value, "ega") == 0) machine.vdu_ega = TRUE;
if (strcmp(value, "vga") == 0) machine.vdu_vga = machine.vdu_ega = TRUE;
} |
|
|