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