邏輯地址、線性地址、物理地址

1、基本概念web

1)物理地址(physical address)
     用於內存芯片級的單元尋址,與處理器和CPU鏈接的地址總線相對應。
2)邏輯地址(logical address)
     Intel爲了兼容,將遠古時代的段式內存管理方式保留了下來。邏輯地址指的是機器語言指令中,用來指數組

     定一個操做數或者是一條指令的地址。spa

3)線性地址(linear address)操作系統

     總的來講,CPU將一個虛擬內存空間中的地址轉換爲物理地址,須要進行兩步:翻譯

     首先將給定一個邏輯地址,CPU要利用其段式內存管理單元,先將爲個邏輯地址轉換成一個線性地設計

     址,  再利用其頁式內存管理單元,轉換爲最終物理地址。code

2、邏輯地址—>線性地址—段式內存管理orm

     一個邏輯地址由兩部份組成:段標識符: 段內偏移量。段標識符是由一個16位長的字段組成,稱爲段選擇符。其中前13位是一個索引號。後面3位包含一些硬件細節。blog

索引號,即段描述符表索引。段選擇符的前13位,經過索引能夠在段描述符表中找到一個具體的段描述符,這個描述符描述了某個段的相關信息:索引

 

Intel設計的本意是,一些全局的段描述符,就放在「全局段描述符表(GDT)」中,一些局部的,例如每一個進程本身的,就放在所謂的「局部段描述符表(LDT)」中。那究竟何時該用GDT,何時該用LDT呢?這是由段選擇符中的T1字段表示的:

(1)爲0,表示用GDT

(2)爲1,表示用LDT
GDT在內存中的地址和大小存放在CPU的gdtr控制寄存器中,而LDT則在ldtr寄存器中。

 

給定一個完整的邏輯地址[段選擇符:段內偏移地址]
1>看段選擇符的T1=0仍是1,知道當前要轉換是GDT中的段,仍是LDT中的段,再根據相應寄存器,獲得其地址和大小。咱們就有了一個數組了。
2>拿出段選擇符中前13位,能夠在這個數組中,查找到對應的段描述符,這樣,它了Base,即基地址就知道了。
3>把Base + offset,就是要轉換的線性地址了。

 

3、Linux段式管理

include/asm-i386/segment.h

 

#define GDT_ENTRY_DEFAULT_USER_CS        14

#define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS * 8 + 3)

 

#define GDT_ENTRY_DEFAULT_USER_DS        15

#define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS * 8 + 3)

 

#define GDT_ENTRY_KERNEL_BASE        12

 

#define GDT_ENTRY_KERNEL_CS                (GDT_ENTRY_KERNEL_BASE + 0)

#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS * 8)

 

#define GDT_ENTRY_KERNEL_DS                (GDT_ENTRY_KERNEL_BASE + 1)

#define __KERNEL_DS (GDT_ENTRY_KERNEL_DS * 8)

 

 

 

把其中的宏替換成數值,則爲:

 

1 #define __USER_CS 115        [00000000 1110  0  11]
2 
3 #define __USER_DS 123        [00000000 1111  0  11]
4 
5 #define __KERNEL_CS 96       [00000000 1100  0  00]
6 
7 #define __KERNEL_DS 104      [00000000 1101  0  00]

 

 

 

方括號後是這四個段選擇符的16位二製表示,它們的索引號和T1字段值也能夠算出來了

__USER_CS             index= 14   T1=0

__USER_DS             index= 15   T1=0

__KERNEL_CS           index= 12   T1=0

__KERNEL_DS           index= 13   T1=0

T1均爲0,則表示都使用了GDT,再來看初始化GDT的內容中相應的12-15項(arch/i386/head.S):

.quad 0x00cf9a000000ffff        /* 0x60 kernel 4GB code at 0x00000000 */

.quad 0x00cf92000000ffff        /* 0x68 kernel 4GB data at 0x00000000 */

.quad 0x00cffa000000ffff        /* 0x73 user 4GB code at 0x00000000 */     

.quad 0x00cff2000000ffff        /* 0x7b user 4GB data at 0x00000000 */

根據段描述符各字段展開,發現16-31位全爲0,即四個段的基地址全爲0
因而,給定一個段內偏移地址,按照前面轉換公式,0 + 段內偏移==>爲線性地址,能夠得出重要的結論:

在Linux下,邏輯地址與線性地址老是一致的,即邏輯地址的偏移量字段的值與線性地址的值老是相同的。

 

4、CPU的頁式內存管理

    CPU的頁式內存管理單元,負責把一個線性地址,最終翻譯爲一個物理地址。

    從管理和效率的角度出發,線性地址被分爲以固定長度爲單位的組,稱爲頁(page),例如一個32位的機器,線性地址最大可爲4G,能夠用4KB爲一個頁來劃分,這頁,整個線性地址就被劃分爲一個tatol_page[2^20]的大數組,共有2的20個次方個頁。這個大數組咱們稱之爲頁目錄。目錄中的每個目錄項,就是一個地址——對應的頁的地址。

     另外一類「頁」,咱們稱之爲物理頁,或者是頁框、頁楨的。是分頁單元把全部的物理內存也劃分爲固定長度的管理單位,它的長度通常與內存頁是一一對應的。

這裏注意到,這個total_page數組有2^20個成員,每一個成員是一個地址(32位機,一個地址也就是4字節),那麼要單單要表示這麼一個數組,就要佔去4MB的內存空間。爲了節省空間,引入了一個二級管理模式的機器來組織分頁單元

 

一、分頁單元中,頁目錄是惟一的,它的地址放在CPU的cr3寄存器中,是進行地址轉換的開始點。
二、每個活動的進程,由於都有其獨立的對應的虛似內存,那麼它也對應了一個獨立的頁目錄地址。

三、每個32位的線性地址被劃分爲三部分,頁目錄索引(10位):頁表索引(10位):偏移(12位)
依據如下步驟進行轉換:
一、從cr3中取出進程的頁目錄地址(操做系統負責在調度進程的時候,把這個地址裝入對應寄存器);
二、根據線性地址前十位,在數組中,找到對應的索引項,由於引入了二級管理模式,頁目錄中的項,再也不是頁的地址,而是一個頁表的地址。真正

    的頁的地址被放到頁表中去了。

三、根據線性地址的中間十位,在頁表(也是數組)中找到頁的起始地址;
四、將頁的起始地址與線性地址中最後12位相加,獲得最終的物理地址;

相關文章
相關標籤/搜索