天天看點

《Linux核心設計的藝術:圖解Linux作業系統架構設計與實作原理》——2.9 初始化程序0

程序0是linux作業系統中運作的第一個程序,也是linux作業系統父子程序建立機制的第一個父程序。下面講解的内容對程序0能夠在主機中正常運算的影響最為重要和深遠,主要包含如下三方面的内容。

1)系統先初始化程序0。程序0管理結構task_struct的母本(init_task = {init_task,})已經在代碼設計階段事先設計好了,但這并不代表程序0已經可用了,還要将程序0的task_struct中的ldt、tss與gdt相挂接,并對gdt、task[64]以及與程序排程相關的寄存器進行初始化設定。

2)linux 0.11作為一個現代作業系統,其最重要的标志就是能夠支援多程序輪流執行,這要求程序具備參與多程序輪詢的能力。系統這裡對時鐘中斷進行設定,以便在程序0運作後,為程序0以及後續由它直接、間接建立出來的程序能夠參與輪轉奠定基礎。

3)程序0要具備處理系統調用的能力。每個程序在運算時都可能需要與核心進行互動,而互動的端口就是系統調用程式。系統通過函數set_system_gate将system_call與idt相挂接,這樣程序0就具備了處理系統調用的能力了。這個system_call就是系統調用的總入口。

程序0隻有具備了以上三種能力才能保證将來在主機中正常地運作,并将這些能力遺傳給後續建立的程序。

這三點的實作都是在sched_init()函數中實作的,具體代碼如下:

2.9.1 初始化程序0

sched_init函數比較難了解的是下面兩行:

這兩行代碼的目的就是要像圖2-17表現的那樣在gdt中初始化程序0所占的4、5兩項,即初始化tss0和ldt0。

《Linux核心設計的藝術:圖解Linux作業系統架構設計與實作原理》——2.9 初始化程式0

另外,要拼出圖2-18所示的結構。我們以tss0為例,參看源代碼中的注釋,可以繪出圖2-19。ldt0類似。

《Linux核心設計的藝術:圖解Linux作業系統架構設計與實作原理》——2.9 初始化程式0

對比源代碼、注釋和圖,可以看出,movw $104,%1是将104賦給了段限長15:0的部分;粒度g為0,說明限長就是104位元組,而tss除去struct i387_struct i387後長度正好是104位元組。ldt是3×8 =24位元組,是以104位元組限長夠用。tss的類型是0x89,即二進制的10001001,可以看出movb $" type ",%4在給type指派1001的同時,順便将p、dpl、s字段都指派好了。同理,movb $0x00,%5在給段限長19:16部分指派0000的同時,順便将g、d/b、保留、avl字段都指派好了。

《Linux核心設計的藝術:圖解Linux作業系統架構設計與實作原理》——2.9 初始化程式0

程序0的task_struct是由作業系統設計者事先寫好的,就是sched.h中的init_task(參看上面相關源代碼和注釋,其結構示意見圖2-20),并用init_task的指針初始化task[64]的0項。

《Linux核心設計的藝術:圖解Linux作業系統架構設計與實作原理》——2.9 初始化程式0

sched_init()函數接下來用for循環将task[64]除程序0占用的0項外的其餘63項清空,同時将gdt的tss1、ldt1往上的所有表項清零,效果如圖2-21所示。

初始化程序0相關的管理結構的最後一步是非常重要的一步,是将tr寄存器指向tss0、ldtr寄存器指向ldt0,這樣,cpu就能通過tr、ldtr寄存器找到程序0的tss0、ldt0,也能找到一切和程序0相關的管理資訊。

《Linux核心設計的藝術:圖解Linux作業系統架構設計與實作原理》——2.9 初始化程式0

2.9.2 設定時鐘中斷

接下來就對時鐘中斷進行設定。時鐘中斷是程序0及其他由它建立的程序輪轉的基礎。對時鐘中斷進行設定的過程具體分為如下三個步驟。

1)對支援輪詢的8253定時器進行設定。這一步操作如圖2-20中的第一步所示,其中latch最關鍵。latch是通過一個宏定義的,通過它在sched.c中的定義“#define latch (1193180/hz)”,即系統每10毫秒發生一次時鐘中斷。

2)設定時鐘中斷,如圖2-22中的第二步所示, timer_interrupt()函數挂接後,在發生時鐘中斷時,系統就可以通過idt找到這個服務程式來進行具體的處理。

3)将8259a晶片中與時鐘中斷相關的屏蔽碼打開,時鐘中斷就可以産生了。從現在開始,時鐘中斷每1/100秒就産生一次。由于此時處于“關中斷”狀态,cpu并不響應,但程序0已經具備參與程序輪轉的潛能。

2.9.3 設定系統調用總入口

将系統調用處理函數system_call與 int 0x80中斷描述符表挂接。system_call是整個作業系統中系統調用軟中斷的總入口。所有使用者程式使用系統調用,産生int 0x80軟中斷後,作業系統都是通過這個總入口找到具體的系統調用函數。該過程如圖2-23所示。

《Linux核心設計的藝術:圖解Linux作業系統架構設計與實作原理》——2.9 初始化程式0
《Linux核心設計的藝術:圖解Linux作業系統架構設計與實作原理》——2.9 初始化程式0

系統調用函數是作業系統對使用者程式的基本支援。在作業系統中,依托硬體提供的特權級對核心進行保護,不允許使用者程序直接通路核心代碼。但程序有大量的像讀盤、建立子程序之類的具體事務處理需要核心代碼的支援。為了解決這個沖突,作業系統的設計者提供了系統調用的解決方案,提供一套系統服務接口。使用者程序隻要想和核心打交道,就調用這套接口程式,之後,就會立即引發int 0x80軟中斷,後面的事情就不需要使用者程式管了,而是通過另一條執行路線——由cpu對這個中斷信号響應,翻轉特權級(從使用者程序的3特權級翻轉到核心的0特權級),通過idt找到系統調用端口,調用具體的系統調用函數來處理事務,之後,再iret翻轉回到程序的3特權級,程序繼續執行原來的邏輯,這樣沖突就解決了。

繼續閱讀