欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
內核代碼學(xué)習==>深入介紹Linux內核(七)

深入介紹Linux內核(七)



.......續上第六篇


4.7 任務(wù)管理

任務(wù)(Task)是處理器可以分配調度、執行和掛起的一個(gè)工作單元。它循
於執行程式、任務(wù)或進(jìn)程、作業(yè)系統服務(wù)、中斷或異常處理行程和內核代碼?。

80X86提供了一種機制,這種機制可用來(lái)保存任務(wù)的狀態(tài)、分派任務(wù)執行以及從一個(gè)任務(wù)切換到另一個(gè)任務(wù)。當工作在保護模式下,處理器所有執行都在任務(wù)中。即使是簡(jiǎn)單系統也必須起碼定義一個(gè)任務(wù)。更為復雜的系統可以使用處理器的任務(wù)管理功能來(lái)支援多工應用。

80X86提供了多工的硬體支援。任務(wù)是一個(gè)正在執行的程式,或者是一個(gè)等待準備執行的程式。透過(guò)中斷、異常、跳轉或呼叫,我們可以執行一個(gè)任務(wù)。當這些控制轉移形式之一和某個(gè)描述符號表中指定項的內容一起使用時(shí),那麼這個(gè)描述符號就是一類(lèi)導致新任務(wù)開(kāi)始執行的描述符號。描述符號表中與任務(wù)相關(guān)的描述符號有兩類(lèi):任務(wù)狀態(tài)段描述符號和任務(wù)門(mén)。當執行權傳給這任何一類(lèi)描述符號時(shí),都會(huì )造成任務(wù)切換。


任務(wù)切換很像程序呼叫,但任務(wù)切換會(huì )保存更多的處理器狀態(tài)資訊。任務(wù)切換會(huì )把控制權完全轉移到一個(gè)新的執行環(huán)境,即新任務(wù)的執行環(huán)境。這種轉移操作要求保存處理器中幾乎所有寄存器的當前內容,包括標志寄存器EFLAGS和所有段積存器。與行程不過(guò),任務(wù)不可重入。任務(wù)切換不會(huì )把任何資訊壓入堆棧中,處理器的狀態(tài)資訊都被保存在記憶體中稱(chēng)為任務(wù)狀態(tài)段(Task state segment)的資料結構中。


4.7.1 任務(wù)的結構和狀態(tài)

一個(gè)任務(wù)由兩部分構成:任務(wù)執行空間和任務(wù)狀態(tài)段TSS(Task-state segment)。任務(wù)執行空間包括代碼段、堆棧段和一個(gè)或多個(gè)資料段,見(jiàn)圖4-33所示。如果作業(yè)系統使用了處理器的特權級保護機制,那麼任務(wù)執行空間就需要為每個(gè)特權級提供一個(gè)獨立的堆??臻g。TSS指定了構成任務(wù)執行空問(wèn)的各個(gè)段,並且為任務(wù)狀態(tài)資訊提供儲存空間。在多工環(huán)境中,TSS也為任務(wù)之間的鏈結提供了處理方法。






一個(gè)任務(wù)使用指向其TSS的段選擇符號來(lái)指定。當一個(gè)任務(wù)被載入進(jìn)處理器中執行時(shí),那麼該任務(wù)的段選擇符號、基底位址、段限長(cháng)以及TSS段描述符號屬性就會(huì )被載入進(jìn)任務(wù)寄存器TR(Task Register)中。如果使用了分頁(yè)機制,那麼任務(wù)使用的頁(yè)目錄表基底位址就會(huì )被載入進(jìn)控制寄存器CR3中。當前執行任務(wù)的狀態(tài)由處理器所有以下一些內容組成:


▓ 所有通用寄存器和段寄存器資訊:

▓ 標志寄存器EFLAGS、程式指標EIP、控制寄存器CR3、任務(wù)寄存器和LDTR寄存器:

▓ 段寄存器指定的任務(wù)當前執行空間:

▓ I/O映射點(diǎn)陣圖基底位址和I/O點(diǎn)陣圖資訊 (在TSS中) ;

▓ 特權級0、1和2的堆棧指標 (在TSS中);

▓ 鏈結至前一個(gè)任務(wù)的鏈指標 (在TSS中)。


4.7.2 任務(wù)的執行

軟件或處理器可以使用以下方法之一來(lái)調度執行一個(gè)任務(wù):

▓ 使用CALL指令明確地呼叫一個(gè)任務(wù);

▓ 使用JMP指令明確地跳轉到一個(gè)任務(wù) (Linux內核使用的方式) ;

▓ (由處理器) 隱含地呼叫一個(gè)中斷控制碼處理任務(wù);

▓ 隱含地呼叫一個(gè)異??刂拼a處理任務(wù);

所有這些排程調度任務(wù)執行的方法都會(huì )使用一個(gè)指向任務(wù)門(mén)或任務(wù)TS段的選擇符號來(lái)確定一個(gè)任務(wù)。當使用CALL或JMP指令調度一個(gè)任務(wù)時(shí),指令中的選擇符號既可以直接選擇任務(wù)的TSS,也可以選擇存放有TSS選擇符號的任務(wù)門(mén)。當調度一個(gè)任務(wù)來(lái)處理一個(gè)中斷或異常時(shí),那麼IDT中該中斷或異常表項必須是一個(gè)任務(wù)門(mén),並且其中含有中斷或異常處理任務(wù)的TSS選擇符號。

當調度排程一個(gè)任務(wù)執行時(shí),當前正在執行任務(wù)和調度任務(wù)之間會(huì )自動(dòng)地發(fā)生任務(wù)切換操作。在任務(wù)切換期間,當前執行任務(wù)的執行環(huán)境 (稱(chēng)為任務(wù)的狀態(tài)或上下文)會(huì )被保存到它的TSS中並且暫停該任務(wù)的執行。此后新調度任務(wù)啊下文會(huì )被載入進(jìn)處理器中,並且從載入的EIP指向的指令處開(kāi)始執行新任務(wù)。

如果當前執行任務(wù)(呼叫者) 呼叫了被調度的新任務(wù)(被呼叫者),那么呼叫者的TSS段選擇符號會(huì )被保存在被呼叫者TSS中,從而提供了一個(gè)返回呼叫者的鏈結。對於所有80X86處理器,任務(wù)是不可遞回呼叫的,即任務(wù)不能呼叫或跳轉到自己。

中斷或異??梢酝高^(guò)切換到一個(gè)任務(wù)來(lái)進(jìn)行處理。在這種情況下,處理器不僅能夠執行任務(wù)切換來(lái)處理中斷或異常,而且也會(huì )在中斷或異常處理任務(wù)返回時(shí)自動(dòng)地切換回被中斷的任務(wù)中去。這種操作方式可以處理在中斷任務(wù)執行時(shí)發(fā)生的中斷。

作為任務(wù)切換操作的一部份,處理器也會(huì )切換到另一個(gè)LDT,從而允許每個(gè)任務(wù)對基於LDT的段具有不同邏輯到實(shí)體位址的映射。同時(shí),頁(yè)目錄寄存器CR3也會(huì )在切換時(shí)被重新載入,因此每個(gè)任務(wù)可以有自己的一套頁(yè)表。這些保護措施能夠用來(lái)隔絕各個(gè)任務(wù)並且防止它們相互干擾。

使用處理器的任務(wù)管理功能來(lái)處理多工應用足任選的。我們也可以使用軟件來(lái)實(shí)現多工,使得每個(gè)軟體定義的任務(wù)在一個(gè)80X86體系結構的任務(wù)上下文中執行。
4.7.3任務(wù)管理資料結構

處理器定義了一下一些支援多工的寄存器和資料結構:

▓ 任務(wù)狀態(tài)段TSS;

▓ TSS描述符號;

▓ 任務(wù)暫存器TR;

▓ 任務(wù)門(mén)描述符號;

▓ 標志寄存器EFLAGS中的NT標志。

使用這些資料結構,處理器可以從一個(gè)任務(wù)切換到另一個(gè)任務(wù),同時(shí)保存原任務(wù)的的上下文,以允許任務(wù)重新執行。


任務(wù)狀態(tài)段

用於恢復一個(gè)任務(wù)執行的處理器狀態(tài)資訊被保存在一類(lèi)稱(chēng)為任務(wù)狀態(tài)段TSS(Task state segment) 的段中。圖4-34給出了32位元CPU使用的TSS的格式。TSS段中各欄位可分成兩大類(lèi):動(dòng)態(tài)欄位和靜態(tài)欄位。







⑴ 動(dòng)態(tài)欄位。當任務(wù)切換而被掛起時(shí),處理器會(huì )更新動(dòng)態(tài)欄位的內容。這些欄位包括:

● 通用寄存器欄位。用于保存EAX、ECX、EDX、EBX、ESP、EBP、ESI和EDI寄存器的內容。

● 段選擇符號欄位。用于保存ES、CS、SS、DS、FS和GS段寄存器的內容。

● 堆棧寄存器EFLAGS欄位。在切換之間保存EFLAGS。

● 指令指標EIP欄位。在切換之前EIP寄存器內容。

● 先前任務(wù)連接欄位。含有前一個(gè)任務(wù)TSS段選擇符號(在呼叫、中斷或異常激發(fā)的任務(wù)切換時(shí)更新)。該欄位(通常也稱(chēng)為后連接欄位(Back link field))允許任務(wù)使用IRET指令切換到前一個(gè)任務(wù)。








⑵ 靜態(tài)欄位。處理器會(huì )讀取靜態(tài)欄位的內容,但通常不會(huì )改變它們。這些欄位內容是在任務(wù)被建立時(shí)設置的。這些欄位有:

● LDT段選擇符號欄位。含有仟務(wù)的LDT段的選擇符號。

● CR3控制暫存器欄位。含行任務(wù)使用的頁(yè)目錄物理基底位址??刂萍拇嫫鰿R3通常也被稱(chēng)為頁(yè)目錄基底位址:寄存器PDBR(Page directory base register)。

● 特權級0、l和2的堆棧指標欄位。這些堆棧指標由堆棧段選擇符號(SS0、SS1和SS2)和堆棧中偏移量指標(ESP0、ESPl和ESP2)組成。注意,對於指定的一個(gè)任務(wù),這些欄位的值是不變的。岡此,如果任務(wù)中發(fā)生堆棧切換,寄存器SS和ESP的內容將會(huì )改變。

● 除錯陷阱(Debug Trap)T標志欄位。該欄位位于位元組0x64 Bit0處。當設置了該位時(shí),處理器切換到該任務(wù)的操作將產(chǎn)生一個(gè)錯異常。

● I/O點(diǎn)陣固基底位址欄位。該欄位含有從TSS段開(kāi)始處到I/O許可點(diǎn)陣圖處的16位偏栘值。

如果使用了分頁(yè)機制,那麼在任務(wù)切換期間應該避免處理器操作的TSS段中(前104位元組中)含有記憶體頁(yè)邊界。如果TSS這部分包含記憶體頁(yè)邊界,那麼該邊界處兩邊的頁(yè)面都必須同時(shí)并且連續存于記憶體中。另外,如果使用了分頁(yè)機制,那麼與原任務(wù)TSS和新任務(wù)TSS相關(guān)的頁(yè)面,以及對應的描述符號表表項應該是可讀寫(xiě)的。


TSS描述符號

與其他段一樣,任務(wù)狀態(tài)段TSS也是使用段描述符號來(lái)定義。圖4-35給出了TSS描述符號的格式。TSS描述符號只能存放在GDT中。







類(lèi)型欄位TYPE中的忙碌標志B用於指明任務(wù)是否處於忙狀態(tài)。忙狀態(tài)的任務(wù)是當前正在執行的任務(wù)或等待執行(被掛起)的任務(wù)。值為0b1001的類(lèi)型欄位表明任務(wù)處於非活動(dòng)狀態(tài):而值為0b1011的類(lèi)型欄位表示任務(wù)正忙。任務(wù)是不可以遞回執行的,因此處理器使用忙標志B來(lái)檢測任何企圖對被中斷執行任務(wù)的呼叫。

其中基底位址、段限長(cháng)、描述符號特權級DPL、顆粒度G和存在位具有與資料段描述符號中相應欄位同樣的功能。當G=0時(shí),限長(cháng)欄位必須具有等於或大於103(0x67)的值,即TSS段的最小長(cháng)度不得小於104位元組。如果TSS段中還包含I/O許可點(diǎn)陣圖,那麼,TSS段長(cháng)度需要大一些。另外,如果作業(yè)系統還想在TSS段中存放其他一些資訊,那麼TSS段就需要更大的長(cháng)度。

使用呼叫或跳轉指令,任何可以存取TSS描述符號的程式都能夠造成任務(wù)切換??梢源嫒SS描述符號的程式其CPL數值必須小於或等於TSS描述符號的DPL。在大多數系統中,TSS描述符號的DPL欄位值應該設置成小於3。這樣,只有具有特權級的軟體可以執行任務(wù)切換操作。然而在多工應用中,某些TSS的DPL可以設置成3,以使得在用戶(hù)特權級上也能進(jìn)行任務(wù)切換操作。

可存取一個(gè)TSS段描述符號並沒(méi)有給程式讀寫(xiě)該描述符號的能力。若想讀或修改一個(gè)TSS段描述符號,可以使用映射到記憶體相同位置的資料段描述符號(即別名描述符號)來(lái)操作。把TSS描述符號載入進(jìn)任何段寄存器將導致一個(gè)異常。企圖使用Tl標志置位元的選擇符號(即當前LDT中的選擇符號)來(lái)存取TSS段也將導致異常。


任務(wù)寄存器

任務(wù)暫存器TR(Task Register)中存放著(zhù)16位元的段選擇符號以及當前任務(wù)TSS段的整個(gè)描述符號(不可見(jiàn)部分)。這些資訊是從GDT中當前任務(wù)的TSS描述符號中復制過(guò)來(lái)的。處理器使用任務(wù)寄存器TR的不可見(jiàn)部分來(lái)緩沖TSS段描述符號內容。

指令LTR和STR分別用於載入和保存任務(wù)寄存器的可見(jiàn)部分,即TSS段選擇符號。LTR指令只能被特權級。的程式執行。LTR指令通常用於系統初始化期間給TR寄存器載入初值(例如,任務(wù)0的、TSS段選擇符號),隨后在系統執行期間,TR的內容會(huì )在任務(wù)切換時(shí)自動(dòng)地被改變。


任務(wù)門(mén)描述符號

任務(wù)門(mén)描述符號(Task gate descriptor)提供對一個(gè)任務(wù)間接、受保護地的真的參照引用,其格式見(jiàn)圖所示。任務(wù)描述符號可以被存放在GDT、LDT或IDT表中。

任務(wù)描述符號中的TSS選擇符號欄位指向GDT中的一個(gè)TSS段描述符號。這個(gè)TSS選擇符號欄位中的RPL域不用。任務(wù)描述符號中的DPL用於在任務(wù)與換時(shí)控制對TSS段的存取。當程式透過(guò)任務(wù)門(mén)呼叫或跳轉到一個(gè)任務(wù)時(shí),程式的CPL以及指向任務(wù)門(mén)的門(mén)選擇符號的RPL值必須小於或等於任務(wù)門(mén)描述符號中的DPL。請注意,當使用任務(wù)門(mén)時(shí),目標TSS段描述符號的DPL忽略不用。

程式可以透過(guò)任務(wù)門(mén)描述符號或者TSS段描述符號來(lái)存取一個(gè)任務(wù)。圖4-36示出了LDT、GDT和IDT表中的任務(wù)門(mén)如何都指向同一個(gè)任務(wù)。








4.7.4任務(wù)切換

處理器可使用一下4種方式之一執行任務(wù)切換操作:

⑴ 當前任務(wù)對GDT中的TSS描述符號執行JMP或CALL指令;

⑵ 當前任務(wù)對GDT或LDT中的任務(wù)門(mén)描述符號執行JMP或CALL指令;

⑶ 中斷或異常向量指向IDT表中的任務(wù)門(mén)描述符號;

⑷ 當EFLAGS中的NT標志設置位元時(shí)當前任務(wù)執行IRET指令。


JMP、CALL和IRET指令以及中斷和異常都是處理器的普通機制,可用于不發(fā)生任務(wù)切換的環(huán)境中。對於TSS描述符號或任務(wù)門(mén)的引用(當呼叫或跳轉駕一個(gè)任務(wù)) ,或者NT標志的狀態(tài)(當執行IRET指令時(shí))確定了是否會(huì )發(fā)生任務(wù)切換。

進(jìn)行任務(wù)切換時(shí),JMP或CALL指令能夠把控制轉移到TSS描述符號或任務(wù)門(mén)上。使用這兩種方式的作用相同,都會(huì )導致處理器把控制轉移到指定任務(wù)中。見(jiàn)圖4-37所示。






當切換到一個(gè)新任務(wù)時(shí),處理器會(huì )執行一下操作:

⑴ 從作為JMP或CALL指令運算元中,或者從任務(wù)門(mén)中,或者從當前TSS的前一任務(wù)鏈結欄位(對於由IRET引起的任務(wù)切換)中取得新任務(wù)的TSS段選擇符號。

⑵ 檢查當前任務(wù)是否允許切換到新任務(wù)。把資料存取特權級規則應用到JMP和CALL指令上。當前任務(wù)的CPL和新任務(wù)段選擇符號的RPL必須小於或等於TSS段描述符號的DPL,或者引用的是一個(gè)任務(wù)門(mén)。無(wú)論目標任務(wù)門(mén)或TSS段描述符號的DPL是何值,異常、中斷(除了使用INT n指令產(chǎn)生的中斷)和IRET一指令都允許執行任務(wù)切換。對於INT n指令產(chǎn)生的中斷將檢查DPL。

⑶ 檢查新任務(wù)的TSS描述符號是標注為存在的(P=1),並且TSS段長(cháng)度有效(大於0x67)。當試圖執行會(huì )產(chǎn)生錯誤的指令時(shí),都會(huì )恢復對處理器狀態(tài)的任何改變。這使得異常處理行程的返回位址指向出錯指令,而非出錯指令隨后的一條指令。因此異常處理行程可以處理出錯條件並且重新執行任務(wù)。異常處理行程的介入處理對應用程式來(lái)說(shuō)是完全透明的。



⑷ 如果任務(wù)切換產(chǎn)生自JMP或1RET指令,處理器就會(huì )把當前任務(wù)(老任務(wù))TSS描述符號中的忙標志B重定;如果任務(wù)切換是由CALL指令、異?;蛑袛喈a(chǎn)生,則忙標志B不動(dòng)。

⑸ 如果任務(wù)切換由IRET產(chǎn)生,則處理器會(huì )把臨時(shí)保存的EFLAGS映射中的NT標志重定;如果任務(wù)切換由CALL、JMP指令或者異?;蛑袛喈a(chǎn)生,則不用改動(dòng)上述NT標志。


⑹ 把當前任務(wù)的狀態(tài)保存到當前任務(wù)的TSS中。處理器會(huì )從任務(wù)寄存器中取得當前任務(wù)TSS的基底位址,並且把一下寄存器內容復制到當前TSS中:所有通用寄存器、段寄存器中的段選擇符號、標志寄存器EFLAGS以及指令指標EIP。

⑺ 如果任務(wù)切換是由CALL指令、異?;蛑袛喈a(chǎn)生,則處理器就會(huì )把從新任務(wù)中載入的EFLAGS中的NT標志置位元。如果任務(wù)切換產(chǎn)生自JMP或IRET指令,就不改動(dòng)新載入EFLAGS中的標志。

⑻ 如果任務(wù)切換由CALL、JMP指令或者異?;蛑袛喈a(chǎn)生,處理器就會(huì )設置新任務(wù)TSS描述符號中的忙標志B。如果任務(wù)切換由IRET產(chǎn)生,則不去改動(dòng)B標志。

⑼ 使用新任務(wù)TSS的段選擇符號和描述符號載入任務(wù)寄存器TR(包括隱藏部分)。設置CR0寄存器的TS標志。

⑽ 把新任務(wù)的TSS狀態(tài)載入進(jìn)處理器。這包括LDTR寄存器、PDBR(CR3)寄存器、
EFLAGS寄存器、EIP寄存器以及通用寄存器和段選擇符號。在此期間檢測到的任何錯誤都將出現在新任務(wù)的上下文中。

⑾ 開(kāi)始執行新任務(wù)(對於異常處理行程,新任務(wù)的第一條指令顯現出還沒(méi)有執行)。


當成功地進(jìn)行了任務(wù)切換操作,當前執行任務(wù)的狀態(tài)總是會(huì )被保存起來(lái)。當任務(wù)恢復執行時(shí),任務(wù)將從保存的EIP指向的指令處開(kāi)始執行,並且所有寄存器都恢復到任務(wù)掛起時(shí)的值。

當執行任務(wù)切換時(shí),新任務(wù)的特權級與原任務(wù)的特權級沒(méi)有任何關(guān)系。新著(zhù)任務(wù)在CS寄存器的CPL欄位指定的特權級上開(kāi)始執行。因為各個(gè)任務(wù)透過(guò)它們獨立的位址空間和TSS段相互隔絕,並且特權級規則已經(jīng)控制對TSS的存取,所以在任務(wù)切換時(shí)軟件不需要再進(jìn)行特權級檢查。

每次任務(wù)切換都會(huì )設置控制寄存器CR0中的任務(wù)切換標志TS。該標志對系統軟件非常有用。系統軟體可用TS標志來(lái)協(xié)調處理器和浮點(diǎn)輔助運算器之間的操作。TS標志指明輔助運算器中的上下文可能與當前任務(wù)的不同。


4.7.5 任務(wù)鏈

TSS的前一任務(wù)連接(Backlink)欄位以及EFLAGS中的NT標志用於返回到前一個(gè)任務(wù)操作中。NT標志指出了當前執行的任務(wù)是否是巢狀嵌在另一個(gè)任務(wù)中執行,并且當前任務(wù)的前一任務(wù)連接欄位中存放著(zhù)巢狀層中更高層任務(wù)的TSS選擇符號,若有的話(huà)(見(jiàn)圖4-38所示)。







當CALL指令、中斷或異常造成任務(wù)切換,處理器把當前TSS段的選擇符號復制到新任務(wù)TSS段的前一任務(wù)鏈結欄位中,然后在EFLAGS中設置NT標志。NT標志指明TSS的前一任務(wù)鏈結欄位中存放有保存的TSS段選擇符號。如果軟件使用IRET指令掛起新任務(wù),處理器就會(huì )使用前一任務(wù)鏈接欄位中值和NT標志返回到前一任務(wù)。也即如果NT標志是置位元的話(huà),處理器會(huì )切換到前一任務(wù)鏈接欄位的任務(wù)去執行。


注意,當任務(wù)切換是由JMP指令造成,那麼新任務(wù)就不會(huì )是巢狀的。也即,NT標志會(huì )被設置為0,並且不使用前一任務(wù)鏈結欄位。JMP指令用於不希望出現巢狀的任務(wù)切換中。

表4-9總結了任務(wù)切換期間,忙標志B(在TSS段描述符號中)、NT標志、前一任務(wù)鏈結欄位和TS標志(在CR0中)的用法。注意,執行於任何特權級上的程式都可以修改NT標志,因此任何程式都可以設置NT標志並執行IRET指令。這種做法會(huì )讓處理器去執行當前任務(wù)TSS的前一任務(wù)鏈結欄位指定的任務(wù)。為了避免這種偽造的任務(wù)切換執行成功,作業(yè)系統應該把每個(gè)TSS的該欄位初始化為0。






4.7.6 任務(wù)位址空間的

任務(wù)的位址空間由任務(wù)能夠存取的段構成。這些段包括代碼段、資料段、堆棧段、TSS中引用的系統段以及任務(wù)代碼能夠存取的任何其他段。這些段都被映射到處理器的線(xiàn)性位址空間中,並且隨后被直接地或者透過(guò)分頁(yè)機制映射到處理器的實(shí)體位址空間中。

TSS中的LDT欄位可以用於給出每個(gè)任務(wù)自己的LDT 。對於一個(gè)給定的任務(wù),透過(guò)把與任務(wù)相關(guān)的所有段描述符號放入LDT中,任務(wù)的位址空間就可以與其他任務(wù)的隔絕開(kāi)來(lái)。

當然,幾個(gè)任務(wù)也可以使用同一個(gè)LDT。這是一種簡(jiǎn)單而有效的允許某些任務(wù)互相通信或控制的方法,而無(wú)須拋棄整個(gè)系統的保護屏障。


因為所有任務(wù)都可以存取GDT,所以也同樣可以建立透過(guò)此表存取的共用段。

如果開(kāi)啟了分頁(yè)機制,則TSS中的CR3暫存器欄位可以讓每個(gè)任務(wù)有它自己的頁(yè)表?;蛘?,幾個(gè)任務(wù)能夠共用相同頁(yè)表集。


把任務(wù)映射到線(xiàn)性和實(shí)體位址空間

有兩種方法可以把任務(wù)映射到線(xiàn)性位址空間和實(shí)體位址空間:

▓ 所有任務(wù)共用一個(gè)線(xiàn)性到實(shí)體位址空間的映射。當沒(méi)有開(kāi)啟分頁(yè)機制時(shí),就只能使用這個(gè)辦法。不開(kāi)啟分頁(yè)時(shí),所有線(xiàn)性位址映射到相同的實(shí)體位址上。當開(kāi)啟了分頁(yè)機制,那麼透過(guò)讓所有任務(wù)使用一個(gè)頁(yè)目錄,我們就可以使用這種從線(xiàn)性到實(shí)體位址空間的映射形式。如果支援需求頁(yè)虛擬儲存技術(shù),則線(xiàn)性位址空間可以超過(guò)現有實(shí)體位址空間的大小。

▓ 每個(gè)任務(wù)有自己的線(xiàn)性位址空間,並映射到實(shí)體位址空間。透過(guò)讓每個(gè)任務(wù)使用不同的頁(yè)目錄,我們就可以使用這種映射形式。因為每次任務(wù)切換都會(huì )載入PDBR (控制暫存器CR3) ,所以每個(gè)任務(wù)可以有不同的頁(yè)目錄。

不同任務(wù)的線(xiàn)性位址空間可以映射到完全不同的實(shí)體位址上。如果不同頁(yè)目錄的條目(表項)指向不同的頁(yè)表,而且頁(yè)表也指向實(shí)體位址中不同的頁(yè)面上,那麼各個(gè)任務(wù)就不會(huì )任何實(shí)體位址。

對於映射任務(wù)線(xiàn)性位址空間的這兩種方法,所有任務(wù)的TSS都必須存放在共用的實(shí)體位址空間區域中,並且所有任務(wù)都能存取這個(gè)區域。為了讓處理器執行任務(wù)切換而讀取或更新TSS時(shí),TSS位址的映射不會(huì )改變,就需要使用這種映射方式。GDT所映射的線(xiàn)性位址空間也應該映射到共用的實(shí)體位址空間中。否則就喪失了GDT的作用。


任務(wù)邏輯位址空間

為了在任務(wù)之間共用資料,可使用下列方法之一來(lái)為資料段建立共用的邏輯到實(shí)體位址空間的映射:

透過(guò)使用GDT中的段描述符號。所有任務(wù)必須能夠存取GDT中的段描述符號。如果GDT中的某些段描述符號指向線(xiàn)性位址空間中的一些段,並且這些段被映射到所有任務(wù)共用的實(shí)體位址空間中,那麼所有任務(wù)部可以共用這些段中的代碼和資料。

透過(guò)共用的LDT。兩個(gè)或多個(gè)任務(wù)可以使用相同的LDT,如果它們TSS中LDT欄位指向同一個(gè)LDT。如果一個(gè)共用的LDT中某些段描述符號指向映射到實(shí)體位址空間公共區域的段,那麼共用LDT的所有任務(wù)可以共用這些段中的所有代碼和資料。這種共用方式要比透過(guò)GDT來(lái)共用好,因為這樣做可以把共用局限於指定的一些任務(wù)中。系統中有不同LDT的其他任務(wù)沒(méi)有存取這些共用段的權利。

透過(guò)映射到線(xiàn)性位址空間公共位址區域的不同LDT中的段描述符號。如果線(xiàn)性位址空間中的這個(gè)公共區域對每個(gè)任務(wù)都映射到實(shí)體位址空間的相同區域,那麼這些段描述符號就允許任務(wù)共用這些段。這樣的段描述符號通常稱(chēng)為別名段。這個(gè)共用方式要此上面給出的方式來(lái)得更好,因為L(cháng)DT中的其他段描述符號可以指向獨立的未共用線(xiàn)性位址區域。


4.8 保護模式程式初始化

我們知道,80X86可以工作在幾種模式下。當機器上電或硬體重定時(shí),處理器工作在8086處理器相容的真實(shí)位址模式下,並且從實(shí)體位址0xFFFFFFF0處開(kāi)始執行軟體初始化代碼(通常在EPROM中)。軟體初始化代碼首先必須設置基本系統功能操作必要的資料結構資訊,例如處理中斷和異常的實(shí)模式IDT表(即中斷向量表)。如果處理器將仍然工作在實(shí)模式下,軟體必須載入作業(yè)系統模組和相應資料以允許應用程式能在實(shí)模式下可靠地執行。如果處理器將要工作在保護模式下,那麼作業(yè)系統軟體就必須載入保護模式操作必要的資料結構資訊
,然后切換到保護模式。


4.8.1 進(jìn)入保護模式時(shí)的初始化操作

保護模式所需要的一些資料結構由處理器記憶體管理功能確定。處理器支援分段模型,可以使用從單個(gè)、統一的位址空間平坦模型到每個(gè)任務(wù)都具有幾個(gè)受保護位址空間的高度結構化的多段模型。分頁(yè)機制能夠用來(lái)部分在記憶體、部分在磁片上的大型資料結構資訊。這兩種位址轉換形式都需要作業(yè)系統在記憶體中為記憶體管理硬體設置所要求的資料結構。因此在處理器能夠被切換到保護模式下執行之前,作業(yè)系統載入和初始化軟(bootsect.s、setup.s和head.s)必須在記憶體中先設置好保護模式下使用的資料結構的基本資訊。這些資料結構包括
以下幾種:

▓ 保護模式中斷描述符號表IDT;

▓ 全域描述符號表GDT;

▓ 任務(wù)狀態(tài)段TSS;

▓ 區域描述符號表LDT;

▓ 若使用分頁(yè)機制,則起碼需要設置一個(gè)頁(yè)目錄和一個(gè)頁(yè)表;

▓ 處理器切換到保護模式下執行的代碼段;

▓ 含有中斷和異常處理程式的代碼模組。

在能夠切換到保護模式之前,軟體初始化代碼還必須設置以下系統寄存器:

▓ 全域描述符號表基底位址寄存器GDTR;

▓ 中斷描述符號表基底位址寄存器IDTR;

▓ 控制寄存器CRl- -CR3;

在初始化了這些資料結構、代碼模組和系統暫存器之后,透過(guò)設置CR0寄存器的保護模式標志PE(位元0) ,處理器就可以切換到保護模式下執行。


保護模式系統結構表

軟體初始化期間在記憶體中設置的保護模式系統表主要依賴(lài)於作業(yè)系統將要支援的記憶體管理類(lèi)型:平坦的、平坦並支援分頁(yè)的、分段的或者分段並支援分頁(yè)的。

為了實(shí)現無(wú)分頁(yè)的平坦記憶體模型,軟體初始化代碼必須起碼設置具有一個(gè)代碼段和一個(gè)資料段的GDT表。當然GDT表第l項還需要放置一個(gè)空描述符號。堆??梢苑胖迷谄胀勺x寫(xiě)資料段中,因此並不需要專(zhuān)門(mén)的堆棧描述符號。支援分頁(yè)機制的平坦記憶體模型還需要一個(gè)頁(yè)目錄和至少一個(gè)頁(yè)表。在可以使用GDT表之前,必須使用LGDT指令把GDT表的基底位址和長(cháng)度值載入到GDTR寄存器中。

而多段模型則還需要用於作業(yè)系統的其他段,以及用於每個(gè)應用程式的段和LDT表段。LDT表的段描述符號要求存放在GDT表中。某些作業(yè)系統會(huì )為應用程式另行分配新段和新的LDT段。這種做法為動(dòng)態(tài)程式設計環(huán)境提供了最大靈活性,例如Linux作業(yè)系統就使用了這種方式。像程序控制器那樣的嵌入式系統可以預先為固定數量的應用程式分配固定數量的段和LDT,這是實(shí)現即時(shí)系統軟件環(huán)境結構的一種簡(jiǎn)單而有效的方法。


保護模式異常和中斷初始化

軟體初始化代碼必須設置一個(gè)保護模式IDT,其中最少需要含有處理器可能產(chǎn)生的每個(gè)異常向量對應的門(mén)描述符號。如果使用了中斷或陷阱門(mén),那麼門(mén)描述符號可以都指向包含中斷和異常處理行程的同一個(gè)代碼段。若使用了任務(wù)門(mén),那麼每個(gè)使用任務(wù)門(mén)的異常處理行程都需要一個(gè)TSS以及相關(guān)的代碼、資料和堆棧段。如果允許硬件產(chǎn)生中斷,那麼必須在IDT中為一個(gè)或多個(gè)中斷處理行程設置門(mén)描述符號。

在可以使用IDT之前,必須使用LIDT指令把IDT表基底位址和長(cháng)度載入到IDTR寄存器中。


分頁(yè)機制初始化

分頁(yè)機制由控制寄存器CR0中的PG標志設置。當這個(gè)標志被清除0時(shí)(即硬體重定時(shí)的狀態(tài)),分頁(yè)機制被關(guān)閉:當設置了PG標志,就開(kāi)啟分頁(yè)機制。在設置PG標志之前,必須先初始化以下資料結構和寄存器:

▓ 軟體必須在實(shí)體記憶體中建立至少一個(gè)頁(yè)目錄和一個(gè)頁(yè)表。如果頁(yè)目錄表中含有指向自身的目錄項時(shí),可以不使用頁(yè)表。此時(shí)頁(yè)目錄表和頁(yè)表被存放在同一頁(yè)面中。

▓ 把頁(yè)目錄表的物理基底位址載入到CR3寄存器中(也稱(chēng)為PDBR寄存器)。

▓ 處理器處於保護模式下。如果滿(mǎn)足所有其他限制,則PG和PE標志可以同時(shí)設置。
為保持相容性,設置PG標志(以及PE標志)時(shí)必須遵守以下規則:

▓ 設置PG標志的指令應該立刻跟隨一條JMP指令。MOV CR0指令后面的JMP指令會(huì )改變執行流,所以它會(huì )清空80X86處理器已經(jīng)取得或已解碼的指令。然而,Pentium及以上處理器使用了分支目標緩沖器BTB(Branch Target Buffer)為分支代碼定向,因此減去了為分支指令更新佇列的需要。
▓ 設置PG標志到跳轉指令JMP之間的代碼必須來(lái)自對等映射(即跳轉之前的線(xiàn)性位址與開(kāi)啟分頁(yè)后的實(shí)體位址相同)的一個(gè)頁(yè)面上。


多工初始化

如果將要使用多工機制,並且/或者允許改變特權級,那麼軟件初始化代碼必須至少設置一個(gè)TSS及相應的TSS段描述符號(因為特權級0、l和2的各堆棧段指標需要從TSS中取得) 。在建立TSS描述符號時(shí)不要將其標注為忙(不要設置忙標志) ,該標志僅由處理器在執行任務(wù)切換時(shí)設置。與LDT段描述符號相同,TSS的描述符號也存放在GDT中。

在處理器切換到保護模式之后,可以用LTR指令把TSS段描述符號的選擇符號載入到任務(wù)暫存器TR中。這個(gè)指令會(huì )把TSS標記成忙狀態(tài)(B=1) ,但是並不執行任務(wù)切換操作。然后處理器可以使用這個(gè)TSS來(lái)定位特權級0、1和2的堆棧。在保護模式中,軟件進(jìn)行第一次任務(wù)切換之前必須首先載入TSS段的選擇符號,因為任務(wù)切換會(huì )把當前任務(wù)狀態(tài)復制到該TSS中。

在LTR指令執行之后,隨后對任務(wù)暫存器的操作由任務(wù)切換進(jìn)行。與其他的段和LDT類(lèi)似,TSS段和TSS段描述符號可以預先設置好,也可以在需要時(shí)才進(jìn)行設置。


4.8.2模式切換

為了讓處理器工作在保護模式下,必須從真實(shí)位址模式下進(jìn)行模式切換操作。一旦進(jìn)入保護模式,軟件通常不會(huì )再需要回到真實(shí)位址模式。為了還能執行為真實(shí)位址模式編制的程式,通常在虛擬-8086模式中執行比再切換回實(shí)模式下執行更為方便。


切換到保護模式

在切換到保護模式之前,必須首先載入一些起碼的系統資料結構和代碼模組。一旦建立了這些系統表,軟件初始化代碼就可以切換到保護模式中。透過(guò)執行在CR0寄存器中設置PE標志的MOV CR0指令,我們就可以進(jìn)行保護模式。(在同一個(gè)指令中,CR0的PG標志可用于開(kāi)啟分頁(yè)機制。)剛進(jìn)入保護模式中執行時(shí),特權級是0。為了保證程式的相容性,切換操作應該按照以下步驟進(jìn)行:

⑴ 禁止中斷。使用CLI指令可以禁止可遮罩硬體中斷。NMI會(huì )由硬體電路來(lái)禁止。同時(shí)軟體應該確保在模式切換操作期間不產(chǎn)生異常和中斷。

⑵ 執行LGDT指令把GDT表的基底位址載入進(jìn)GDTR暫存器。

⑶ 執行在控制暫存器CR0中設置PE標志(可選同時(shí)設置PG標志)的MOV CR0指令。

⑷ 在MOV CR0指令之后立刻執行一個(gè)遠跳轉JMP或遠呼叫CALL指令。這個(gè)操作通常是遠跳轉到或遠呼叫指令流中的下一條指令。

⑸ 若要使用區域描述符號表,則執行LLDT指令把LDT段的選擇符號載入到LDTR寄存器中。
⑹ 執行LTR指令,用初始保護模式任務(wù)的段選擇符號或者可寫(xiě)記憶體區域的段描述符號載入任務(wù)寄存器TR。這個(gè)可寫(xiě)記憶體區域用於在任務(wù)切換時(shí)存放任務(wù)的TSS資訊。

⑺ 在進(jìn)入保護模式后,段寄存器仍然含有在真實(shí)位址模式時(shí)的內容。第4步中的JMP或CALL指令會(huì )重置CS寄存器。執行以下操作之一可以更新其余段寄存器的內容:其余段寄存器的內容可透過(guò)重新載入或切換到一個(gè)新任務(wù)來(lái)更新。

⑻ 執行LIDT指令把保護模式IDT表的基底位址和長(cháng)度載入到IDTR寄存器中。

⑼ 執行STI指令開(kāi)啟可遮罩硬體中斷,並且執行必要的硬體操作開(kāi)啟NMI中斷。


另外,MOV CR0指令之后緊接著(zhù)的JMP或CALL指令會(huì )改變執行流。如果開(kāi)啟了分頁(yè)機制,那麼MOV CR0指令到JMP或CALL指令之間的代碼必須來(lái)自對等映射(即跳轉之前的線(xiàn)性位址與開(kāi)敔分頁(yè)后的實(shí)體位址相同)的一個(gè)頁(yè)面上。而JMP或CALL指令跳轉到的目標指令並不需要處於對等映射頁(yè)面上。


切換回真實(shí)位址模式

若想切換回真實(shí)位址模式,則可以使用MOV CR0指令把控制暫存器CR0中的PE標志清0。重新進(jìn)入真實(shí)位址模式的行程應該按照以下步驟進(jìn)行:

⑴ 禁止中斷。使用CLI指令可以禁止可遮罩硬件中斷。NMI會(huì )由硬件電路來(lái)禁止。同時(shí)
軟體應該確保在模式切換操作期間不產(chǎn)生異常和中斷。

⑵ 如果已開(kāi)啟分頁(yè)機制,那麼需要執行:

● 把程式的控制轉移到對等映射的線(xiàn)性位址處(即線(xiàn)性位址等於實(shí)體位址)’

● 確保GDT和IDT在對等映射的頁(yè)面上。

● 清除CR0中的PG標志。

● CR3寄存器中設置為0x00,用於更新TLB緩沖。

⑶ 把程式的控制轉移到長(cháng)度為64KB(0xFFFF)的可讀段中。這步操作使用實(shí)模式要求的段長(cháng)度載入CS寄存器。

⑷ 使用指向含有以下設置值的描述符號的選擇符號來(lái)載入SS、DS、ES、FS和GS段寄存器。

● 段限長(cháng)Limit:64KB

● 位元組顆粒度(G=0)。

● 向上擴展(E=0)。

● 可寫(xiě)(W=1)。

● 存在(P=I)。

⑸ 執行LIDT指令來(lái)指向在1 MB實(shí)模式位址范圍內的真實(shí)位址模式中斷表。

⑹ 清除CR0中的PE標志來(lái)切換到真實(shí)位址模式。

⑺ 執行一個(gè)遠跳轉指令跳轉到一個(gè)實(shí)模式程式中。這步操作會(huì )更新指令佇列並且為CS寄存器載入合適的基底位址和存取許可權值。

⑻ 載入真實(shí)位址模式程式碼會(huì )使用的SS、DS、ES、FS和GS寄存器。

⑼ 執行STI指令開(kāi)啟可遮罩硬件中斷,並且執行必要的硬件操作開(kāi)啟NMI中斷。


4.9 一個(gè)簡(jiǎn)單的多工內核實(shí)例

作為對本章和前幾章內容的總結,本節完整描述了一個(gè)簡(jiǎn)單多工內核的設計和實(shí)現方法。這個(gè)內核示例中包含兩個(gè)特權級3的用戶(hù)任務(wù)和一個(gè)系統呼叫中斷行程。我們首先說(shuō)明這個(gè)簡(jiǎn)單內核的基本結構和載入執行的基本原理,然后描述它是如何被載入進(jìn)機器RAM記憶體中以及兩個(gè)任務(wù)是如何進(jìn)行切換執行的。最后我們給出實(shí)現這個(gè)簡(jiǎn)單內核的來(lái)源程式:開(kāi)機啟動(dòng)引導程式boot.s和保護模式多工內核程式head.s。


4.9.1 多工程式結構和工作原理

本節給出的內核實(shí)例由2個(gè)檔構成。一個(gè)是使用as86語(yǔ)言編制的開(kāi)機啟動(dòng)程式boot.s,用於在電腦系統加電時(shí)從啟動(dòng)碟上把內核代碼載入到記憶體中;另一個(gè)是使用GNU as組合語(yǔ)言編制的內核程式head.s,其中實(shí)現了兩個(gè)執行在特權級3上的任務(wù)在時(shí)鐘中斷控制下相互切換執行,並且還實(shí)現了在螢幕上顯示字元的一個(gè)系統呼叫。我們把這兩個(gè)任務(wù)分別稱(chēng)為任務(wù)A和任務(wù)B(或任務(wù)0和任務(wù)1),它們會(huì )呼叫這個(gè)顯示系統呼叫在螢幕上分別顯示出字元‘A’和‘B’直到每個(gè)10毫秒切換到另一個(gè)任務(wù)。任務(wù)A連續回圈地呼叫系統呼叫在螢幕上顯示字元‘A’;任務(wù)B則一直顯示字元‘B’。若要終止這個(gè)內核實(shí)例程式,則需要重新啟動(dòng)機器,或者關(guān)閉執行的模擬PC執行環(huán)境軟件。

Boot.s程式編譯出的代碼共512位元組,將被存放在軟碟映射檔的第一個(gè)磁區中,見(jiàn)圖4-39所示。 PC機在加電啟動(dòng)時(shí),ROM BIOS中的程式會(huì )把啟動(dòng)盤(pán)上第一個(gè)磁區載入到實(shí)體記憶體0x7c00(31KB)位置開(kāi)始處,並把執行權轉移到0x7c00處開(kāi)始執行boot程式碼。






boot程式的主要功能是把軟碟或映射檔中的head內核代碼載入到記憶體某個(gè)指定位置處,並在設置好臨時(shí)GDT表等資訊后,把處理器設置成執行在保護模式下,然后跳轉到head代碼處去執行內核代碼。實(shí)際上,boot.s程式會(huì )首先利用ROM BIOS中斷int 0x13把軟碟中的head代碼讀入到記憶體0x10000(64KB)位置開(kāi)始處,然后再把這段head代碼移動(dòng)到記憶體0開(kāi)始處。最后設置控制寄存器CR0中的開(kāi)啟保護執行模式標志,並跳轉到記憶體0處開(kāi)始執行head代碼。Boot程式碼在記憶體中移動(dòng)head代碼的示意圖見(jiàn)圖4-40所示。





把head內核代碼移動(dòng)到實(shí)體記憶體0開(kāi)始處的主要原因是為了設置GDT表時(shí)可以簡(jiǎn)單一些,因而也能讓head.s程式盡量短一些。但是我們不能讓boot程式把head代碼從軟碟或映射檔中直接載入到記憶體0處。因為載入操作需要使用ROM BIOS提供的中斷行程,而B(niǎo)IOS使用的中斷向量表正處於記憶體0開(kāi)始的地方,並且在記憶體l Kb開(kāi)始處是BIOS程式使用的資料區,所以若直接把head代碼載入到記憶體0處將使得BIOS中斷行程不能正常執行。當然我們也可以把head代碼載入到記憶體0xl0000處后就直接跳轉到該處執行head代碼,使用這種方式的來(lái)源程式可從oldlinux.org網(wǎng)站下載,見(jiàn)下面說(shuō)明。

Head.s程式執行在32位元保護模式下,其中主要包括初始設置的代碼、時(shí)鐘中斷int 0x08的行程代碼、系統呼叫中斷int 0x80的行程代碼以及任務(wù)A和任務(wù)B等的代碼和資料。其中初始設置工作主要包括:①重新設置GDT表:②設置系統計時(shí)器晶片;③重新設置IDT表並且設置時(shí)鐘和系統呼叫中斷門(mén):④移動(dòng)到任務(wù)A中執行。

在虛擬位址空間中head.s程式的內核代碼和任務(wù)代碼分配圖如圖4-4l所示。實(shí)際上,本內核示例中所有代碼和資料段部對應到實(shí)體記憶體同一個(gè)區域上,即從實(shí)體記憶體0開(kāi)始的區域。GDT中全域代碼段和資料段描述符號的內容都設置為:基底位址為0x0000;段限長(cháng)值為0x07ff 。因為顆粒度為1,所以實(shí)際段長(cháng)度為8MB。而全域顯示資料段被設置成:基底位址為0xb8000:段限長(cháng)值為0x0002,所以實(shí)際段長(cháng)度為8KB,對應到顯示記憶體區域上。







兩個(gè)任務(wù)的在LDT中代碼段和資料段描述符號的內容也都設置為:基底位址為0x0000;段限長(cháng)值為0x03ff,實(shí)際段長(cháng)度為4MB 。因此在線(xiàn)性位址空間中這個(gè)“內核”的代碼和資料段與任務(wù)的代碼和資料段都從線(xiàn)性位址。開(kāi)始並且由於沒(méi)有採用分頁(yè)機制,所以它們都直接對應實(shí)體位址0開(kāi)始處。在head程式編譯出的目標檔中以及最終得到的軟碟映射檔中,代碼和資料的組織形式見(jiàn)圖4-42所示。






由於處於特權級0的代碼不能直接把控制權轉移到特權級3的代碼中執行,但中斷返回操作是可以的,因此當初始化GDT、IDT和定時(shí)晶片結束后,我們就利用中斷返回指令I(lǐng)RET來(lái)啟動(dòng)執行第l個(gè)任務(wù)。具體實(shí)現方法是在初始堆棧init_stack中人工設置一個(gè)返回環(huán)境。即把任務(wù)。的TSS段選擇符號載入到任務(wù)寄存器LTR中、LDT段選擇符號載入到LDTR中以后,把任務(wù)。的用戶(hù)堆棧指標(0x17:init_stack)和代碼指標(0x0f:task0)以及標志寄存器值壓入堆棧。然后執行中斷返回指令I(lǐng)RET。該指令會(huì )彈出堆棧上的堆棧指標作為任務(wù)。用戶(hù)堆棧指標,恢復假設的任務(wù)0的標志寄存器內容,並且彈出堆棧中代碼指標放入CS:EIP寄存器中,從而開(kāi)始執行任務(wù)0的代碼,完成了從特權級0到特權級3代碼的控制轉移。

為了每隔10毫秒切換執行的任務(wù),head.s程式中把計時(shí)器晶片8253的通道0設置成每經(jīng)過(guò)l0毫秒就向中斷控制晶片8259A發(fā)送一個(gè)時(shí)鐘中斷請求信號。PC機的ROM BIOS開(kāi)機時(shí)已經(jīng)在8259A中把時(shí)鐘中斷請求信號設置成中斷向量8,因此我們需要在中斷8的處理行程中執行任務(wù)切換操作。任務(wù)切換的實(shí)現方法是查看current變數中當前執行任務(wù)號。如果current當前是0,就利用任務(wù)l(shuí)的TSS選擇符號作為運算元執行遠跳轉指令,從而切換到任務(wù)l(shuí)中執行,否則反之。

每個(gè)任務(wù)在執行時(shí),會(huì )首先把一個(gè)字元的ASCII碼放入寄存器AL中,然后呼叫系統中斷呼叫int 0x80,而該系統呼叫處理行程則會(huì )呼叫一個(gè)簡(jiǎn)單的字元寫(xiě)到螢幕副程式,把積存器AL中的字元顯示在螢幕上,同時(shí)把字元顯示的螢幕的下一個(gè)位置記錄下來(lái),作為下一次顯示字元的螢幕位置。在顯示過(guò)一個(gè)字元后,任務(wù)代碼會(huì )使用回圈語(yǔ)句延遲一段時(shí)間,然后又跳轉到任務(wù)代碼開(kāi)始處繼續回圈執行,直到執行了l0毫秒而發(fā)生了定時(shí)中斷,從而代碼會(huì )切換到另一個(gè)任務(wù)去執行。對於任務(wù)A,寄存器AL中將始終存放字元‘A’,而任務(wù)B執行時(shí)AL中始終存放字元‘B’。因此在程式執行時(shí)我們將看到一連串的字元‘A’和一連串的字元‘A’間隔地連續不斷地顯示在螢幕上,見(jiàn)圖4-43所示。






圖4-43是我們在Bochs模擬軟件中執行這個(gè)內核示例的螢幕顯示情況。細心的讀者會(huì )發(fā)現,在圖中底端一行上顯示出一個(gè)字元‘C’。這是由於PC機偶然產(chǎn)生了一個(gè)不是時(shí)鐘和系統呼叫的其他中斷而引起的。因為我們已經(jīng)在程式給所有其他中斷安裝了一個(gè)預設中斷處理程式,在這個(gè)程式中會(huì )顯示一個(gè)字元‘C’,然后退出中斷。

下面列出boot.s和head.s程式的詳細注釋。有關(guān)這個(gè)簡(jiǎn)單內核示例的編譯和執行方法請參考我們最后一章中“編譯執行簡(jiǎn)單內核示例程式”一節內容。


4.9.2 開(kāi)機啟動(dòng)程式boot.s

為了盡量讓程式簡(jiǎn)單,這個(gè)開(kāi)機啟動(dòng)磁區程式僅能夠載入長(cháng)度不超過(guò)16個(gè)磁區的head代碼,並且直接使用了ROM BIOS預設設置的中斷向量號,即定時(shí)中斷請求處理的中斷號仍然是8。這與Linux系統中使用的不同。Linux系統會(huì )在內核初始化時(shí)重新設置8259A中斷控制晶片,并把時(shí)鐘中斷請求信號對應到中斷0x20以上,詳細說(shuō)明請參考“內核開(kāi)機啟動(dòng)程式”一章的內容。






4.9.3多工內核程式head.s

在進(jìn)入保護模式后,head.s程式重新建立和設置IDT、GDT表的主要原因是為了讓程式在結構上比較清晰,也為了與后面Linux 0.12內核原始碼中這兩個(gè)表的設置方式保持一致。當然,就本程式來(lái)說(shuō)我們完全可以直接使用boot.s中設置的IDT和GDT表位置,填入適當的描述符號項即可。







192 .1ong 0,0,0,0,0 /* espl,ssl,esp2,ss2,cr3 */
193 .1ong 0,0,0,0,0 /* eip,eflags,eax,ecx,edx */
194 .1ong 0,0,0,0,0 /* ebx esp,ebp,esi,edi */
195 .1ong 0,0,0,0,0 /* es,cs,ss,ds,fs,gs */
196 .1ong LDT0_SEL,0x8000000 /* ldt,trace bitmap */
197
198 .fill 128,4,0 #這是任務(wù)0的內核堆??臻g。
199 krn_stk0 :
200
201 #下面是任務(wù)l(shuí)的LDT表段內容和TSS段內容。
202 .align 3
203 ldt1: .quad 0x0000000000000000 #第l個(gè)描述符號,不用。
204 .quad 0x00c0fa00000003ff #選擇符號是0x0f,基底位址 = 0x00000。
205 .quad 0x00c0f200000003ff #選擇符號是0x17,基底位址 = 0x00000。
206
207 tss1: .long 0 /* back link */
208 .long krn_stk1,0x10 /* esp0,ss0 */
209 .1ong 0,0,0,0,0 /* espl,ssl,esp2,ss2,cr3 */
210 .1ong task1,0x200 /* eip,eflags */
211 .1ong 0,0,0,0,0 /* eax,ecx,edx,ebx */
212 .1ong usr_stk1,0,0,0 /* esp,ebp,esi,edi */
213 .1ong 0x17,0x0f,0x17,0x17,0x17,0x17 /* es,cs,ss,ds,fs,gs */
214 .1ong LDT1_SEL,0x8000000 /* ldt,trace bitmap */
215
216 .fill 128,4,0 #這是任務(wù)1的內核堆??臻g其用戶(hù)堆棧直接使用初始堆??臻g。
217 krn_stk1 :
218
219 #下面是任務(wù)0和任務(wù)1的程式,它們分別回圈顯示字元‘A’和‘B’。
220 task0 :
221 movl $0x17,%eax #首先讓DS指向任務(wù)的區域資料段。
222 movw %ax, %ds #因為任務(wù)沒(méi)有使用區域資料,所以這兩句可省略。
223 movl $65, %al #把需要顯示的字元‘A’放入AL寄存器中。
224 int $0x80 #執行系統呼叫,顯示字元。
225 movl $0xfff,%ecx #執行回圈,起延時(shí)作用。
226 l : loop lb
227 jmp task0 #跳轉到任務(wù)代碼開(kāi)始處繼續顯示字元。
228 taskl :
229 movl $66, %al #把需要顯示的字元‘B’放入AL寄存器中。
230 int $0x80 #執行系統呼叫,顯示字元。
231 movl $0xfff,%ecx #延時(shí)一段時(shí)間,並跳轉到開(kāi)始處繼續回圈顯示。
232 l : loop lb
233 jmp taskl
234
235 .fill 128,4,0 #這是任務(wù)l(shuí)的用戶(hù)堆??臻g
236 usr_stk1 :







To be continued......
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
TSS任務(wù)狀態(tài)段
Linux進(jìn)程-進(jìn)程的創(chuàng )建
任務(wù)門(mén),調用門(mén),中斷門(mén),陷阱門(mén)
80386保護模式總結
第10章 保護模式下的存儲器管理
Linux 內核
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久