寒假OS學習第四天

2021-10-17 18:55:11 字數 4633 閱讀 1820

接下來將進入x86保護模式程式設計的一些細節。

從80386處理器開始,cpu有了四種執行模式

實模式保護模式

虛擬8086模式

smm模式工作模式是指cpu的定址方式、暫存器大小等。

cpu的實模式

在8086時代,cpu以實模式執行

cpu剛剛上電後,也以實模式啟動

參考資料:

(最開始的時候,cpu一共只有20位位址線、8個16位的段暫存器)

實模式下,記憶體定址方式由16位暫存器的內容乘以10h當作段基位址(由段暫存器提供),加上16位偏移位址形成20位實體地址(段基址:段偏移量)。最大定址空間1mb,最大分段64kb,可以使用32位指令。

段暫存器一共有6種:

cs、ds、ss、es、fs、gs

段暫存器

段暫存器是因為對記憶體的分段管理而設定的。計算機需要對記憶體分段,以分配給不同的程式使用。

在進行記憶體分段時,需要以下資訊:

段的大小

段的起始位址

段的屬性

需要使用8個位元組即64位儲存這些資訊

段暫存器只有16位,因此,段暫存器只能儲存segment selector,由其對映到存在記憶體中的全域性段號記錄表(gdt)來讀取段的資訊。

cs是**段。指向存放程式的記憶體。ip是存放下條待執行指令的偏移量,合在一起就是下條指令位置。

偏移量由通用暫存器提供,也是16位。

實體地址=段位址<<4+段內偏移
ds是資料段。預設。

ss是堆疊段。指向堆疊的記憶體段基位址,sp指向該堆疊的棧頂,合在一起可以訪問棧頂單元。加上bp可以訪問整個堆疊。

es是附加段。串操作指令中目的串所在的段。

將記憶體分段後,每個段都有乙個段基址,段暫存器儲存這個段基址的高16位,16位段基址左移4位後可以構成20位的段基址。

fs和gs沒有定義,由作業系統賦予它們目的。

實模式之所以稱之為實模式,是因為它的實體地址是真實的。

任意程式可以修改任意位址的變數

保護模式

隨著cpu的發展,實模式下的記憶體位址計算方式不再適用。

保護模式能提供更大的空間、更靈活、更安全的記憶體訪問。

記憶體定址方式需要相容老辦法,即(段基址、段偏移量)。

這個時候cpu內的通用暫存器全部換為32位,但是段暫存器還是16位的。

偏移值和實模式下一樣,仍然由通用暫存器提供,只是大小變成了32位。

將關於記憶體段的限制資訊放在gdt即全域性描述符表中,裡面的每乙個項稱之為段描述符。

段暫存器在保護模式下存放的東西類似於陣列索引。

使用專用暫存器gdtr指向全域性描述符表。

gdtr的結構:0-15存放gdt的長度,16-47存放基址。

乙個段描述符只能用來定義乙個記憶體段。

段界限:段邊界擴張法最值,即最大擴充套件多少、最小擴充套件多少。它的單位由g決定,g=1時單位為4kb,g=0時單位為位元組。

實際段界限邊界值 = (段界限+1) * 單位大小 - 1
若偏移位址超過段界限,則會報錯

此時的段暫存器內儲存的是乙個「選擇子」

選擇子的0-2位是rpl,描述特權級別

3位是ti,ti=0表示在gdt中索引,ti=1表示在ldt中索引

3-15位是描述符索引值

保護模式下,程式不能隨心所欲地修改任意位址的變數

虛擬8086模式

用於在保護模式下執行16位**

smm模式

不對程式設計師開放,不關心

cpu內部有5個32位的控制暫存器:cr0-cr3,cr8

cr0:含有控制cpu操作模式和狀態的標識

cr1:保留不用

cr2:儲存導致頁錯誤的線性位址

cr3:含有頁目錄表的物理記憶體基址

cr0中的保護控制位:pe

pe設定->開啟了保護模式

pg設定->開啟分頁機制(pe、pg都要設定)

cpu一進入保護模式立刻按照保護模式定址,這要求我們要在cpu進入保護模式前放好gdt

我們的核心剛剛啟動時,機器的狀態是這樣的:

eax            0x2badb002          732803074

ecx 0x1c300 115456

edx 0x2be00 179712

ebx 0x2bd20 179488

esp 0x7ffc 0x7ffc

ebp 0x0 0x0

esi 0x2be78 179832

edi 0x80 128

eip 0x10051f 0x10051f eflags 0x6 [ pf ]

cs 0x8 8

ss 0x10 16

ds 0x10 16

es 0x10 16

fs 0x10 16

gs 0x10 16

在實模式下,cpu只有1mb的定址空間,所以相當於gdt被限制在這裡了

grub在載入核心後,cs指向基位址為0x0、長度為4g-1的**描述符,ds指向了基位址為0x0、長度為1的資料段描述符

也就是,grub載入後,已經進入了平坦模式。

分段是intel的cpu一致保持的一種機制,分頁只是保護模式下的一種機制

如何繞過分段直接使用分頁?

使用平坦模式,即將整個記憶體作為乙個分段。

當整個虛擬空間為乙個起始位址為0、限長為4g的段時,給出的偏移位址就在數值上等於段機制處理後的位址了。

因此,此時計算機可以相容實模式

在grub引導後,我們的計算機已經進入了保護模式了

@ring: 0

cs = 0x8

ss = 0x10

ds = 0x10

es = 0x10

但是我們仍然需要再來一次,乙個是學習,另乙個是後期還要用到

首先需要構建資料型別

根據我們上面的介紹,構建如下的資料結構

// 定義gdt結構

typedef

struct

gdt_t;

typedef

struct

__attribute__

((packed)

)gdtr_t;

注意第二個結構體的__attribute__屬性!特別重要

沒有加上這個屬性,結構體大小為64,加上這個屬性,結構體大小為48,差了特別多!

其次,讓我們構建初始化gdt的函式

#define gdt_len 5

static gdt_t gdt[gdt_len]

;static gdtr_t gdtr;

static

void

gdt_set

(int num, uint32_t base,

uint32_t limit, uint8_t access, uint8_t gran)

;void

init_gdt()

static

void

gdt_set

(int num, uint32_t base,

uint32_t limit, uint8_t access, uint8_t gran)

這裡的gdt_flush負責更新gdrt

這個操作只能使用彙編完成

[global gdt_flush]

gdt_flush:

mov eax, [esp + 4]

lgdt [eax]

mov ax, 0x10

mov ss, ax

mov ds, ax

mov gs, ax

mov es, ax

mov fs, ax

jmp 0x08:.flush

.flush:

ret

注意這個jmp語句:

此處的jmp有兩個作用

重新整理cs暫存器

重新整理快取記憶體與流水線

這是nasm裡面的遠跳轉的寫法

寒假學習第四天

今天進行了spark的安裝。右擊,複製鏈結如下 在master的命令列中輸入 wget 複製結果如下 輸入命令 wget 2.2 解壓 輸入命令 tar zxf spark 2.4.0 bin hadoop2.7.tgz 2.3 遷移目錄 輸入命令 sudo mv spark 2.4.0 bin h...

第四天學習

一 權重關係 樣式表的權重關係 內聯樣式表的權重最大!內部和外部樣式的權重,和書寫的前後順序有關!放在後面的會把放在前面的樣式覆蓋掉 網頁的布局 先做上下排版 再做左右排版 從外往裡 二 css語法 選擇符選擇符 選擇符就是給標籤起名字 型別選擇符 標籤選擇符 所有的html標籤可以直接當做選擇符進...

C Primer學習第四天

第四章 陣列和指標 c 語言提供了兩種類似於vector和迭代器型別的低階復合型別 陣列和指標。與vector型別相似,陣列也可以儲存某種型別的一組物件 而它們的區別在於,陣列的長度是固定的。陣列一經建立,就不允許新增新的元素。指標則可以像迭代器一樣用於遍歷和檢查陣列中的元素。現代c 程式應盡量使用...