轉自:http://www.cnblogs.com/worldisimple/articles/2447577.html
一、概述處理器(CPU)
1.1 處理器位數
在intel處理器的X86系列中,包含8086和8088的16位處理器,以及從80386(即i386)開始的32位處理器,而如今又有X86-64架構的64位處理器。
那這些16位,32位和64位又有什么意義了?位數越高,處理器的尋址能力越強,則可以支持越大的物理內存。具體如下表(可見對於64位處理器的尋址范圍已經是非常之大):
處理器位數 |
可支持的物理內存大小 |
尋址范圍 |
16 |
2^16 = 64K |
0x0000 ~ 0xffff |
32 |
2^32 = 4G |
0x00000000 ~ 0xffffffff |
64 |
2^64 |
在平時安裝操作系統時候,經常會問是要裝32位系統還是64位系統?對於32位處理器,只能安裝32位的系統,不能安裝64位系統。對於64位處理,既能夠安裝32位的系統,也可以安裝64位的系統。在Linux下可以通過下面的方面查詢系統裝的是幾位的:
(1) 查看根目錄下是否有有lib64目錄。32位系統只有/lib一個目錄,64位的系統會有/lib64和/lib兩個目錄。
(2) 執行getconf LONG_BIT命令查看返回結果。32位的系統中long類型是4字節(32位),64位的系統中long類型已變成了8字節(64位)。
(3) 執行uname -i命令。32位的系統返回i386,64位的系統放回x86_64。
(4) 執行file /bin/ls命令。
32位系統返回如下結果:
/bin/ls: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.2.5,dynamically linked (uses shared libs), stripped
64位系統返回如下結果:
/bin/ls: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.6.9,dynamically linked (uses shared libs), for GNU/Linux 2.6.9, stripped
1.2 處理器的寄存器
寄存器是處理器的組成部分,是有限存貯容量的高速存貯部件,它們可用來暫存指令、數據和位址。寄存器的訪問速度在所有存儲階層(見下圖)是最快的。
在大學學習匯編時候,還用寄存器來寫匯編程序,現在也忘記差不多了,這邊就大致記錄一下處理器分別有哪些寄存器。
在8086中,所有的寄存器都是16位的。
在80386中,寄存器的發生的變化如下:
(1) 把16位的通用寄存器、指令指針寄存器以及標志寄存器擴充為32位的寄存器。
(2) 段寄存器仍然為16位,並增加2個16位的段寄存器。
寄存器的分類 |
32位CPU寄存器 |
16位CPU寄存器 |
主要用途 |
|
通 用 寄 存 器 |
數據 寄存器 |
EAX |
AX |
乘、除運算,字的輸入輸出,中間結果的緩存 |
EBX |
BX |
存儲器指針 |
||
ECX |
CX |
串操作、循環控制的計數器 |
||
EDX |
DX |
字的乘、除運算,間接的輸入輸出 |
||
變址 寄存器 |
ESI |
SI |
存儲器指針、串指令中的源操作數指針 |
|
EDI |
DI |
存儲器指針、串指令中的目的操作數指針 |
||
變址 寄存器 |
EBP |
BP |
存儲器指針、存取堆棧的指針 |
|
ESP |
SP |
堆棧的棧頂指針 |
||
指令指針寄存器 |
EIP |
IP |
存放下一條將要執行指令的偏移量,偏移量加上當前代碼段的基地址,就形成了下一條指令的地址。 |
|
標志位寄存器 |
EFLAG |
FLAG |
||
段寄存器 |
CS |
CS |
代碼段寄存器 |
|
DS |
DS |
數據段寄存器 |
||
SS |
SS |
堆棧段寄存器 |
||
ES |
ES |
附加數據段寄存器 |
||
FS |
- |
32位CPU新增加的附加數據段寄存器 |
||
GS |
- |
32位CPU新增加的附加數據段寄存器 |
(3) 增加4個32位的控制寄存器(CR0、CR1、CR2 和CR3),在進程管理及虛擬內存管理中會涉及到CR0(其中有2位分別用於指示運行在實模式/保護模式和是否開啟分頁機制)、CR2以及CR3(是頁目錄基址寄存器,保存頁目錄表的物理地址)這幾個寄存器。
(4) 增加4個系統地址寄存器,具體如下:
全局描述符表寄存器GDTR(Global Descriptor Table Register),是48位寄存器,用來保存全局描述符表(GDT)的32位基地址和16位GDT的界限。
中斷描述符表寄存器IDTR(Interrupt Descriptor Table Register),是48位寄存器,用來保存中斷描述符表(IDT)的32位基地址和16位IDT的界限。
局部描述符表寄存器LDTR(Global Descriptor Table Register),是16位寄存器,保存局部描述符表LDT段的選擇符。
任務狀態寄存器TR(Task State Register)是16位寄存器,用於保存任務狀態段TSS段的16位選擇符。
(5) 增加8個32位調式寄存器DR0~DR7。
(6) 增加2個32位測試寄存器TR6和TR7。
二、內存管理
下面的內容主要依賴於80386的32位處理器的保護模式下。
2.1 內存地址
物理內存單元的實際地址即物理地址。32位的處理器尋址范圍為0x00000000 ~ 0xffffffff,支持4G的物理內存大小。
程序產生的段選擇符與段相關的偏移地址部分構成了邏輯地址。在實模式下,沒有分段或分頁機制,邏輯地址和物理地址是相等的,不需要地址轉換可以直接訪問物理內存。但是在保護模式下,邏輯地址需要轉換成物理地址,才能訪問物理內存。那么,這個時候需要處理器中的內存管理單元(MMU)將邏輯地址映射為物理地址,來進行地址轉換(如下圖)。
那么,MMU是怎么將邏輯地址轉換成物理地址?
MMU是一種硬件電路,它包含兩個部件,一個是分段部件,一個是分頁部件,通過分段機制(把一個邏輯地址轉換為線性地址,線性地址也是32位,其地址取值范圍為0x00000000~0xffffffff)和分頁機制(把一個線性地址轉換為物理地址),最終將邏輯地址映射為物理地址。如下圖:
2.2 分段機制
在操作系統原理關於分段的說明:段的分配時為了更好的滿足用戶,段的長度不固定,由用戶定義,每個段都有自己的地址空間(通過基址包含某物理內存的地址,和長度值來表示段的長度),表示一個地址需要給出段部分(選擇符)和偏移部分。如下圖,如果沒有分頁的話,那么圖中的線性地址也就是物理地址,這種方式對於段的離散分配就很容易導致碎片問題(進而使用分頁機制來提高內存利用率):
在Linux中,主要設置了:內核代碼段,內核數據段,用戶代碼段,用戶數據段。而且每個段的基地址對應線性地址都是為0,而且都可以使用4G的地址空間,相當與繞過了邏輯地址和線性地址的映射,從而完全利用了分頁機制。另外,分段中怎樣使用段寄存器可以參考:http://book.51cto.com/art/200812/103305.htm
2.3 分頁機制
通過使用分頁機制可以很好的提高內存利用率。分頁機制把一個線性地址轉換為物理地址。Linux下一個頁大小為4K,把線性地址(32位)和物理地址(32位,2^32=4G物理內存)都按照4K(2^12)頁大小來進行划分,那么,一共有4G/4K=1M的頁面,如果只是簡單的進行線性地址和物理地址一對一記錄映射的話,這樣在映射表建立的就會占用比較大的物理內存。這個時候就引入了頁表和頁目錄表,地址轉換過程見下圖:
(1) 通過對32位線性地址划分:第31~22這10位(2^10=1024)定位頁目錄項,第21~12這10位定位頁表項,第11~0這12位(2^12=4K)為頁內偏移值。
(2) 對於頁目錄表,有1024個頁目錄項,每個頁目錄項(又含有1024個頁表項)指向下一級頁表的物理地址(32位=4個字節),那么一共需要1024*4(=4K)字節,即只要分配一頁就可以完全存放。
(3) 對於頁表,原理和頁目錄表一樣,那么一共需要1024(1024個頁目錄項)*1024(每個頁目錄項含有1024個頁表項)*4(=1M)字節。
(4) 對於頁目錄的物理地址,就存放在CR3寄存器中。
所以,這樣可以尋址1024*1024*4K=4G的物理內存。另外,在Linux的X86架構引入了3級頁表機制(包括了頁全局目錄、頁中間目錄和頁表)。
【參考】
2、OReilly.Understanding.the.Linux.Kernel.3rd.Edition
3、PPT: http://www.docin.com/p-54896290.html
4、http://www.ibm.com/developerworks/cn/linux/l-memmod/
-----------------------------------------------------------------