進(jìn)入內(nèi)核后,當(dāng)然不能無(wú)所事事。先創(chuàng)建三個(gè)進(jìn)程,分別打印 A,B,C。雖然只是簡(jiǎn)單的打印,但卻是一切擴(kuò)展的基礎(chǔ),不可等閑視之。
進(jìn)程切換,涉及一系列的寄存器需要保護(hù),于是,就有了 PRocessStack 結(jié)構(gòu),代碼如下:
typedef struct { u32 gs; u32 fs; u32 es; u32 ds; u32 edi; u32 esi; u32 ebp; u32 KernelEsp; u32 ebx; u32 edx; u32 ecx; u32 eax; u32 RetAddr; u32 eip; u32 cs; u32 eflags; u32 esp; u32 ss;} ProcessStack;
稍加注意,會(huì)發(fā)現(xiàn)有個(gè) KernelEsp。它的作用,是防止進(jìn)程切換時(shí),棧指針亂指。
進(jìn)程切換,當(dāng)然離不開(kāi)中斷。有意思的是,涉及中斷調(diào)用的任務(wù)狀態(tài)棧 TSS 同 ProcessStack 竟有異曲同工之妙。
進(jìn)程切換,還有一個(gè)關(guān)鍵,就是不能再用簡(jiǎn)單的 ret 來(lái)返回了。kernel.s 中的 save 代碼如下:
save: pushad push ds push es push fs push gs mov dx, ss mov ds, dx mov es, dx mov esi, esp inc dWord [g_IntReenter] cmp dword [g_IntReenter], 0 jne .1 mov esp, StackTop push Restart jmp [esi + P_RetAddr - P_StackBase].1: push reenter jmp [esi + P_RetAddr - P_StackBase]Restart: mov esp, [g_pProcReady] lldt [esp + P_LdtSel] lea esi, [esp + P_StackTop] mov dword [g_Tss + TSS_ESP0], esireenter: dec dword [g_IntReenter] pop gs pop fs pop es pop ds popad add esp, 4 iretd
其中的 jmp [esi + P_RetAddr - P_StackBase] ,就是跳到事先保存的返回地址。而這一返回地址,由 main.c 中的 KernelMain 設(shè)置。即 for 循環(huán)里的pProc->Regs.esp = (u32)pTaskStack; 這種多兵種作戰(zhàn),需細(xì)心體會(huì),方能領(lǐng)會(huì)之。
此關(guān)鍵點(diǎn)如能領(lǐng)會(huì),進(jìn)程切換就不是難事。所謂進(jìn)程,不過(guò)在 ProcessStack 的基礎(chǔ)上,添加一些進(jìn)程 Id,name,優(yōu)先級(jí)而已。
進(jìn)入工程目錄,make 后,再 bochs,即可看到如下界面:
其中,優(yōu)先級(jí)的設(shè)置為 15:5:3, 同顯示的基本一致。完整代碼,可到 x01.Lab.Download 中下載。虛擬機(jī)及開(kāi)發(fā)工具,可參看 x01.os.7。
有個(gè)問(wèn)題需說(shuō)明一下。就是修改后重新 make 時(shí),會(huì)出現(xiàn) /mnt/temp 忙,可運(yùn)行命令 sudo umount /mnt/temp 卸載之。
新聞熱點(diǎn)
疑難解答
圖片精選