最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

一文帶你深入理解Linux內(nèi)核之內(nèi)存尋址

2022-06-30 20:13 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

一、內(nèi)存地址

1.1 邏輯地址 (logic address)

在機(jī)器語(yǔ)言指令中用來(lái)指定一個(gè)操作數(shù)或一條指令的地址,每一個(gè)邏輯地址都由以下兩部分組成

  • 段 (segment)指明段位置

  • 偏移量 (offset)指明段開(kāi)始處到實(shí)際地址的距離

1.2 虛擬地址 (virtual address)

根據(jù)機(jī)器的位數(shù)不同而不同,32位機(jī)器即32位無(wú)符號(hào)整數(shù)、64位即64位無(wú)符號(hào)整數(shù),這里取32位為例。

  • 可用于表達(dá) 即 4GB 的地址空間

  • 通常用16進(jìn)制表示,值的范圍從 0x00000000 ~ 0xffffffff

1.3 物理地址 (physical address)

內(nèi)存芯片級(jí)的內(nèi)存單元尋址,從CPU的地址引腳發(fā)送到內(nèi)存總線上的電信號(hào)相對(duì)應(yīng),由 32 位或 36 位無(wú)符號(hào)整數(shù)表示

1.4 內(nèi)存控制單元 MMU

內(nèi)存控制單元以下簡(jiǎn)稱MMU,其集成在CPU上進(jìn)行地址翻譯,轉(zhuǎn)換過(guò)程為兩階段

  • 分段:由邏輯地址到虛擬地址

  • 分頁(yè):由虛擬地址到物理地址


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺(jué)得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ? ??


在多核系統(tǒng)中,所有的CPU核心共享同一內(nèi)存,則代表著CPU可以并發(fā)的訪問(wèn)內(nèi)存。而內(nèi)存的讀寫必須是串行執(zhí)行,所以需要專用元器件對(duì)內(nèi)存訪問(wèn)進(jìn)行排序,其稱為內(nèi)存仲裁器。

內(nèi)存仲裁器是在內(nèi)存總線和RAM芯片之間的硬件電路

  • 若內(nèi)存空閑:允許訪問(wèn)

  • 若內(nèi)存被占用:延遲CPU訪問(wèn)

注:由于單處理器上存在一個(gè)叫做DMA控制器的特殊處理器,因此其實(shí)單處理器上也有內(nèi)存仲裁器

1.6 分段和分頁(yè)的意義

分段和分頁(yè)是用于劃分進(jìn)程的物理地址空間的

  • 分段:每個(gè)進(jìn)程分配不同的虛擬地址空間

  • 分頁(yè):把同一虛擬地址空間映射到不同的物理地址

Linux更多使用分頁(yè)的方式

  • 不同進(jìn)程共享同一組虛擬地址空間,內(nèi)存管理簡(jiǎn)單

  • 跨平臺(tái),因?yàn)镽ISC體系結(jié)構(gòu)對(duì)分段支持有限

二、內(nèi)存分段


2.1 硬件分段

2.1.1 實(shí)模式和保護(hù)模式

從 80286 模型開(kāi)始,Intel處理器采用兩種不同方式進(jìn)行地址轉(zhuǎn)換,稱為實(shí)模式(real mode)和保護(hù)模式(protected mode)

  • 實(shí)模式其作用是為維持處理器和早期模型的兼容,因?yàn)樵缙诩拇嫫魑粩?shù)太少,物理地址有20位,最多1MB的內(nèi)存空間。而段基址寄存器有16位,最多只能訪問(wèn)64kb。為了訪問(wèn)64kb以上的空間,需要對(duì)內(nèi)存進(jìn)行分段,使用段基址+段偏移的模式尋址。 通過(guò) 物理地址 = 段基址 << 4 + 段內(nèi)偏移 的方式表示物理地址。這個(gè)實(shí)模式的 “實(shí)” 體現(xiàn)在其反應(yīng)的是真實(shí)物理地址。 但是由于實(shí)模式?jīng)]有區(qū)分代碼和數(shù)據(jù),如果用戶程序的一個(gè)指針如果指向了系統(tǒng)程序區(qū)域或其他用戶程序區(qū)域,并修改了內(nèi)容,那么后果就很可能是災(zāi)難性的。

  • 保護(hù)模式

隨著寄存器硬件的擴(kuò)展,地址位數(shù)和寄存器位數(shù)都變成了32/64位,現(xiàn)代CPU已經(jīng)不需要使用上述實(shí)模式了,當(dāng)然為了兼容老版本所以還是得支持實(shí)模式。

同時(shí)由于實(shí)模式不安全,我們通過(guò)一些手段來(lái)實(shí)現(xiàn)比較安全的尋址,這也是保護(hù)模式的命名的由來(lái)。

  1. 地址保護(hù):程序內(nèi)部的地址(虛擬地址)要由操作系統(tǒng)轉(zhuǎn)化為物理地址去訪問(wèn),程序?qū)Υ艘粺o(wú)所知

  2. 邊界保護(hù): 段寄存器中不再儲(chǔ)存的是段地址而是段索引。我們將數(shù)據(jù)放在一個(gè)叫做全局描述符表(GDT) 的結(jié)構(gòu)中,其中表項(xiàng)稱為段描述符,段描述符存放了段基址、段界限、內(nèi)存段類型屬性,用來(lái)索引段地址和標(biāo)記段邊界。

2.1.2 段選擇符和段寄存器

  • 段選擇符邏輯地址 = 段標(biāo)識(shí)符 (16位) + 段偏移量 (32位),我們又將段標(biāo)識(shí)符稱為段選擇符,其結(jié)構(gòu)如下圖所示

  • index 描述符的入口,在2.1.4節(jié)中會(huì)詳細(xì)講解

  • TI (Table Indicator)標(biāo)明段在GDT還是LDT中,在GDT中為0,LDT中為1

  • RPL 請(qǐng)求特權(quán)級(jí),cs寄存器改變時(shí)指示出CPU當(dāng)前特權(quán)級(jí)

  • 段寄存器段寄存器存放段選擇符,段寄存器共有 cs,ss,ds,es,fs和gs六個(gè),其作用如圖三所示。 注:cs寄存器中還有一個(gè)兩位的字段,指明CPU當(dāng)前特權(quán)級(jí)別(CPL)0~3,Linux只用0和3,代表內(nèi)核態(tài)和用戶態(tài) ?





2.1.3 段描述符

每個(gè)段被一個(gè)8字節(jié)的段描述符(Segment Descriptor)表示,描述了段的特征。

其放在 全局描述符表(GDT - Global Descriptor Table) 或 局部描述符表 (LDT - Local Descriptor Table) 中

  • 全局描述符表(GDT - Global Descriptor Table)- 特點(diǎn):進(jìn)程共享 ? - 存放:gdtr寄存器(基址+大?。?/p>

  • 局部描述符表 (LDT - Local Descriptor Table)

  • 特點(diǎn):進(jìn)程獨(dú)享

  • 存放:ldtr寄存器(基址+大?。?/p>

  • 段描述符字段

  • 描述符段分類


  • 代表任務(wù)狀態(tài)段(TSS)用于保存寄存器內(nèi)容,僅在GDT中

  • 代碼段描述符

  • 數(shù)據(jù)段描述符

  • 任務(wù)狀態(tài)段描述符 (TSSD)

2.1.4 快速訪問(wèn)段描述符

  • 段描述符的索引規(guī)則:段基址 + 段選擇符 index [13位] << 3 因此描述符最大數(shù)目為2^13-1

2.1.5 分段單元

圖六已經(jīng)較為清楚的展示了分段單元把邏輯地址轉(zhuǎn)為虛擬地址的過(guò)程,段選擇符在段寄存器中,offset存儲(chǔ)在ip寄存器中



邏輯地址翻譯

2.2 Linux 分段


2.2.1 Linux中的段結(jié)構(gòu)

2.6版的Linux只有在 80x86 結(jié)構(gòu)下才進(jìn)行分段,下圖為L(zhǎng)inux的分段結(jié)構(gòu)


Linux分段

所有段都從0x00000000開(kāi)始,所以在Linux下,邏輯地址和虛擬地址相同

相應(yīng)端選擇符由宏 __USER_CS、__USER_DS、__KERNEL_CS、__KERNEL_DS 定義

CPU的CPL存儲(chǔ)在 cs 寄存器的 RPL 字段中,特權(quán)級(jí)別改變,某些段寄存器必須更新

例如當(dāng)CPL由 3 變?yōu)?0 時(shí) ds寄存器必須從含有用戶態(tài)數(shù)據(jù)段的段選擇符變?yōu)楹袃?nèi)核數(shù)據(jù)段的段選擇符,ss類似


2.2.2 Linux GDT

每個(gè)CPU對(duì)應(yīng)一個(gè)GDT,所有的GDT都存放在 cpu_gdt_table 里,所有的GDT地址和大小被存放在 cpu_gdt_descr數(shù)組中。

這些符號(hào)在 arch/i386/kernel/head.S 中被定義

每個(gè)GDT包含 18個(gè)段描述符和14個(gè)空的保留項(xiàng),保留項(xiàng)保證了常用的描述符可以在同一個(gè)32字節(jié)的 Cache 中,防止 Cache 抖動(dòng)。


Linux GDT結(jié)構(gòu)

三、內(nèi)存分頁(yè)

3.1 硬件分頁(yè)

分頁(yè)單元(Paging Unit)是將虛擬地址轉(zhuǎn)化為物理地址

關(guān)鍵任務(wù):是將所請(qǐng)求的訪問(wèn)類型和虛擬地址訪問(wèn)權(quán)限相比較,如果訪問(wèn)無(wú)效,則產(chǎn)生缺頁(yè)異常

頁(yè):一組虛擬地址,又指包含在這組地址中的數(shù)據(jù)。把RAM分成固定長(zhǎng)度的頁(yè)框(Page Frame)每個(gè)頁(yè)框(結(jié)構(gòu))包含一個(gè)頁(yè)(數(shù)據(jù))。

頁(yè)表:將虛擬地址映射到物理地址的數(shù)據(jù)結(jié)構(gòu)

cr0寄存器:PG標(biāo)志為0,虛擬地址就解釋為物理地址,否則如果 PG = 1 代表啟用分頁(yè)。

3.2 Linux 分頁(yè)

Linux采用4級(jí)分頁(yè)模式,節(jié)省內(nèi)存空間花費(fèi),頁(yè)表基址寄存器cr3

  • 頁(yè)全局目錄 (Page Global Directory)

  • 頁(yè)上級(jí)目錄(Page Upper DIrectory)

  • 頁(yè)中間目錄(Page Middle Directory)

  • 頁(yè)表 (Page Table)




Linux多級(jí)分頁(yè)

如圖所示,虛擬地址翻譯過(guò)程,其將虛擬地址分為五部分,標(biāo)準(zhǔn)頁(yè)大小4kb,所以offset占12位,剩下 52 位 每 13 位代表相應(yīng)目錄偏移量,先取出cr3寄存器中頁(yè)全局目錄的基址,和偏移量相加,索引到下級(jí)頁(yè)上級(jí)目錄的極致,如此重復(fù),直到索引到頁(yè)表取出 PPN,由于物理地址偏移量和虛擬地址相同,所以直接和虛擬地址偏移量 VPO 拼接得到物理地址.

為什么要使用多級(jí)頁(yè)表來(lái)完成映射呢?


用來(lái)將虛擬地址映射到物理地址的數(shù)據(jù)結(jié)構(gòu)稱為頁(yè)表, 實(shí)現(xiàn)兩個(gè)地址空間的關(guān)聯(lián)最容易的方式是使用數(shù)組, 對(duì)虛擬地址空間中的每一頁(yè), 都分配一個(gè)數(shù)組項(xiàng). 該數(shù)組指向與之關(guān)聯(lián)的頁(yè)幀, 但這會(huì)引發(fā)一個(gè)問(wèn)題, 例如, IA-32體系結(jié)構(gòu)使用4KB大小的頁(yè), 在虛擬地址空間為4GB的前提下, 則需要包含100萬(wàn)項(xiàng)的頁(yè)表. 這個(gè)問(wèn)題在64位體系結(jié)構(gòu)下, 情況會(huì)更加糟糕. 而每個(gè)進(jìn)程都需要自身的頁(yè)表, 這回導(dǎo)致系統(tǒng)中大量的所有內(nèi)存都用來(lái)保存頁(yè)表.

設(shè)想一個(gè)典型的32位的X86系統(tǒng),它的虛擬內(nèi)存用戶空間(user space)大小為3G, 并且典型的一個(gè)頁(yè)表項(xiàng)(page table entry, pte)大小為4 bytes,每一個(gè)頁(yè)(page)大小為4k bytes。那么這3G空間一共有(3G/4k=)786432個(gè)頁(yè)面,每個(gè)頁(yè)面需要一個(gè)pte來(lái)保存映射信息,這樣一共需要786432個(gè)pte!

如何存儲(chǔ)這些信息呢?一個(gè)直觀的做法是用數(shù)組來(lái)存儲(chǔ),這樣每個(gè)頁(yè)能存儲(chǔ)(4k/4=)1K個(gè),這樣一共需要(786432/1k=)768個(gè)連續(xù)的物理頁(yè)面(phsical page)。而且,這只是一個(gè)進(jìn)程,如果要存放所有N個(gè)進(jìn)程,這個(gè)數(shù)目還要乘上N! 這是個(gè)巨大的數(shù)目,哪怕內(nèi)存能提供這樣數(shù)量的空間,要找到連續(xù)768個(gè)連續(xù)的物理頁(yè)面在系統(tǒng)運(yùn)行一段時(shí)間后碎片化的情況下,也是不現(xiàn)實(shí)的。

假設(shè)每個(gè)進(jìn)程都占用了4G的線性地址空間,頁(yè)表共含1M個(gè)表項(xiàng),每個(gè)表項(xiàng)占4個(gè)字節(jié),那么每個(gè)進(jìn)程的頁(yè)表要占據(jù)4M的內(nèi)存空間。為了節(jié)省頁(yè)表占用的空間,我們使用兩級(jí)頁(yè)表。每個(gè)進(jìn)程都會(huì)被分配一個(gè)頁(yè)目錄,但是只有被實(shí)際使用頁(yè)表才會(huì)被分配到內(nèi)存里面。一級(jí)頁(yè)表需要一次分配所有頁(yè)表空間,兩級(jí)頁(yè)表則可以在需要的時(shí)候再分配頁(yè)表空間,而Linux根據(jù)實(shí)際情況(64位CPU,內(nèi)存大小,查詢效率),選擇4級(jí)頁(yè)表。


3.2.1 分頁(yè)機(jī)制的優(yōu)勢(shì)

虛擬地址到物理地址的自動(dòng)轉(zhuǎn)換使得下述設(shè)計(jì)目標(biāo)變得現(xiàn)實(shí)

  • 給每個(gè)進(jìn)程分配不同的物理地址空間,防止尋址錯(cuò)誤

  • 區(qū)別頁(yè)和頁(yè)框不同,允許頁(yè)被裝入不同的頁(yè)框中,是虛擬內(nèi)存機(jī)制的基本要素

每個(gè)進(jìn)程有自己的頁(yè)全局目錄和頁(yè)表集合,每次進(jìn)行進(jìn)程上下文切換時(shí),Linux內(nèi)核把前一個(gè)進(jìn)程的cr3寄存器值存入在前一個(gè)進(jìn)程的進(jìn)程描述符中,并載入新進(jìn)程的全局目錄基址進(jìn)入cr3寄存器中。

3.2.2 進(jìn)程頁(yè)表

進(jìn)程的虛擬內(nèi)存空間被分為兩部分

  • 用戶態(tài)尋址部分:0x00000000 ~ 0xbfffffff

  • 內(nèi)核態(tài)尋址部分:0xc0000000 ~ 0xffffffff

進(jìn)程運(yùn)行在用戶態(tài)時(shí),其產(chǎn)生的線性地址小于 0xc0000000,在內(nèi)核態(tài)則隨意

3.2.3 內(nèi)核頁(yè)表

內(nèi)核有自己的一組頁(yè)表,存放在主內(nèi)核頁(yè)全局目錄中。主內(nèi)核頁(yè)全局目錄的最高目錄項(xiàng)部分作為參考模型,為系統(tǒng)中每個(gè)普通進(jìn)程對(duì)應(yīng)的頁(yè)全局目錄項(xiàng)提供參考模型。



一文帶你深入理解Linux內(nèi)核之內(nèi)存尋址的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
抚顺县| 和龙市| 城口县| 伊春市| 丽江市| 当涂县| 崇左市| 手游| 青州市| 德惠市| 永昌县| 黄大仙区| 龙胜| 青田县| 鄂温| 罗田县| 荆州市| 旌德县| 永川市| 家居| 鄂尔多斯市| 蕉岭县| 西盟| 闻喜县| 吉水县| 嵊州市| 根河市| 鄂州市| 苏尼特右旗| 沙田区| 云安县| 渭南市| 黎城县| 即墨市| 浦东新区| 贵南县| 高雄市| 长治市| 宝兴县| 习水县| 宁夏|