進入內核后,當然不能無所事事。先創建三個進程,分別打印 A,B,C。雖然只是簡單的打印,但卻是一切擴展的基礎,不可等閑視之。
進程切換,涉及一系列的寄存器需要保護,于是,就有了 PRocessStack 結構,代碼如下:
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;
稍加注意,會發現有個 KernelEsp。它的作用,是防止進程切換時,棧指針亂指。
進程切換,當然離不開中斷。有意思的是,涉及中斷調用的任務狀態棧 TSS 同 ProcessStack 竟有異曲同工之妙。
進程切換,還有一個關鍵,就是不能再用簡單的 ret 來返回了。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 設置。即 for 循環里的pProc->Regs.esp = (u32)pTaskStack; 這種多兵種作戰,需細心體會,方能領會之。
此關鍵點如能領會,進程切換就不是難事。所謂進程,不過在 ProcessStack 的基礎上,添加一些進程 Id,name,優先級而已。
進入工程目錄,make 后,再 bochs,即可看到如下界面:
其中,優先級的設置為 15:5:3, 同顯示的基本一致。完整代碼,可到 x01.Lab.Download 中下載。虛擬機及開發工具,可參看 x01.os.7。
有個問題需說明一下。就是修改后重新 make 時,會出現 /mnt/temp 忙,可運行命令 sudo umount /mnt/temp 卸載之。
新聞熱點
疑難解答