日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

CPU实模式和保护模式、全局描述符表GDT、Linux内核中GDT和IDT的结构定义

發布時間:2025/4/14 linux 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CPU实模式和保护模式、全局描述符表GDT、Linux内核中GDT和IDT的结构定义 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一 計算機實模式和保護模式

?

實模式
在實模式下,內存被限制為僅有1M字節(220 字節)。有效的地址從00000到FFFFF (十六進制)。
這些地址需要用20位的數來表示。一個20位的數不適合任何一個8086的16位寄存器。
Intel通過利用兩個16位數值來決定一個地址的方法來解決這個問題。開始的16位值稱為段地址(selector)。
段地址的值必須存儲在段寄存器中。第二個16位值稱為偏移地址(offset)。

16位保護模式
在實模式下,一個段地址的值是物理內存里的一節的首地址。在保護模式下,一個段地址的值是一個指向描述符表的指針
。兩種模式下,程序都是被分成段。在實模式下,這些段在物理內存的固定位置而且段地址的值表示段開始處所在節的首
地址。在保護模式下,這些段不是在物理內存的固定的地址。事實上,它們不一定需要在內存中。

保護模式使用了一種叫做虛擬內存的技術。虛擬內存的基本思想是僅僅保存程序現在正在使用的代碼和數據到內存中。其
它數據和代碼暫時儲存在硬盤中直到它們再次需要時。

在保護模式下,每一段都分配了一條描述符表里的條目。這個條目擁有系統想知道的關于這段的所有信息。這些信息包括
:現在是否在內存中;如果在內存中,在哪;訪問權限(例如: 只讀)。段的條目的指針是儲存在段寄存器里的段地址值

32位保護模式
80386引入了32位保護模式。
386 32位保護模式和286 16位保護模式之間最主要的區別是:
? ? 1 偏移地址擴展成了32位。這就允許偏移地址范圍升至4G。因此,段的大小也升至4G。
? ? 2 段可以分成較小的4K大小的單元,稱為內存頁。虛擬內存系統工作在頁的方式下,代替了段方式。這就意味著一段
在任何一個時刻只有部分可能在內存中。在28616位保護模式下,要么整個段在內存中,要么整個不在。?

? ? 在Windows 3.x系統中,標準模式為286 16位保護模式而增強模式為32位保護模式。Windows 9X,Windows
NT/2000/XP,OS/2和Linux都運行在分頁管理的32位保護模式下。

?

二 全局描述符表GDT

?

? ? GDT,Global Descriptor Table。
? ? IA32允許將一個段的基地址設置為32bit所能表示的任何值,limit(段大小)則可以設置成以2^12為倍數的任何值。
? ? 在保護模式下,對一個段的描述包括以下三個方面:[Base Address,Limit,Access],他們加在一起被放在一個64bit
長的數據結構中,被成為段描述符。
? ? 在這種情況下,如果我們直接通過一個64bit段描述符來引用一個段的時候,就必須使用一個64bit長的段寄存器裝入
這個段描述符。
? ? 把這些長度為64bit的段描述符放入一個數組中,而將段寄存器中的值作為下標索引來間接引用(事實上就是將段寄
存器中的高13bit的內容作為索引)。這個全局數據就是GDT。

?

三 Linux中GDT和IDT的結構定義

?

GDT,IDT都是全局的。LDT是局部的(在GDT中有它的描述符);

GDT用來存儲描述符(門或非門);系統中幾個CPU,就有幾個GDT

struct gdt_page {

? ? struct desc_struct gdt[GDT_ENTRIES];

} __attribute__((aligned(PAGE_SIZE)));

DECLARE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page);


IDT整個系統只有一個;
系統啟動時候需要初始化GDT和IDT;


描述符結構定義,在<arch/x86/include/asm/desc_defs.h>

struct desc_struct {

? ? union {

? ? ? ? struct {

? ? ? ? ? ? unsigned int a;

? ? ? ? ? ? unsigned int b;

? ? ? ? };

? ? ? ? struct {

? ? ? ? ? ? u16 limit0;

? ? ? ? ? ? u16 base0;

? ? ? ? ? ? unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1;

? ? ? ? ? ? unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8;

? ? ? ? };

? ? };?
} __attribute__((packed));

上面第一個匿名結構體用來作為成員訪問取值的出口,下面第二個結構體對真實的成員設置值的入口。

字段:

limit:段長度

base:段的首字節的線性地址,有base0,base1,base2三部分構成

type:段的類型和存取權限

s:系統標志。1-系統段;0-普通段

dpl:描述符特權級

p:segment-Present。linux下總是1

avl:linux不用

d:區分代碼段還是數據段

g:段大小粒度。以4K倍數計算

?

在32位機器上,這就是所有描述符的數據結構;

typedef struct desc_struct gate_desc;

typedef struct desc_struct ldt_desc;

typedef struct desc_struct tss_desc;

?

由于三類描述符都是一個結構類型,從而一律使用下面宏初始化在GDT中表項

#define GDT_ENTRY_INIT(flags, base, limit) { { { \

? ? ? ? .a = ((limit) & 0xffff) | (((base) & 0xffff) << 16), \

? ? ? ? .b = (((base) & 0xff0000) >> 16) | (((flags) & 0xf0ff) << 8) | \

? ? ? ? ? ? ((limit) & 0xf0000) | ((base) & 0xff000000), \

? ? } } }

?

但是在64位機器上,Linux則進行了細致劃分;
無論是32位還是64位機器上,都使用typedef重新定義,以提供給系統其他使用此描述符的部分一致的類型名;

?

區分描述符的枚舉量

enum {

? ? GATE_INTERRUPT = 0xE,

? ? GATE_TRAP = 0xF,

? ? GATE_CALL = 0xC,

? ? GATE_TASK = 0x5,

};


enum {

? ? DESC_TSS = 0x9,

? ? DESC_LDT = 0x2,

? ? DESCTYPE_S = 0x10, ?/* !system */

};

?

系統GDT,IDT指針描述結構

struct desc_ptr {

? ? unsigned short size;

? ? unsigned long address;

} __attribute__((packed)) ;


這個結構記錄了系統的GDT或者IDT的大小以及在系統中的線性基址;

Reference:

? ? <arch/x86/include/asm/desc_defs.h>

?

四 如何通過段描述符訪問內存

?

當我們要訪問某個段中的一個地址時候:
? ? 1 從GDTR中拿到GDT在內存中的基地址,得到段描述符表;?

? ? 2 從段選擇子中的前13位得到我們要訪問的段的描述符在段描述符表中的索引;?

? ? 3 從段描述符表中得到要訪問的段的描述符,得到其基地址;
? ? 4 基地址加上偏移地址就是我們要訪問的內存地址(這里是虛擬地址,接下來是分頁機制的功能將虛地址轉換為物理
地址,)

?

看內核相關源碼涉及到 AT&T匯編,和Intel匯編語法不同;先學部分AT&T匯編語法;

? ? 操作數排列是從源(左)到目的(右),如"movl %eax(源), %ebx(目的)";

? ? 符號常數直接引用 如:
value: .long 0x12a3f2de
movl value , %ebx

? ? 會見到如下的指令:push,pushl,pushfl;

? ? 操作數的長度用加在指令后的符號表示b(byte, 8-bit), w(word, 16-bits), l(long, 32-bits);
? ? 如
? ? ? ? "movb %al, %bl",
? ? ? ? "movw %ax, %bx",
? ? ? ? "movl %eax, %ebx",
? ? 目前還不知道pushfl是啥;

? ? 如果沒有指定操作數長度的話,編譯器將按照目標操作數的長度來設置。

參閱
https://blog.csdn.net/cwcmcw/article/details/21640363
http://blog.chinaunix.net/uid-29113598-id-5210949.html

總結

以上是生活随笔為你收集整理的CPU实模式和保护模式、全局描述符表GDT、Linux内核中GDT和IDT的结构定义的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。