W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
本章研究 Linux 內(nèi)存管理的部分, 重點(diǎn)在對(duì)于設(shè)備驅(qū)動(dòng)作者有用的技術(shù). 許多類型的驅(qū)動(dòng)編程需要一些對(duì)于虛擬內(nèi)存子系統(tǒng)如何工作的理解; 我們?cè)诒菊律婕暗降牟牧蟻碜允诸^, 而不是象我們?cè)M(jìn)入更加復(fù)雜和性能關(guān)鍵的子系統(tǒng)一樣. 虛擬內(nèi)存子系統(tǒng)也是 Linux 內(nèi)核核心的非常有趣的部分, 并且因而, 值得一見.
本章的材料分為 3 個(gè)部分:
第一部分涉及 mmap 系統(tǒng)調(diào)用的實(shí)現(xiàn), 它允許設(shè)備內(nèi)存直接映射到一個(gè)用戶進(jìn)程地址空間. 不是所有的設(shè)備需要 mmap 支持, 但是, 對(duì)一些, 映射設(shè)備內(nèi)存可產(chǎn)生可觀的性能提高.
我們接著看從其他的方向跨過邊界, 用對(duì)直接存取用戶空間的討論. 相對(duì)少驅(qū)動(dòng)需要這個(gè)能力; 在大部分情況下, 內(nèi)核做這種映射而驅(qū)動(dòng)甚至不知道它. 但是了解如何映射用戶空間內(nèi)存到內(nèi)核(使用 get_user_pages)會(huì)有用.
最后一節(jié)涵蓋直接內(nèi)存存取( DMA ) I/O 操作, 它提供給外設(shè)對(duì)系統(tǒng)內(nèi)存的直接存取.
當(dāng)然, 所有這些技術(shù)需要一個(gè)對(duì) Linux 內(nèi)存管理如何工作的理解, 因此我們從對(duì)這個(gè)子系統(tǒng)的總覽開始.
不是描述操作系統(tǒng)的內(nèi)存管理理論, 本節(jié)試圖指出 Linux 實(shí)現(xiàn)的主要特點(diǎn). 盡管你不必是一位 Linux 虛擬內(nèi)存專家來實(shí)現(xiàn) mmap, 一個(gè)對(duì)事情如何工作的基本了解是有用的. 下面是一個(gè)相當(dāng)長(zhǎng)的對(duì)內(nèi)核使用來管理內(nèi)存的數(shù)據(jù)結(jié)構(gòu)的描述. 一旦必要的背景已被覆蓋, 我們就進(jìn)入使用這個(gè)結(jié)構(gòu).
Linux 是, 當(dāng)然, 一個(gè)虛擬內(nèi)存系統(tǒng), 意味著用戶程序見到的地址不直接對(duì)應(yīng)于硬件使用的物理地址. 虛擬內(nèi)存引入了一個(gè)間接層, 它允許了許多好事情. 有了虛擬內(nèi)存, 系統(tǒng)重運(yùn)行的程序可以分配遠(yuǎn)多于物理上可用的內(nèi)存; 確實(shí), 即便一個(gè)單個(gè)進(jìn)程可擁有一個(gè)虛擬地址空間大于系統(tǒng)的物理內(nèi)存. 虛擬內(nèi)存也允許程序?qū)M(jìn)程的地址空間運(yùn)用多種技巧, 包括映射成員的內(nèi)存到設(shè)備內(nèi)存.
至此, 我們已經(jīng)討論了虛擬和物理地址, 但是許多細(xì)節(jié)被掩蓋過去了. Linux 系統(tǒng)處理幾種類型的地址, 每個(gè)有它自己的含義. 不幸的是, 內(nèi)核代碼不是一直非常清楚確切地在每個(gè)情況下在使用什么類型地地址, 因此程序員必須小心.
下面是一個(gè) Linux 中使用的地址類型列表. 圖 Linux 中使用的地址類型顯示了這個(gè)地址類型如何關(guān)聯(lián)到物理內(nèi)存.
圖?15.1.?Linux 中使用的地址類型
User virtual addresses
這是被用戶程序見到的常規(guī)地址. 用戶地址在長(zhǎng)度上是 32 位或者 64 位, 依賴底層的硬件結(jié)構(gòu), 并且每個(gè)進(jìn)程有它自己的虛擬地址空間.
Physical addresses
在處理器和系統(tǒng)內(nèi)存之間使用的地址. 物理地址是 32- 或者 64-位的量; 甚至 32-位系統(tǒng)在某些情況下可使用更大的物理地址.
Bus addresses
在外設(shè)和內(nèi)存之間使用的地址. 經(jīng)常, 它們和被處理器使用的物理地址相同, 但是這不是必要的情況. 一些體系可提供一個(gè) I/O 內(nèi)存管理單元(IOMMU), 它在總線和主內(nèi)存之間重映射地址. 一個(gè) IOMMU 可用多種方法使事情簡(jiǎn)單(例如, 使散布在內(nèi)存中的緩沖對(duì)設(shè)備看來是連續(xù)的, 例如), 但是當(dāng)設(shè)定 DMA 操作時(shí)對(duì) IOMMU 編程是一個(gè)必須做的額外的步驟. 總線地址是高度特性依賴的, 當(dāng)然.
Kernel logical addresses
這些組成了正常的內(nèi)核地址空間. 這些地址映射了部分(也許全部)主存并且常常被當(dāng)作它們是物理內(nèi)存來對(duì)待. 在大部分的體系上, 邏輯地址和它們的相關(guān)物理地址只差一個(gè)常量偏移. 邏輯地址使用硬件的本地指針大小并且, 因此, 可能不能在重裝備的 32-位系統(tǒng)上尋址所有的物理內(nèi)存. 邏輯地址常常存儲(chǔ)于 unsigned long 或者 void * 類型的變量中. 從 kmalloc 返回的內(nèi)存有內(nèi)核邏輯地址.
Kernel virtual addresses
內(nèi)核虛擬地址類似于邏輯地址, 它們都是從內(nèi)核空間地址到物理地址的映射. 內(nèi)核虛擬地址不必有邏輯地址空間具備的線性的, 一對(duì)一到物理地址的映射, 但是. 所有的邏輯地址是內(nèi)核虛擬地址, 但是許多內(nèi)核虛擬地址不是邏輯地址. 例如, vmalloc 分配的內(nèi)存有虛擬地址(但沒有直接物理映射). kmap 函數(shù)(本章稍后描述)也返回虛擬地址. 虛擬地址常常存儲(chǔ)于指針變量.
如果你有邏輯地址, 宏 pa() ( 在 <asm/page.h> 中定義)返回它的關(guān)聯(lián)的物理地址. 物理地址可被映射回邏輯地址使用 va(), 但是只給低內(nèi)存頁(yè).
不同的內(nèi)核函數(shù)需要不同類型地址. 如果有不同的 C 類型被定義可能不錯(cuò), 這樣請(qǐng)求的地址類型是明確的, 但是我們沒有這樣的好運(yùn). 在本章, 我們盡力對(duì)在哪里使用哪種類型地址保持清晰.
物理內(nèi)存被劃分為離散的單元稱為頁(yè). 系統(tǒng)的許多內(nèi)部?jī)?nèi)存處理在按頁(yè)的基礎(chǔ)上完成. 頁(yè)大小一個(gè)體系不同于另一個(gè), 盡管大部分系統(tǒng)當(dāng)前使用 4096-字節(jié)的頁(yè). 常量 PAGE_SIZE (定義在 <asm/page.h>) 給出了頁(yè)大小在任何給定的體系上.
如果你查看一個(gè)內(nèi)存地址 - 虛擬或物理 - 它可分為一個(gè)頁(yè)號(hào)和一個(gè)頁(yè)內(nèi)的偏移. 如果使用 4096-字節(jié)頁(yè), 例如, 12 位低有效位是偏移, 并且剩下的, 高位指示頁(yè)號(hào). 如果你丟棄偏移并且向右移動(dòng)剩下的部分 offset 位, 結(jié)果被稱為一個(gè)頁(yè)幀號(hào) (PFN). 移位來在頁(yè)幀號(hào)和地址之間轉(zhuǎn)換是一個(gè)相當(dāng)普通的操作. 宏 PAGE_SHIFT 告訴必須移動(dòng)多少位來進(jìn)行這個(gè)轉(zhuǎn)換.
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: