《自己動手寫作業系統》第三章 pmtest1——從真實模式到保護模式
摘要:本節,我們將學習如何從真實模式進入保護模式,剖析pmtest1.asm原始碼。詳細講解如何從保護模式進入真實模式。
1.標頭檔案編寫:
這一部分,你需要把一些關鍵物理器件和資料結構的佈局記在腦子裡
GDT描述符:32b段基地址(B2、B3、B4、B7)+20b段限長(B0、B1、B6的低4位)+12b段屬性(B5、B6的高4位),詳細布局見下圖(針對程式碼段和資料段):
所以,我們定義瞭如下的儲存段描述符結構體:
42;巨集定義----------------------------------- 43;segment discripor 44;for code and data 45;usage Descripor Base, Limit, Attr 46; Base dd 47; Limit dd (Low 20b are available) 48; Attr dw(lower 4b of higher byte are 0) 49%macro Descriptor 3 50 dw %2&0FFFFh 51 dw %1&0FFFFh 52 db (%1 >> 16)&0FFh ;注意,運算以後超過8b,但是會被db截斷 53 dw (%3&0F0FFh) | ((%2 >> 8)&F0FFh) 54 db (%1>> 24)&0FFh 55 %endmacro;8位元組
同時,我們定義瞭如下的門描述符結構:
57;for gate
58;usage Gate Selector Selector,Offset,Dcount,Attr
59; selector dw
60; offset dd
61; Dcount dw
62; Attr dw
63%macro Gate 4
64 dw (%2&FFFFh)
65 dw %1
66 dw (%3 & 1Fh) | ((%4<< 8) & FF00h)
67 dw (%2 >> 16) & FFFFh
68 %endmarco
段選擇子:佈局是2+(1+13
相應的,我們根據IA-32的有關說明定義瞭如下的常量:
1;描述符型別說明: 2_LDT EQU 82h ; 區域性描述符表段型別值 3DA_TaskGate EQU 85h ; 任務門型別值 4DA_386TSS EQU 89h ; 可用386任務狀態段型別值 5DA_386CGate EQU 8Ch ; 386 呼叫門型別值 6DA_386IGate EQU 8Eh ; 386 中斷門型別值 7DA_386TGate EQU 8Fh ; 386 陷阱門型別值 8;--------------------------------------------------- 9;DA_32 EQU 4000h ;32b段 10DA_DPL0 EQU 00h ; DPL = 0 11DA_DPL1 EQU 20h ; DPL = 1 12DA_DPL2 EQU 40h ; DPL = 2 13DA_DPL3 EQU 60h ; DPL = 3 14 15;資料段和程式碼段描述符的低8位 16;--------------------------------------------------------------------------- 17DA_DR EQU 90h ; 存在的只讀資料段型別值 18DA_DRW EQU 92h ; 存在的可讀寫資料段屬性值 19DA_DRWA EQU 93h ; 存在的已訪問可讀寫資料段型別值 20DA_C EQU 98h ; 存在的只執行程式碼段屬性值 21DA_CR EQU 9Ah ; 存在的可執行可讀程式碼段屬性值 22DA_CCO EQU 9Ch ; 存在的只執行一致程式碼段屬性值 23DA_CCOR EQU 9Eh ; 存在的可執行可讀一致程式碼段屬性值 24 25 26;選擇子型別說明 27------------------------------------------ 28;SA_selector attribute 29SA_RPL0 equ 0; 30SA_RPL1 equ 1; 31SA_RPL2 equ 2; 32SA_RPL3 equ 3; 33 34SA_TIG equ 0; 35SA_TIG equ 4;
注意,在這裡,我們為什麼用的是4,不是1,是為了方便以後用加法賦值。從中,我們也可以看到,儘量做到所有的數字,是位元組對齊的.
寫好上述程式碼以後,放入一個.inc檔案之中,然後使用命令%include"pm.inc"將標頭檔案引入
2.保護模式的執行環境
我們採用dos的載入程式,直接來書寫啟動核心。這樣,可以解決引導扇區只有512B的限制。
需要在bochs環境中設定從軟盤a啟動,然後執行軟盤b中的程式。
3.GDT
GDT的產生,需要追溯到真實模式與保護模式的定址差別:段暫存器CS等儲存的內容如果是索引,那麼我們需要有一個結構來儲存段的資訊,這個結構就是GDT。GDT的作用是提供保護模式下的段儲存機制。對於這一步分,需要明白段描述符的詳細組成(8B)。
4.詳細程式碼與分析
程式碼解惑:
4.1[BITS32]等修飾,起到了什麼作用?與BITS16有什麼區別?
答:關於BITS(可能,你需要了解一下處理器字長和指令位數等:)
'BITS'指令指定NASM產生的程式碼是被設計執行在16位模式的處理器上還是執行在32位模式的處理器上。語法是'BITS16'或'BITS32'在大多數情況下,你可能不需要顯式地指定'BITS'。
'a.out','elf'和'win32'目標檔案格式都是被設計用在32位作業系統上的,它們會讓NASM預設選擇32位模式。而'obj'目標檔案格式允許你為每一個段指定'USE16'或'USE32',然後NASM就會按你的指定設定操作模式,所以多次使用'BITS'是沒有必要的。
但是我們的Realinit.bin的開始部分程式碼,採用NASM編譯,目標格式為BIN格式,即純粹的二進位制可執行檔案,不帶任何標頭檔案。
最有可能使用'BITS'的場合是在一個純二進位制檔案中使用32位程式碼;這是因為'bin'輸出格式在作為DOS的'.COM'程式,DOS的'.SYS'裝置驅動程式,或載入程式時,預設都是16位模式。如果你僅僅是為了在16位的DOS程式中使用32位指令,你不必指定'BITS32',如果你這樣做了,彙編器反而會產生錯誤的程式碼,因為這樣它會產生執行在16位模式下,卻以32位平臺為目標的程式碼。當NASM在'BITS16'狀態下時,使用32位資料的指令可以加一個位元組的字首0x66,要使用32位的地址,可以加上0x67字首。在'BITS32'狀態下,相反的情況成立,32位指令不需要字首,而使用16位資料的指令需要0x66字首,使用16位地址的指令需要0x67字首。'BITS'指令擁有一個等效的原始形式:[BITS16]和[BITS32]。而使用者級的形式只是一個僅僅呼叫原始形式的巨集。
4.2段基地址是如何計算的?LABEL_BIGIN不是段基地址?
我們要清楚,一個實體地址,如果沒有開啟分頁機制,在保護模式和真實模式下對應的地址是相同的,是不過定址方式不同而已。
4.3真實模式和保護模式的定址區別在哪裡?在程式碼中是如何體現出來的?
結合上一個問題,真實模式下是segment*16+offset,注意,這個segment是cs等中的數值;保護模式也是CS:offset,不過此時的CS僅僅是一個選擇符而已,還需要轉換成段基地址。另外,程式碼中的LABEL-BEGIN等,表示的是段內偏移,所以採用(eax<<4)+ LABEL_BEGIN來表示段的首地址。
4.4不同長度的運算元是如何進行運算的?是截斷還是補齊?為什麼會有修飾符movbyte和jmpdword等?
分情況:movax,bl:暫存器之間,按照高位補0的原則;
mov al,ff0ffh:暫存器與操作樹之間,按照截斷和補充高位0的原則
mov [ax],03:立即數和記憶體,很顯然,這個難辦的地方在於雙方都沒有固定的長度,或者說只要有記憶體在內,就沒有固定長度,此時需要指令運算元長度,例如movbyte [ax],03等。
同理,jmpword和dword在於對偏移量的處理,假如我們使用前者,只有16b暫存器,會發生截斷;所以用後者才比較安全。所以,jmp指令是一個需要特殊對待的指令。
另外,不要將長運算元賦值給短的:movbyte [bx],ax這樣是錯誤的;總之,進行相關操作的時候,儘量確保兩個運算元長度的統一
4.5為什麼進入保護模式之前,需要先關中斷?需要開啟A20?設定GDT?
這裡,我們先挖坑,等以後回來再填補.
4.6真實模式下的偏移和保護模式之下的offset有什麼區別?真實模式下,標號的地址表示實際的實體地址還是相當於段的offset呢?
答:offset本身的含義沒有什麼不同。label表示offset而不是實際的實體地址,之所以看起來像實體地址,是因為那時候cs的初始值是0000h。
那麼,如果僅僅是offset,那麼如何解釋“mov word [LABEL_DESC_CODE32 + 2], ax”中記憶體資料的定址呢?
我們來看一下,上面這條指令彙編以後的結果:
mov word ptr ds:0x010e, ax ; a30e01
看見了沒有,對於記憶體定址,ds被隱藏起來了,這就是我們之前為什麼要初始化ds的原因!!!
也就是說,標號的地址是本身相對與段首地址的offset。
4.7org 0100h是什麼意思?為什麼要載入到這個地方?
答:要了解ORG 0100h,就必須先了解程式段字首PSP(Program Segment Prefix)
程式段字首是一個作業系統(DOS)概念。當輸入一個外部命令或通過EXEC子功能(系統功能呼叫INT21h,子功能號為4Bh)載入一個程式時,COMMAND確定當前可用記憶體的最低端作為程式段的起點,也就是程式被載入到記憶體空間的起點。在程式所佔用記憶體的前256(0100h)個位元組中,DOS會為程式建立字首(PSP)資料區。PSP結構與CP/M中的“控制區域”概念十分接近,這是因為DOS就是從CP/M演變而來的。
比如你有一個標號Test的偏移地址是0x0Bh,當編譯器看見ORG 0x100h後,就會給這個偏移加上0x100h,編譯完成的.com檔案中,這個偏移就變成了0x10Bh。所以,你如果想在最開始設定斷點,b 00h是不會生效的,因為00h被移動到了100h。
DOS下的.com程式肯定被載入的CS段+0x100h處,因為段的前0100h(256位元組)是留給PSP的。這是作業系統DOS的概念,跟ORG沒有關係,所以你寫ORG 0200h
,也不會讓程式載入到CS段的0200h處。另外,dos是一個執行在真實模式之下的作業系統。
4.8關於equ?是什麼時候計算的?
答:equ實際上相當於一個巨集定義,所以它僅僅是一個替換作用,只有在程式實際執行的時候,才得到前面的值。
5.讓我們再來回顧一下,從真實模式到保護模式的過程
1)完成對段描述符的初始化
2)裝填gdtptr
3)關中斷
4)開啟A20
5)設定cr0暫存器
6)jmp切換
6.除錯程式
觀察各個暫存器和相關指令的執行和變化,得到的經驗。
書寫16進位制數的時候可以寫成ox0100,或者0010h,但是不能寫成ox0100h
相關推薦
《自己動手寫作業系統》第三章 pmtest1——從真實模式到保護模式
摘要:本節,我們將學習如何從真實模式進入保護模式,剖析pmtest1.asm原始碼。詳細講解如何從保護模式進入真實模式。 1.標頭檔案編寫: 這一部分,你需要把一些關鍵物理器件和資料結構的佈局記在腦子裡 GDT描述符:32b段基地址(B2、B3、B4、B7)+20b段限長
全面剖析《自己動手寫作業系統》第四章---載入Loader.bin
上一節我們已經詳細介紹了FAT12檔案系統的資料結構,下面我們需要思考的是兩個問題:1、引導扇區通過怎樣的步驟才能找到檔案;2、如何能夠把檔案內容全都讀出來並載入進入記憶體。 下面我們先解決第一個問題: 1、 如何讀取軟盤? (1) 我們需要使用BIOS中斷int 13h來讀取軟盤。它的用法如下表所
全面剖析《自己動手寫作業系統》第六章---程序
在一開始學習程序的時候,我們大概每個人都會遇到過這樣的問題,下面就讓我們帶著這些問題來認識認識程序。 1、程序是什麼? 2、什麼是多程序? 3、執行一個程序需要什麼? 4、多程序之間是如何排程的? 5、程序的上下文環境是什麼? 6、如何建立一個新的程序? 一、程序是什麼?
全面剖析《自己動手寫作業系統》的pmtest1.asm
##段機制輕鬆體驗 段機制輕鬆體驗 記憶體定址: 真實模式下的記憶體定址: 讓我們首先來回顧真實模式下的定址方式 段首地址×16+偏移量 = 實體地址 為什麼要×16?因為在8086CPU中,地址線是20位,但暫存器是16位的,最高定址64KB,它無法定址到1M記憶體。於是,Int
《自己動手寫作業系統》第2版:簡介
今年剛畢業,從事電商java開發崗位,一直對著需求編碼的話感覺技術長進不會太大,碰巧對作業系統這塊有些許興趣,就想著學習這塊的知識,如果學得好的話看將來能不能轉型成作業系統,系統安全或者c/c++相關的開發人員。 於是在網上找了很多資料,其實大部分都是理論書
作業系統 第三章 4 死鎖
1、死鎖(Deadlock): 指多個程序在執行過程中,因爭奪資源而造成的一種僵局。當程序處於這種狀態時,若無外力作用,它們都將無法再向前推進。 死鎖 : 指程序之間無休止地互相等待! 飢餓 :指一個程序無休止地等待! 2、產生死鎖的原因
作業系統 第三章 3 實時排程
1、實時系統: 指系統能夠在限定的響應時間內提供所需水平的服務。 2、實現實時排程的基本條件 1)提供必要的資訊 就緒時間。 開始截止時間、完成截止時間。 處理時間。 資源要求。 優先順序。 2)系統處理能力足夠強 3
作業系統 第三章 2 排程演算法
排程的實質就是一種資源分配。 1.先來先服務排程演算法FCFS 按照作業提交,或程序變為就緒狀態的先後次序分派CPU; 新作業只有噹噹前作業或程序執行完或阻塞才獲得CPU執行 被喚醒的作業或程序不立即恢復執行,通常等到當前作業或程序出讓CPU。 缺
作業系統 第三章 1 排程
1、處理機排程 多道程式環境下,動態的把處理機分配給就緒佇列中的一個程序使之執行。 2、高階排程(外存進記憶體) 又稱作業排程或長程排程、接納排程 決定外存後備佇列中的哪些作業調入記憶體; 為它們建立程序、分配必要的資源; 將
作業系統--第三章處理機排程與死鎖_2
死鎖 定義: 如果一組程序中的每個程序都在等待僅由該組程序中的其他程序才能引發的事件,那麼該組程序是死鎖的. 產生死鎖的必要條件: 互斥條件:程序對分配到的資源進行排他性的使用. 請求和保持條件:程序已經保持了至少一個資源,因為對另一個資源申請時被阻塞同時保持當前
作業系統--第三章處理機排程與死鎖_1
處理機排程定義: 在多道程式環境下,動態的將處理機分配給處於就緒狀態的一個程序使之執行. 對於大型系統執行時的效能,很大程度上取決於處理機排程效能的好壞. 處理機排程的層次: 高階排程: 又稱為長程排程或作業排程,他的排程物件是外村上處於後備佇列中的作業.高階排程主要用於
作業系統——第三章筆記(四)
死鎖問題 1.多道程式系統藉助併發執行改善資源利用率,提高系統吞吐量,但可能發生一種危險——死鎖。 死鎖(Deadlock):指多個程序在執行過程中,因爭奪資源而造成的一種僵局。當程序處於這種狀態時,若無外力作用,它們都將無法再向前推進。 死鎖(Deadlock): 指程序之間無休止地互相等
作業系統——第三章筆記(三)(含程序排程題目)
實時排程 1.什麼是實時系統? ○1指系統能夠在限定的響應時間內提供所需水平的服務。 ○2指計算的正確性不僅取決於程式的邏輯正確性,也取決於結果產生的時間,如果系統的時間約束條件得不到滿足,將會發生系統出錯。 實時任務:具有明確時間約束的計算任務,有軟/硬,隨機/週期性之分。 硬實時任務:必
作業系統——第三章筆記(二)
排程演算法 排程的實質就是一種資源分配。不同的系統和系統目標,通常採用不同的排程演算法——適合自己的才是最好的。 1)如批處理系統為照顧為數眾多的短作業,應採用短作業優先的排程演算法; 2)如分時系統為保證系統具有合理的響應時間,應採用輪轉法進行排程。 3)目前存在的多種排程演算法中,有的演
作業系統——第三章筆記(一)
處理及排程與死鎖 1.處理機排程:多道程式環境下,動態的把處理機分配給就緒佇列中的一個程序使之執行。 2.提高處理機的利用率、改善系統性能,很大程度上取決於處理機排程的效能。 3.處理機排程便成為OS設計的中心問題之一。分配的任務由處理機排程程式完成。 一.處理機排程的基本概念 作業進入系統
現代作業系統 第三章 記憶體管理 習題
Chapter03 第三章 記憶體管理 習題 知識點小記 當一個程序發生缺頁中斷的時候,程序會陷入核心態,執行以下操作: 1、檢查要訪問的虛擬地址是否合法 2、查詢/分配一個物理頁 3、填充物理頁內容(讀取磁碟,或者直接置0,或者啥也不幹) 4、建立對映關係(虛擬地址到實體
計算機作業系統第三章自測題-處理機排程與死鎖
1、在單處理器的多程序系統中,程序什麼時候佔有處理器以及決定佔用時間的長短是由( )決定的。 A、程序執行時間 B、程序的特點和程序排程策略 C、程序執行的程式碼 D、程序完成什麼功能 程序排程的時機與程序特點有關,如程序是否為CPU繁忙型還是I/O繁忙型
作業系統 第三章 死鎖--筆記
注意區分兩個概念 死鎖(Deadlock):指程序之間無休止地相互等待 飢餓(Starvation):指一個程序無休止地等待 在多道程式系統中,雖然可藉助於多個程式的併發執行來改善系統的資源利用率,提高系統吞吐量,但可能引發死鎖(因為上面也提到了死鎖是程序間無休
讀 自己動手寫作業系統
用一個月左右的時間讀了《自己動手寫作業系統》,這是一本讓人讀著很過癮,卻也特別累的一本書。 對作業系統的興趣由來已久,只是一直未能找到入門之徑。作業系統教材是個令人生畏的東西,它可以告訴人有什麼,卻不能告訴人為什麼,從那裡瞭解的作業系統有如盲人摸到的象,得到各個部分,卻不
作業系統 第三章 2 排程演算法
排程的實質就是一種資源分配。 1.先來先服務排程演算法FCFS 按照作業提交,或程序變為就緒狀態的先後次序分派CPU; 新作業只有噹噹前作業或程序執行完或阻塞才獲得CPU執行 被喚醒的作業或程序不立即恢復執行,通常等到當前作業或程序出讓CPU。 缺點: 不利於