JOS學習筆記(十)

神說、進程要有多個、可以分片、切換、互不影響. 
並要支持多任務、多處理器並行.事就這樣成了。 
 於是 神造了多個內核棧,又開闢多個寄存器。 
 就把這些擺列在內存裏、內核空間裏、 
管理多核,分別任務. 神看着是好的. 

有晚上、有早晨、是第四日。 


博主寫完論文,又寫了個簡單的編譯器,然後回來再拾起來差點爛尾的JOS發現代碼已經完全看不懂了,花了一整天時間複習之前自己寫的博客,才勉強做了實驗四的一點。

本篇博客內容對應課程地址(http://pdos.csail.mit.edu/6.828/2011/labs/lab4/)locking標籤之前的內容,也就是多核CPU的初始化工作。博客分以下2部分來進行闡述,1、多核啓動流程,2、實驗部分


1、多核CPU啓動流程

在內核加載和進行初始化時,即便是有一個多核CPU,也只能使用一個核,爲了和JOS實驗中的描述一致,我們這裏暫且把多個核(Core)稱之爲多個CPU。

內核啓動過程中用於執行代碼的CPU叫做bootstrap processor (BSP),其它還未被使用的CPU叫做application processors (APs),所以在內核執行的時候必然會有的一個過程就是使用BSP來激活AP的過程。

對應JOS代碼是init.c中的init主函數,其關鍵片段如下:


lab2的 mem_init,lab3的env_init和trap_init,lab4的mp_init和lapic_init在這之後需要補充一個Big kernel Lock 暫時不用管,然後boot_ap函數啓動所有的CPU,接着有多少個CPU就建立多少個ENV。

在啓動過程中,mp_init和lapic_init是和硬件以及體系架構緊密相關的,通過讀取某個特殊內存地址(當然前提是能讀取的到,所以在mem_init中需要修改進行相應映射),來獲取CPU的信息,根據這些信息初始化CPU結構,大致流程就是這樣,博主因爲能力所限,這部分就不進行詳細分析了。

boot_ap是個很有趣的函數。在函數中首先找到一段用於啓動的彙編代碼,該代碼和上一章實驗一樣是嵌入在內核代碼段之上的一部分,其中mpentry_start和mpentry_end是編譯器導出符號,代表這段代碼在內存(虛擬地址)中的起止位置,接着把代碼複製到MPENTRY_PADDR處。隨後調用lapic_startap來命令特定的AP去執行這段代碼。

這段彙編(mpentry.S)中所做的工作和entry.S所做的工作基本相同。需要注意的一點是每個CPU都有自己的寄存器和棧,需要啓動的AP目前還處於實模式,並且內存也沒有開啓分頁,因此所有和符號地址相關的操作都要非常謹慎的轉換爲物理地址。

之後控制流跳轉到mp_main,值得注意的是從mpentry.S開始這些代碼都是執行在AP上的,此時BSP正在等待(while循環)AP啓動成功。在mp_main裏可以看到AP初始化自己的env,trap等,接着改變自己的cpu數據結構中的cpu狀態標誌爲啓動成功,然後進入死循環空轉。BSP得到AP啓動成功的信息後接着嘗試啓動下一個AP。

整個啓動流程大概就是如此,下面進入實驗過程。


2、實驗

2.1 

第一個任務是因爲我們把代碼拷貝到了MPENTRY_PADDR處,所以要在初始化Page的時候把這一頁從Page_Free_List中取出來,以防止該頁被分配出去導致代碼拷貝的失敗進而不能正確啓動AP。


只需要在pmap.c的page_init函數的最後加上以上幾行代碼,首先獲取該地址對應的Page結構,然後從page_free_list中剝離就行。

如果正確的話,此時應該能通過check_page_free_list函數

2.2 

第二個實驗要求爲每一個核映射其內核棧,也就是對於編號爲i的cpu,需要映射KSTACKTOP-i*(KSTKSIZE+KSTKGAP)-KSTKSIZE 到KSTACKTOP-i*(KSTKSIZE+KSTKGAP) 這塊虛擬地址空間到符號percpu_kstacks[i]所對應的物理地址處,改變mp_mem_init函數,代碼如下:


值得注意的是,雖然課程中說此時應該可以通過check_kern_pgdir,但實際上是通不過的。原因在於BSP的內核棧被映射了兩次,第一次是在lab3中將內核棧映射到了bootstack,當時只有一個CPU,自然映射的是BSP的堆棧;第二次是在我們剛纔寫的代碼裏,將BSP(也就是cpunum()==0的CPU)的內核棧映射到了percpu_kstack[0]。詭異的是bootstack地址不等於percpu_kstack地址,而check_kern_pgdir里居然要求兩種映射都存在的情況下才能通過。這顯然是不可能的,感覺是JOS實驗設計中的一個疏忽吧。因此我把檢查bootstack的那段代碼註釋掉了,這樣才得以通過。


2.3

第三個實驗是需要完成trap_init_percpu()函數,給相應的CPU加載正確的TSS段選擇子,代碼如下:


根據函數中的暗示+照葫蘆畫瓢,不難把代碼改成上述的樣子。

至此就完成了LAB4的PART A的一小部分,運行目前的OS可以看到(使用make qemu CPUS=4)可以發現創建了9個env,然後出現了未定義的sys_call,系統panic。


發佈了78 篇原創文章 · 獲贊 14 · 訪問量 48萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章