《一個作業系統的實現》讀書筆記--第三章--保護模式
pmtest1.asm
; pmtest1.asm ; 編譯方法:nasm pmtest1.asm -o pmtest1.com ; ========================================== %include "pm.inc" ; 常量, 巨集, 以及一些說明 org 0100h jmp LABEL_BEGIN [SECTION .gdt] ; GDT ; 段基址, 段界限 , 屬性 LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符 LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 ; 非一致程式碼段, 32 LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 視訊記憶體首地址 ; GDT 結束 GdtLen equ $ - LABEL_GDT ; GDT長度 GdtPtr dw GdtLen - 1 ; GDT界限 dd 0 ; GDT基地址 ; GDT 選擇子 SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT ; END of [SECTION .gdt] [SECTION .s16] [BITS 16] LABEL_BEGIN: mov ax, cs mov ds, ax mov es, ax mov ss, ax mov sp, 0100h ; 初始化 32 位程式碼段描述符 xor eax, eax mov ax, cs shl eax, 4 add eax, LABEL_SEG_CODE32 mov word [LABEL_DESC_CODE32 + 2], ax shr eax, 16 mov byte [LABEL_DESC_CODE32 + 4], al mov byte [LABEL_DESC_CODE32 + 7], ah ; 為載入 GDTR 作準備 xor eax, eax mov ax, ds shl eax, 4 add eax, LABEL_GDT ; eax <- gdt 基地址 mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址 ; 載入 GDTR lgdt [GdtPtr] ; 關中斷 cli ; 開啟地址線A20 in al, 92h or al, 00000010b out 92h, al ; 準備切換到保護模式 mov eax, cr0 or eax, 1 mov cr0, eax ; 真正進入保護模式 jmp dword SelectorCode32:0 ; 執行這一句會把 SelectorCode32 裝入 cs, 並跳轉到 Code32Selector:0 處 ; END of [SECTION .s16] [SECTION .s32]; 32 位程式碼段. 由真實模式跳入. [BITS 32] LABEL_SEG_CODE32: mov ax, SelectorVideo mov gs, ax ; 視訊段選擇子(目的) mov edi, (80 * 10 + 0) * 2 ; 螢幕第 10 行, 第 0 列。 mov ah, 0Ch ; 0000: 黑底 1100: 紅字 mov al, 'P' mov [gs:edi], ax ; 到此停止 jmp $ SegCode32Len equ $ - LABEL_SEG_CODE32 ; END of [SECTION .s32]
下面我以pmtest1.asm為例,回答下面的問題。
(1)[SECTION .XXX]為何物?
(2)段描述符(Descriptor)、全域性描述符表(GDT)、全域性描述符表暫存器(GDTR)、選擇子(SelectorXXX) 為何物?有什麼作用?
(3)真實模式下的定址方式與保護模式下的定址方式的區別?
(4)段描述符巨集定義和初始化段描述符
(5)載入GDTR
1、[SECTION .XXX]為何物?
SECTION和SEGMENT的作用相類似,就是代表“段”的意思。從整個程式來看,該程式分為3個模組,分別是[SECTION .gdt]、[SECITON .s16]、[SECTION .s32]三部分。我們很容易就可以看出,其中的[SECTION .gdt]應該是資料段,其他的兩個是程式碼段。通過[SECTION .XXX]將程式分成不同模組,完成不同的功能,使得程式看起來清晰明瞭。
2、描述符(Descriptor)、全域性描述符表(GDT)、全域性描述符表暫存器(GDTR)、選擇子(SelectorXXX) 是什麼?用來做什麼?
段(Segment),在80X86中,分段機制將記憶體空間分成一個或者多個線性區域,我們把這些線性區域稱為段。我們需要將這些段區分開來,於是分段機制為每個段賦予3個屬性,分別是:段基址(Base address):指定段線上性地址空間中的開始地址。段界限(Limit):表示了段內最大可用偏移量,也就是說它定義了段的長度。段屬性(Attribute):指定了段的特性,包括:可讀,可寫或者可執行,特權等級等特性。
段描述符(Descriptor),
段描述符表(Descriptor Table),在一個程式中,不只存在一個段(段描述符)。所以我們需要將這些段描述符組織起來,於是定義了一個儲存段描述符的陣列,稱為段描述符表。段描述符表有兩種,一種是全域性描述符表(GDT),一種是區域性描述符表(LDT),系統中供所有的任務共享的是全域性描述符表,而不同的任務卻是使用自己的區域性描述符表。
段選擇子(SelectorXXX),把所有段描述符都儲存在段描述符表中,當我們使用其中某一個段的時候,我們並不直接指向該段,而是通過該段描述符在段描述符表中的位置來訪問的。故段選擇子,就是一個16位的識別符號,用來標識該段描述符在描述符表中的位置。
段描述符表暫存器,如何讓系統知道段描述符表在什麼地方呢?處理器提供了記憶體管理暫存器,分別是全域性描述符表暫存器(GDTR)、區域性描述符表暫存器(LDTR)。GDTR暫存器中用於存放全域性描述符表GDT的32位線性基地址和16位的表的長度值。LDTR暫存器中用於存放區域性描述符表LDT的32位線性基地址和16位的表的長度值。通過系統指令,lgdt將GDT的線性基址和長度值載入到GDTR暫存器中,lldt將LDT的線性基址和長度值載入到LDTR暫存器中。
下面我們來分析pmtest1.asm中的原始碼:
[SECTION .gdt]
; GDT
; 段基址, 段界限 , 屬性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 ; 非一致程式碼段, 32
LABEL_DESC_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW ; 視訊記憶體首地址
; GDT 結束
GdtLen equ $ - LABEL_GDT ; GDT長度
GdtPtr dw GdtLen - 1 ; GDT界限
dd 0 ; GDT基地址
; GDT 選擇子
SelectorCode32 equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorVideo equ LABEL_DESC_VIDEO - LABEL_GDT
; END of [SECTION .gdt]
在程式中,4、5、6行定義了3個段描述符,LABEL_GDT(空描述符),LABEL_DESC_CODE32(32位程式碼段描述符),LABEL_SESC_VIDEO(顯示記憶體描述符)。每個描述符都包含了3個屬性,段基址、段界限、段屬性。將三個描述符組織到一起構成一個全域性段描述符表(GDT)。
GdtLen是GDT的長度。GdtPtr為一個數據結構,包含兩個元素,第一個元素是2 bytes的GDT界限。第二個元素是4 bytes的GDT的基地址。該資料結構與全域性描述符表暫存器(GDTR)的資料結構相同,所以在載入GDTR的時候(原始碼55行),就是將該GdtPtr載入到GDTR中。
由於第一個段LABEL_GDT是空描述符,它僅僅代表該GDT的初始地址,所以該描述符為空描述符,一般情況下,不為它建立選擇子。然後該程式建立了兩個選擇子(24、25行)SelectorCode32和SelectorVideo,分別對應著這兩個段LABEL_SESC_CODE32和LABEL_DESC_VIDEO。
這段程式碼的結構大家應該明白了吧。
下面我要分別介紹段描述符,全域性描述符表暫存器,選擇子的資料結構。
段描述符(Descriptor)的結構圖如下:
段選擇子(SelectorXXX)的結構圖如下圖所示:
TI標誌著該選擇子所指向的段描述符是全域性描述符,還是區域性描述符。當TI=0時,表示全域性描述符,當TI=1時,表示區域性描述符。
RPL請求優先順序,稍後下一節將會提到。
全域性描述符表暫存器(GDT)的結構圖如下所示:
3、真實模式下的定址方式與保護模式下的定址方式有什麼不同?
在真實模式下,也就是在8086系統下的定址方式。 Intel 8086是16位的CPU,它有著16位的暫存器(Register),16位的資料匯流排(Data Bus)以及20位的地址匯流排(Address Bus)和1MB的定址能力。一個地址是由段和偏移兩部分組成的,實體地址遵循這樣的計算公式:
實體地址(Physical Address) = 段值(Segment) * 16 + 偏移(Offset)。其中段值和偏移都是16位的。故定址範圍為1MB。
在保護模式下,有了分段機制,所以它的定址方式發生了很大的變化。具體如下圖所示:
在保護模式下,首先使用段選擇子在段描述符表中查詢到相對應的段描述符,找到32位段基址,然後在與32位的偏移量相加,得到線性地址。段基址和段偏移量都是32位的,所以定址範圍大小為4GB。在程式中jmp dword SlectorCode32:0的作用,就是進入保護模式下的定址方式。其中,在使用某個段時,它的段選擇子是儲存在段暫存器中的。
這裡面存在著一個問題,是否我們每次定址都要先去全域性描述符表暫存器(GDTR)中,查詢到全域性描述符表(GDT)的基址,然後再次根據選擇子的索引跳轉到該描述符所在的位置,然後取得段描述符中的基址,如果這樣的話,我們裡裡外外採訪了幾次記憶體,太浪費時間了。實際上段暫存器結構是這樣的:
這樣的好處就是,我們可以直接獲取段描述符。4、描述符巨集定義和初始化段描述符
描述符巨集定義:
; 描述符
; usage: Descriptor Base, Limit, Attr
; Base: dd
; Limit: dd (low 20 bits available)
; Attr: dw (lower 4 bits of higher byte are always 0)
%macro Descriptor 3
dw %2 & 0FFFFh ; 段界限 1 (2 位元組)
dw %1 & 0FFFFh ; 段基址 1 (2 位元組)
db (%1 >> 16) & 0FFh ; 段基址 2 (1 位元組)
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh) ; 屬性 1 + 段界限 2 + 屬性 2 (2 位元組)
db (%1 >> 24) & 0FFh ; 段基址 3 (1 位元組)
%endmacro ; 共 8 位元組
2、3、4、5行註釋告訴我們,該巨集定義需要三個變數,分別是段基址(4 bytes),段界限(4 bytes),段屬性(dw)。
回顧剛才的段描述符結構,該巨集定義,就是將變數Base,Limit,Attr分別安插到描述符中相應的位置。Base是%1,Limit是%2,Attr是%3。
7行是將Limit低16位賦值給描述符的BYTE0和BYTE1
8 行是將Base低16位賦值給描述符的BYTE2和BYTE3
9 行是將Base右移16位後的低8位(也就是原Base的第16—23位)賦值給描述符的BYTE4
10行是將Limit右移8位之後的第8—11位和Attr的0—7和12—15位,組合起來儲存到描述符的BYTE5和BYTE6
11行是將Base右移24位後的低8位(也就是原Base的24—32位)賦值給描述符的BYTE7
初始化段描述符程式碼:
; 初始化 32 位程式碼段描述符
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_SEG_CODE32
mov word [LABEL_DESC_CODE32 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE32 + 4], al
mov byte [LABEL_DESC_CODE32 + 7], ah
為什麼要初始化?你會發現這裡只是修改了段描述符基地址,即LABEL_DESC_CODE32的BYTE2,BYTE4,BYTE7。是不是突然恍然大悟?因為在我們初始化該LABEL_DESC_CODE32描述符時,將其基地址初始化為0,所以我們要修改描述符的基地址為其實際的地址。這也是在前面介紹段描述符的時候,我提醒大家需要注意的地方,即描述符的基地址所佔有的位元組是BYTE2,BYTE4,BYTE7。
5、載入GDTR
; 為載入 GDTR 作準備
xor eax, eax
mov ax, ds
shl eax, 4
add eax, LABEL_GDT ; eax <- gdt 基地址
mov dword [GdtPtr + 2], eax ; [GdtPtr + 2] <- gdt 基地址
; 載入 GDTR
lgdt [GdtPtr]
這個很好理解,我們就是對GdtPtr進行賦值,主要是初始化GDT的基地址。也就是將GDT的初始地址,賦值給GdtPtr的BYTE2,BYTE3,BYTE4,BYTE5。使GdtPtr的資料結構剛好符合GDTR,然後執行lgdt [GdtPtr],載入全域性描述符表暫存器。將GDT的基地址和界限賦值給GDTR。
最近做了一個 Json 格式化,線上時間戳轉換,Md5 編碼,URL 編碼,Base64 編解碼,正則表示式,Linux 命令大全 等功能,歡迎大家使用和加入。
相關推薦
《一個作業系統的實現》讀書筆記--第三章--保護模式
pmtest1.asm ; pmtest1.asm ; 編譯方法:nasm pmtest1.asm -o pmtest1.com ; ========================================== %include "pm.inc" ; 常量, 巨
《一個作業系統的實現》讀書筆記--第三章--分頁機制
1、邏輯地址、線性地址和實體地址 2、分頁管理機制 3、PDE、PTE、cr3 4、如何初始化頁目錄表與頁表 一、邏輯地址、線性地址和實體地址 1、在未開啟分頁機制情況下 2、在開啟分頁機制情況下 二、分頁管理機制 下圖向大家展示,如何通過分頁管理機制,將線
《一個作業系統的實現》讀書筆記--第三章---不同特權級程式碼段之間的跳轉
1、特權級 2、一致程式碼段和非一致程式碼段 3、DPL、RPL、CPL分別代表的含義,儲存在什麼位置,以及它們之間的關係 4、不同特權級資料段之間的訪問規則 5、不同特權級程式碼段之間的轉移 6、程式碼段之間的轉移對堆疊的影響 7、結合pmtest5.asm來見證不同特權
《一個作業系統的實現》讀書筆記--第三章--中斷機制
1、中斷產生的原因 2、如何將中斷向量與中斷服務程式關聯起來 3、外部中斷 一、中斷 中斷產生的原因有兩種:一是外部中斷,就是由硬體產生的中斷;另一種是由指令int n產生的中斷。 二、如何將中斷向量與中斷服務程式關聯起來 1、真實模式下: 這個過程很簡
java並發編程的藝術,讀書筆記第三章
java並發編程的藝術final域的內存語義寫final域的重排規則:禁止把final域的寫重排序到構造方法之外,主要包括倆個個方面1)JMM禁止編譯器把final域的寫重排序到構造方法之外2)編譯器會在final域寫之後,構造函數return之前插入一個storestore屏障,這個屏障禁止處理器把fina
《數據庫設計入門經典》讀書筆記——第三章:工作場所中的數據庫建模
中間 特定 理論 大學 並且 外鍵 另一個 必須 所有 規範化用於粒度化和組織在數據庫中使用的數據。 在第4章中將詳細介紹規範化和應用範式的過程。在這個階段只需要知道規範化是用於將數據劃分到單獨表中的方法或公式——根據一組規則。 不信任將視圖用於除了安全性目標之外的任何事情
強化學習(RLAI)讀書筆記第三章有限馬爾科夫決策過程(finite MDP)
第三章 有限馬爾科夫決策過程 有限馬爾科夫決策過程(MDP)是關於評估型反饋的,就像多臂老虎機問題裡一樣,但是有是關聯型的問題。MDP是一個經典的關於連續序列決策的模型,其中動作不僅影響當前的反饋,也會影響接下來的狀態以及以後的反饋。因此MDP需要考慮延遲反饋和當前反饋與延遲反饋之間的交換。
《Linux命令列與shell指令碼程式設計大全》讀書筆記————第三章 基本的bash shell命令
本章內容 1、使用shell 2、bash手冊 3、瀏覽檔案系統 4、檔案和目錄列表 5、管理檔案和目錄 6、檢視檔案內容 3.3 bash手冊 命令: man xterm 作用:檢視檢視xterm使用者手冊 man命
精益資料分析讀書筆記——第三章-你把生命獻給誰
精益畫布 精益畫布是呈現在一張紙上的視覺化簡明商業企劃書。 似乎可以參考這個思路做產品分析 1.問題 提出三個你認為該產品解決的最核心的痛點,從而提出該產品的商業目標。 例如摩拜解決的主要問題就是近距離的通行問題,打車貴,開車麻煩,走路又遠。自己騎自行車維護管
作業系統概念學習筆記 第三章 程序
3.1 程序概念 1. 程序 程序是一種執行中的程式 執行什麼程式 執行什麼資料 處在什麼狀態 程序包括 程式程式碼/文字段 當前活動,程式計數器和CPU暫存器 記憶體中的
Unix環境高階程式設計 讀書筆記 第三章 檔案IO
概述 對於open、read、write、lseek、close等函式,被稱為不帶緩衝的I/O。即unbuffered i/O,術語“不帶緩衝”指的是每個read或者write都呼叫核心中的一個系統呼叫。 檔案描述符 檔案描述符是一個非負的整數; 檔案描述符0與程序
深度學習(花書)讀書筆記——第三章-概率與資訊理論
當方差很小時,f (x) 的值形成的簇比較接近它們的期望值。方差的平方根被稱為標準差(standard deviation)。協方差(covariance)在某種意義上給出了兩個變數線性相關性的強度以及這些變數的尺度: 協方差的絕對值如果很大則意味著變數值變化很大並且它們同時距離各自的均值很遠。
機器學習讀書筆記第三章(1):線性模型
一、基本形式: 1.在機器學習中,X一般表示m行1列的列向量: 對於一個m行n列的X矩陣而言,每一行是一個樣本,每一列是其特徵值。給定d個屬性描述的示例x=(x1;x2;x3;.........xd),其中xi是在第i個屬性上的取值。線性模型試圖學得一個通過屬性的線性組合來進行函式的預測
effective java-讀書筆記-第三章 對於所有物件都通用的方法
第三章 對於所有物件都通用的方法 所有非final方法(equals、hashCode、toString、clone、finalize)都有明確的通用約定,因為它們被設計成是要被覆蓋的,如果不遵守,基於雜湊的集合(HashMap、HashSet、HashTable)可
Effective Java讀書筆記 -- 第三章:對於所有物件都通用的方法
儘管Object是一個具體類,但是設計Object類主要是為了擴充套件。它的所有非final方法(equals、hashCode、toString、clone和finalize)都有明確的通用約定,因為它們就是被設計成要被覆蓋的。第八條:覆蓋equals時請遵守通用約定
《深入理解計算機系統》讀書筆記 —— 第三章 程式的機器級表示
>本章主要介紹了計算機中的機器程式碼——組合語言。當我們使用高階語言(C、Java等)程式設計時,程式碼會遮蔽機器級的細節,我們無法瞭解到機器級的程式碼實現。既然有了高階語言,我們為什麼還需要學習組合語言呢?學習程式的機器級實現,可以幫助我們理解編譯器的優化能力,可以讓我們瞭解程式是如何執行的,哪些部分是可以
嵌入式實時作業系統small RTOS51原理及應用 ----筆記 第三章 一個簡單的例子
嵌入式實時作業系統small RTOS51原理及應用 ----筆記 第三章 一個簡單的例子 keil C51 除錯程式碼: 軟體模擬模擬 執行 原始碼 #define OS_ENTER_CRITICAL() EA = 0,Os_Enter_Sum++
INSPIRED啟示錄 讀書筆記 - 第19章 用戶體驗設計與實現
高保真 設計軟件 開發階段 階段 工作 完成 軟件開發 用戶 一點 先定義用戶體驗再動手開發 在軟件開發過程中,有很多工作可以同時進行。比如,需求調研和產品設計(用戶體驗設計)、開發與測試 盡管如此,用戶體驗設計和軟件開發就不能同時進行,原因有五點 1、與軟件
《機器學習》 周志華學習筆記第三章 線性模型(課後習題)python 實現
線性模型 一、內容 1.基本形式 2.線性迴歸:均方誤差是迴歸任務中最常用的效能度量 3.對數機率迴歸:對數機率函式(logistic function)對率函式是任意階可導的凸函式,這是非常重要的性質。 4.線性判別分析(LDA 是一種降維的方法) 5.多分類學習:
《現代作業系統》精讀與思考筆記 第三章 記憶體管理
本系列博文是《現代作業系統(英文第三版)》(Modern Operating Systems,簡稱MOS)的閱讀筆記,定位是正文精要部分的摘錄理解和課後習題精解,因此不會事無鉅細的全面摘抄,僅僅根據個人情況進行記錄和推薦。由於是英文版,部分內容會使用英文原文。 課後習題的選擇標準:儘量避免單純的概念