首先對某些概念進行解釋。
數(shù)據(jù)總線:是計算機中各個組成部件間進行數(shù)據(jù)傳輸時的公共通道;“內(nèi)數(shù)據(jù)總線寬度”是指CPU芯片內(nèi)部數(shù)據(jù)傳送的寬度;“外數(shù)據(jù)總線寬度”是指CPU與外部交換數(shù)據(jù)時的數(shù)據(jù)寬度。顯然,數(shù)據(jù)總線位數(shù)越多,數(shù)據(jù)交換的速度就越快。
地址總線:是載對存儲器或I/O端口進行訪問時,傳送由CPU提供的要訪問的存儲單元或I/O端口的地址信息的總線,其寬度決定了處理器能直接訪問的主存容量的大小。
現(xiàn)在的微型計算機系統(tǒng)采用下圖的三級存儲器組織結(jié)構(gòu),即緩沖存儲器Cache、主存、和外存。
高速緩沖存儲器Cache的使用,大大減少了CPU讀取指令和操作數(shù)所需的時間,使CPU的執(zhí)行速度顯著提高。
在80X86CPU的發(fā)展過程中,存儲器的管理機制發(fā)生了較大的變化。8086/8088CPU對存儲器的管理采用分段的實方式;80286CPU除了可在實方式下工作外,還可以在保護模式下工作;而80386CPU之后的處理器則具有三種工作方式:實方式、保護方式和虛擬8086方式。
三種工作方式的轉(zhuǎn)換如圖:
80386三種工作方式之間的轉(zhuǎn)換
8086寄存器結(jié)構(gòu):
8086/8088CPU內(nèi)部有14個16位寄存器。按功能分為三大類:通用寄存器(8個)、控制寄存器(2個)、段寄存器(4個)。
通用寄存器包括4個數(shù)據(jù)寄存器、兩個地址寄存器和兩個變址寄存器。
數(shù)據(jù)寄存器:用于存放參與運算的操作數(shù)或運算結(jié)果。包括AX累加器、BX基址寄存器、CX計數(shù)寄存器、DX數(shù)據(jù)寄存器。
指針寄存器:SP堆棧指針寄存器、BP基址寄存器。
變址寄存器:SI源變址寄存器、DI目的變址寄存器。
段寄存器包括:CS代碼段寄存器、DS數(shù)據(jù)段寄存器、SS堆棧段寄存器、ES附加數(shù)據(jù)段寄存器。
控制寄存器包括:IP指令指針寄存器、FLAGS狀態(tài)標(biāo)志寄存器。
段的引入:8086為了用16位寄存器實現(xiàn)1MB的尋址內(nèi)存空間,引入了段的概念。
段是虛擬地址空間的基本單位,分段機制把虛擬地址空間的一個地址轉(zhuǎn)換為線性地址空間的一個線性地址。
虛擬地址到線性地址的轉(zhuǎn)換
虛擬地址到線性地址的映射
其中base為段的基地址,是線性地址空間中段的起始地址
limit是段的界限,在虛擬空間中,段內(nèi)可以使用的最大偏移量
當(dāng)然虛擬地址到線性地址的映射通過段寄存器和段描述符表共同完成。且載保護模式下段描述符表分為全局描述符表(GDT)、中斷描述符表(IDT)、及局部描述符表(LDT)。Linux中的段控制單元
在Linux中,所有的段寄存器都指向相同的段地址范圍—— 換言之,每個段寄存器都使用相同的線性地址。這使Linux所用的段描述符數(shù)量受限,從而可將所有描述符都保存在GDT之中。這種模型有兩個優(yōu)點:
· 當(dāng)所有的進程都使用相同的段寄存器值時(當(dāng)它們共享相同的線性地址空間時),內(nèi)存管理更為簡單。
· 在大部分架構(gòu)上都可以實現(xiàn)可移植性。
Linux使用以下段描述符:
·內(nèi)核代碼段
·內(nèi)核數(shù)據(jù)段
·用戶代碼段
·用戶數(shù)據(jù)段
·TSS段
·默認(rèn)LDT 段
GDT中的內(nèi)核代碼段 (kernelcode segment)描述符中的值如下:
·Base = 0x00000000
·Limit = 0xffffffff(2^32 -1) = 4GB
·G(粒度標(biāo)志)=1,表示段的大小是以頁為單位表示的
·S = 1,表示普通代碼或數(shù)據(jù)段
·Type= 0xa,表示可以讀取或執(zhí)行的代碼段
·DPL 值=0,表示內(nèi)核模式
與這個段相關(guān)的線性地址是4 GB,S= 1 和 type= 0xa 表示代碼段。選擇器在cs寄存器中。Linux中用來訪問這個段選擇器的宏是_KERNEL_CS。
內(nèi)核數(shù)據(jù)段(kerneldata segment)描述符的值與內(nèi)核代碼段的值類似,惟一不同的就是Type字段值為2。這表示此段為數(shù)據(jù)段,選擇器存儲在ds寄存器中。Linux中用來訪問這個段選擇器的宏是_KERNEL_DS。
用戶代碼段(usercode segment)由處于用戶模式中的所有進程共享。存儲在GDT中的對應(yīng)段描述符的值如下:
·Base = 0x00000000
·Limit = 0xffffffff
·G = 1
·S = 1
·Type= 0xa,表示可以讀取和執(zhí)行的代碼段
·DPL = 3,表示用戶模式
在Linux中,我們可以通過_USER_CS宏來訪問此段選擇器。
在用戶數(shù)據(jù)段(userdata segment)描述符中,惟一不同的字段就是Type,它被設(shè)置為2,表示將此數(shù)據(jù)段定義為可讀取和寫入。Linux中用來訪問此段選擇器的宏是_USER_DS。
除了這些段描述符之外,GDT還包含了另外兩個用于每個創(chuàng)建的進程的段描述符—— TSS和 LDT段。
每個TSS 段(TSSsegment)描述符都代表一個不同的進程。TSS中保存了每個 CPU的硬件上下文信息,它有助于有效地切換上下文。
每個進程都有自己在GDT中存儲的對應(yīng)進程的 TSS描述符。這些描述符的值如下:
·Base = &tss(對應(yīng)進程描述符的TSS字段的地址;例如&tss_struct)這是在Linux內(nèi)核的schedule.h文件中定義的
·Limit = 0xeb (TSS段的大小是236字節(jié))
·Type = 9 或11
·DPL = 0。用戶模式不能訪問TSS。G標(biāo)志被清除
所有進程共享默認(rèn)LDT段。默認(rèn)情況下,其中會包含一個空的段描述符。這個默認(rèn)LDT段描述符存儲在 GDT中。Linux所生成的 LDT的大小是 24個字節(jié)。
所有GDT存放在cpu_gdt_table[]數(shù)組中,段的大小和指針存放在cpu_gdt_descr[]數(shù)組中。
Linux中的段:現(xiàn)在的大多數(shù)硬件平臺都不支持分段機制,但是又不能繞過她而直接給出線性地址空間,在這種情況下,linux的設(shè)計人員巧妙的讓段的基地址為0,使得偏移量=線性地址。從而實現(xiàn)了虛擬地址到線性地址的映射。
分頁機制的引入:段機制規(guī)定,必須為代碼段和數(shù)據(jù)段創(chuàng)建不同的段,這樣一來,不同的特權(quán)級都出現(xiàn)了相應(yīng)的CS和DS,這樣就失去了段保護的作用。
分頁機制完成了線性地址到物理地址的轉(zhuǎn)換過程。
首先了解分頁機制之前,先要分清頁和頁面的概念:
頁:將線性地址空間劃分成若干大小相等的片,稱為頁(page)
頁面:對應(yīng)頁的劃分將物理地址空間分成與頁大小相等的若干存儲塊,就稱為頁面或塊。
我們知道線性地址空間的大小為4GB,那怎樣來劃分頁的大小合理呢?IA32的標(biāo)準(zhǔn)頁大小為4KB,也就是說,線性地址空間被分成1M個4KB大小的頁。分大點可以不?可以,但是相應(yīng)的內(nèi)存中頁面的數(shù)目就減少,帶來的結(jié)果是一個頁面的空間過大,那么對于一個小數(shù)據(jù)來說,給他分配一個塊是不是有點浪費?要不分小點,在內(nèi)存運行時數(shù)據(jù)被分散到了不同的塊,讀起來也是很費勁的,因此,就巧妙的把頁的大小設(shè)為4KB。
分頁機制中使用頁表這種數(shù)據(jù)結(jié)構(gòu)實現(xiàn)了線性地址到物理地址的映射。
頁表中包含物理頁面基地址和頁的屬性。
對于頁表有兩級頁表和三級頁表之分。linux為了保證可移植行,
采用了三級分頁機制,當(dāng)然其在某些情況下可以返回到二級分頁。
上圖為線性地址到物理地址的映射
聯(lián)系客服