1. 程式人生 > >Linux下的分頁機制

Linux下的分頁機制


分段可以給每個程序分配一個不同的程序地址空間,而分頁可以把相同的線性地址空間對映到不同的實體地址空間。
通俗的講,就是每個程序都有一個虛擬地址到實體地址的轉換表,而這個轉換表不同的程序是不同的。所以就會出現不同程序的同一個虛擬地址對應不同的實體地址
一、邏輯地址轉線性地址

機器語言指令中出現的記憶體地址,都是邏輯地址,需要轉換成線性地址,再經過MMU(CPU中的記憶體管理單元)轉換成實體地址才能夠被訪問到。

我們寫個最簡單的hello world程式,用gccs編譯,再反編譯後會看到以下指令:

mov    0x80495b0, %eax

這裡的記憶體地址0x80495b0 就是一個邏輯地址,

必須加上隱含的DS 資料段的基地址,才能構成線性地址。也就是說 0x80495b0 是當前任務的DS資料段內的偏移

段式對映過程中所有程序全都共用一個GDT,沒有用到LDT。而頁式對映中,每個程序都有其自身的頁面目錄PGD,指向這個目錄的指標儲存在每個程序的mm_struct 資料結構中,每當排程一個程序進入執行的時候,核心都要為即將執行的程序設定好控制暫存器CR3,而MMU的硬體總是從CR3中取得指向當前頁面目錄的指標。而CPU在執行時使用的是虛擬地址,而MMU硬體在進行對映是使用的則是實體地址(CR3)。這個是在Inline函式switch_mm()中完成的,如下:

static inline void switch_mm(struct mm_struct *prev,struct mm_struct *next, struct tast_struct *tsk)

{

asm volatile ("movl %0,%%cr3"::"r"(_pa(next->pgd))); //說明pgd中儲存的是虛擬地址,然後通過_pa轉換為實際的實體地址,這個也說明,PGD的實體地址是在核心空間中,這個表示不管什麼程序在核心空間中執行,核心中都有相同的頁面對映, 他一般是放在實際的實體記憶體中的,由於核心空間是在實體記憶體開始部分。

}

從硬體角度來說的話,Linux核心只要能為硬體準備好頁面目錄PGD、頁面表PT以及全域性段描述表GDT和區域性段描述表LDT,並正確地設定了有關的暫存器,就完成了記憶體管理機制中地址對映部分的準備工作。

核心中有一個mem_map,這是一個全域性變數,是一個指標,指向一個page資料結構的陣列,每個page資料結構代表著一個物理頁面,整個陣列代表著系統中的全部物理頁面,因此,頁面表項的高20位對於軟體和MMU硬體有著不同的意義,對於軟體,這是一個物理頁面的序號,將這個序號用作下標就可以從mem_map找到代表這個物理頁面的page資料結構,對於硬體,則(在低位補上12個0後)就是物理頁面的起始地址。

x86保護模式下,段的資訊(段基線性地址、長度、許可權等)即段描述符8個位元組,段資訊無法直接存放在段暫存器中(段暫存器只有2位元組)。Intel的設計是段描述符集中存放在GDTLDT中,而段暫存器存放的是段描述符在GDTLDT內的索引值(index)

Linux中邏輯地址等於線性地址。為什麼這麼說呢?因為Linux所有的段(使用者程式碼段、使用者資料段、核心程式碼段、核心資料段)的線性地址都是從 0x00000000 開始,長度4G,這樣線性地址=邏輯地址+ 0x00000000,也就是說邏輯地址等於線性地址了。

這樣的情況下Linux只用到了GDT,不論是使用者任務還是核心任務,都沒有用到LDTGDT的第1213項段描述符是 __KERNEL_CS __KERNEL_DS,第1415項段描述符是 __USER_CS __USER_DS。核心任務使用__KERNEL_CS__KERNEL_DS,所有的使用者任務共用__USER_CS __USER_DS,也就是說不需要給每個任務再單獨分配段描述符。核心段描述符和使用者段描述符雖然起始線性地址和長度都一樣,但DPL(描述符特權級)是不一樣的。__KERNEL_CS __KERNEL_DS DPL值為0(最高特權),__USER_CS __USER_DSDPL值為3

gdb除錯程式的時候,用info reg 顯示當前暫存器的值:

cs             0x73     115  (使用者程式碼段)

ss             0x7b     123  (使用者資料段)

ds             0x7b     123 (使用者資料段)

es             0x7b     123 (使用者資料段)

可以看到ds值為0x7b, 轉換成二進位制為 00000000 01111011TI欄位值為0,表示使用GDTGDT索引值為 01111,即十進位制15,對應的就是GDT內的__USER_DATA 使用者資料段描述符。

從上面可以看到,Linuxx86的分段機制上執行,卻通過一個巧妙的方式繞開了分段。

Linux主要以分頁的方式實現記憶體管理。


二、線性地址轉實體地址

前面說了Linux中邏輯地址等於線性地址,那麼線性地址怎麼對應到實體地址呢?這個大家都知道,那就是通過分頁機制,具體的說,就是通過頁表查詢來對應實體地址

準確的說分頁是CPU提供的一種機制,Linux只是根據這種機制的規則,利用它實現了記憶體管理。

在保護模式下,控制暫存器CR0的最高位PG位控制著分頁管理機制是否生效,如果PG=1,分頁機制生效,需通過頁表查詢才能把線性地址轉換實體地址。如果PG=0,則分頁機制無效,線性地址就直接做為實體地址

分頁的基本原理是把記憶體劃分成大小固定的若干單元,每個單元稱為一頁(page),每頁包含4k位元組的地址空間(為簡化分析,我們不考慮擴充套件分頁的情況)。這樣每一頁的起始地址都是4k位元組對齊的。為了能轉換成實體地址,我們需要給CPU提供當前任務的線性地址轉實體地址的查詢表,即頁表(page table)。注意,為了實現每個任務的平坦的虛擬記憶體,每個任務都有自己的頁目錄表和頁表

為了節約頁表佔用的記憶體空間,x86將線性地址通過頁目錄表頁表兩級查詢轉換成實體地址。

32位的線性地址被分成3個部分:

最高10 Directory 頁目錄表偏移量,中間10 Table是頁表偏移量,最低12Offset是物理頁內的位元組偏移量。

頁目錄表的大小為4k(剛好是一個頁的大小),包含1024項,每個項4位元組(32位),專案裡儲存的內容就是頁表的實體地址。如果頁目錄表中的頁表尚未分配,則實體地址填0

頁表的大小也是4k,同樣包含1024項,每個項4位元組,內容為最終物理頁的實體記憶體起始地址。

每個活動的任務,必須要先分配給它一個自己的頁目錄表,並把頁目錄表的實體地址存入cr3暫存器。頁表可以提前分配好,也可以在用到的時候再分配

還是以 mov0x80495b0, %eax中的地址為例分析一下線性地址轉實體地址的過程。

前面說到Linux中邏輯地址等於線性地址,那麼我們要轉換的線性地址就是0x80495b0轉換的過程是由CPU自動完成的Linux所要做的就是準備好轉換所需的頁目錄表和頁表(假設已經準備好,給頁目錄表和頁表分配實體記憶體的過程很複雜,後面再分析)。

核心先將當前任務的頁目錄表的實體地址填入cr3暫存器。

每一個程序有它自己的頁全域性目錄和自己的頁表集。當發生程序切換時,Linux把cr3控制暫存器的內容儲存在前一個執行程序的描述符中,然後把下一個要執行程序的描述符的值裝入cr3暫存器中。

因此,當新程序重新開始在CPU上執行時,分頁單元指向一組正確的頁表。

線性地址 0x80495b0 轉換成二進位制後是 0000 1000 0000 0100 1001 0101 1011 0000,最高100000 1000 00的十進位制是32CPU檢視頁目錄表第32項,裡面存放的是頁表的實體地址。線性地址中間1000 0100 1001 的十進位制是73,頁表的第73項儲存的是最終物理頁的物理起始地址。物理頁基地址加上線性地址中最低12位的偏移量,CPU就找到了線性地址最終對應的實體記憶體單元。

我們知道Linux中使用者程序線性地址能定址的範圍是 3G,那麼是不是需要提前先把這3G虛擬記憶體的頁表都建立好呢?一般情況下,實體記憶體是遠遠小於3G的,加上同時有很多程序都在執行,根本無法給每個程序提前建立3G的線性地址頁表。Linux利用CPU的一個機制解決了這個問題。程序建立後我們可以給頁目錄表的表項值都填0CPU在查詢頁表時,如果表項的內容為0,則會引發一個缺頁異常,程序暫停執行,Linux核心這時候可以通過一系列複雜的演算法給分配一個物理頁,並把物理頁的地址填入表項中,程序再恢復執行。當然程序在這個過程中是被矇蔽的,它自己的感覺還是正常訪問到了實體記憶體。



http://blog.163.com/huawei_d/blog/static/211610257201321054753140/

相關推薦

Linux機制

分段可以給每個程序分配一個不同的程序地址空間,而分頁可以把相同的線性地址空間對映到不同的實體地址空間。 通俗的講,就是每個程序都有一個虛擬地址到實體地址的轉換表,而這個轉換表不同的程序是不同的。所以就會出現不同程序的同一個虛擬地址對應不同的實體地址 一、邏輯地址轉線性地

Linux內存尋址之機制

緩存 itl ans linux 存儲器 apt target tar linux中 http://blog.xiaohansong.com/2015/10/05/Linux內存尋址之分頁機制/ 在上一篇文章Linux內存尋址之分段機制中,我們了解邏輯地址通過分段機制轉換為

Linux機制之概述--Linux記憶體管理(六)

1 分頁機制 在虛擬記憶體中,頁表是個對映表的概念, 即從程序能理解的線性地址(linear address)對映到儲存器上的實體地址(phisical address). 很顯然,這個頁表是需要常駐記憶體的東西, 以應對頻繁的查詢對映需要(實際上,現代支援VM的處理器都有一個叫TLB的硬體級頁表快取部件

Linux機制機制的演變--Linux記憶體管理(七)

1 頁式管理 1.1 分段機制存在的問題 分段,是指將程式所需要的記憶體空間大小的虛擬空間,通過對映機制對映到某個實體地址空間(對映的操作由硬體完成)。分段對映機制解決了之前作業系統存在的兩個問題: 地址空間沒有隔離 程式執行的地址不確定 不過分段方法存在一個嚴重的問題:記憶體的使用效率

Linux機制

分頁機制為傳統需求頁、虛擬記憶體系統提供了實現機制 系統中的線性地址比實際的實體地址大的多,所以進行虛擬化線性地址空間,即虛擬儲存技術 當使用分頁時,每個段被劃分成頁面(每頁通常4KB或者1位元組)

Linux核心原始碼分析--記憶體管理(一、機制

        Linux系統中分為幾大模組:程序排程、記憶體管理、程序通訊、檔案系統、網路模組;各個模組之間都有一定的聯絡,就像蜘蛛網一樣,所以這也是為什麼Linux核心那麼難理解,因為不知道從哪裡開始著手去學習。很多人會跟著系統上電啟動 BIOS-->bootse

Linux記憶體地址的分段、機制(上)

在深入學習Linux核心原始碼之前,需要先對Linux執行的硬體基礎有個大概的認識,主要包括CPU中的暫存器和磁碟。 1.i386暫存器和系統指令 在Linux系統中使用的主要包括i386暫存器中的16位標誌暫存器,4個記憶體管理暫存器和4個控制暫存器及

深入詳解保護模式的記憶體機制

以下是Intel文件中關於分頁機制的詳細描述:IA-32 Memory Models When employing the processor’s memory management facilities, programs do not       — 使用處理器記憶體管理設施時程式不會 directly

Linux的記憶體定址——淺談分段和機制

本文會以80x86架構,linux2.6為例,簡單介紹記憶體的分段和分頁機制。1. 三種記憶體地址關於記憶體地址,首先要了解它有三種,分別是邏輯地址、線性地址和實體地址。把邏輯地址轉換為線性地址是由一個叫做分段單元的硬體電路完成的。同樣地,還有一個叫做分頁單元的硬體電路負責把

Linux機制機制的實現詳解--Linux記憶體管理(八)

[注意] 如果您當前使用的系統並不是linux,或者您的系統中只有一份linux原始碼,而您又期待能夠檢視或者檢索不同版本的linux原始碼 LXR (Linux Cross Reference)是比較流行的linux

Linux記憶體管理解析(一) : 分段與機制

背景 : 在此文章裡會從分頁分段機制去解析Linux記憶體管理系統如何工作的,由於Linux記憶體管理過於複雜而本人能力有限。會盡量將自己總結歸納的部分寫清晰。 從真實模式到保護模式的定址方式的不同 :    16位CPU的定址方式 : 在 8086 CPU 中,提供了兩類暫存器來進行定址,分別為段

作業系統:x86記憶體機制 (1)

前置知識: 分段的概念(當然手寫過肯定是墜吼的 ##為什麼要分頁 當我們寫程式的時候,總是傾向於把一個完整的程式分成最基本的資料段,程式碼段,棧段。並且普通的分段機制就是在程序所屬的LDT中把每一個段給標識出來。但是在實際運用中,大多數程序不會無限地執行下去。當程序結束之後它佔有的記憶體空間也會被釋放。

SSM框架的實現(封裝page.java和List<?>)

添加 interface jsp頁面 har show 初始化 ring array dex 之前寫過一篇博客 java分頁的實現(後臺工具類和前臺jsp頁面),介紹了分頁的原理。 今天整合了Spring和SpringMVC和MyBatis,做了增刪改查和分頁,之前的邏輯

Linux區、格式化、自動掛載

-1 tar code sudo mkf mount -a etc 目錄 detail 說明:現在硬盤基本沒有了IDE,所以基本是從SCSI開始說起,第一塊硬盤標示為sda,第二塊為sdb,以此類推。那麽第一塊硬盤的第一個分區為sda1,也是以此類推。 一、硬盤分區

LINUX區命令Parted詳解

運行 script mbr gpt分區 ble 版本號 may was mkpart 通常劃分分區工具我們用的比較多是fdisk命令,但是現在由於磁盤越來越廉價,而且磁盤空間越來越大。而fdisk工具他對分區是有大小限制的,它只能劃分小於2T的磁盤。現在的磁盤

2017-2018-1 20155222 《信息安全系統設計基礎》第10周 Linux的IPC機制

mct 執行 除了 comm 同進程 href sem_flag 消息隊列 con 2017-2018-1 20155222 《信息安全系統設計基礎》第10周 Linux下的IPC機制 IPC機制 在linux下的多個進程間的通信機制叫做IPC(Inter-Process

操作系統學習(三)、機制

x86 頁面 管理機 技術 由於 映射 空間 pos 邏輯地址 目錄 1.分頁機制介紹 2.頁表結構 3.頁表項格式 4.虛擬存儲 5.直達底部 分頁機制介紹 分頁機制是 80x86 內存管理機制的第二部分。它在分段機制的基礎上完成虛擬地址到物理地址的轉換過程。分段

Linux查看文件內容

string 結束 進行 cell ctrl str middle 繼續 cte 按鍵 進行工作 空格鍵 向下翻一頁 [Page Down] 向下翻一頁 [Page Up] 向上翻一頁 [Ctrl + U] 向上翻一頁 [Ctrl + D] 向下翻

Linux布式系統以及CAP理論分析

單機 osql 問題 實例 ase 均衡負載 sof rds 就是 CAP理論被很多人拿來作為分布式系統設計的金律,然而感覺大家對CAP這三個屬性的認識卻存在不少誤區,那麽什麽是CAP理論呢?CAP原本是一個猜想,2000年PODC大會的時候大牛Brewer提出的,他認

記憶體的管理和機制

一、問題提出: 我們經常會使用malloc()以及free()函式進行堆區記憶體申請與釋放。那麼你是否會這樣做: int * p = malloc(0);/*malloc分配了0個位元組嗎,如果是那麼p指向誰呢,是NULL嗎*/ free(p);/*假如malloc分配了0個位元組,p指向了NU