Linux 核心空間虛擬位址和實體地址相互轉換

2021-07-13 23:59:21 字數 1528 閱讀 8032

個人學習筆記,可能會有錯誤之處,敬請諒解。

一直以來感覺虛擬位址和實體地址之間的相互轉換非常麻煩,虛擬位址到實體地址的轉換由cpu硬體完成,但實體地址到虛擬位址怎麼轉換啊?況且有時候在軟體上也希望通過乙個虛擬位址得到實體地址,這時候自然不能依賴cpu的硬體了,該怎麼轉換呢?

#define __va(x)                 ((void *)((unsigned long)(x)+page_offset))

#define page_offset             ((unsigned long)__page_offset)
巨集__page_offset在arch/x86/include/asm/page_64_types.h中定義如下:

#define __page_offset           _ac(0xffff880000000000, ul)
__ac也是巨集定義在include/uapi/linux/const.h中:

#ifdef __assembly__

#define _ac(x,y) x

#define _at(t,x) x

#else

#define __ac(x,y) (x##y)

#define _ac(x,y) __ac(x,y)

#define _at(t,x) ((t)(x))

#endif

這是為了適應assembly和c不同的語法定義的巨集,可能這就是巨集 __ac 名字的**吧。

可想而知,虛擬位址到實體地址的轉換應該也很簡單吧,就把這個偏移量減去就行了唄。。。

在arch/x86/include/asm/page.h中由該巨集定義:

#define __pa(x)         __phys_addr((unsigned long)(x))

__phys_addr 的定義在arch/x86/mm/physaddr.c中如下:

unsigned long __phys_addr(unsigned long x)

else

return x;

}

__start_kernel_map 也是乙個偏移量,也在arch/x86/include/asm/page_64_types.h中

#define __start_kernel_map      _ac(0xffffffff80000000, ul)

其實如果只看 else 部分,簡單算術就知道,從虛擬位址到實體地址轉換就是減去了乙個 page_offset。至於 if 部分,"unlikely" 都告訴你了,這部分**執行概率不高,哈哈,不去細究 phys_base 是什麼了。。。

不過以上簡單的轉換只適用於核心位址空間,使用者位址空間當然就不會這麼簡單了,現在還沒搞懂。。。

Linux虛擬位址空間

在多工作業系統中,每個程序都執行在屬於自己的記憶體沙盤中。這個沙盤就是虛擬位址空間 virtual address space 在32位模式下它是乙個4gb的記憶體位址塊,這篇部落格均是x86架構的 1.位址空間分布 2.核心位址空間 從pkmap base 到 fixaddr start用於對映高...

Linux虛擬位址空間

為了防止不同程序同一時刻在物理記憶體中執行而對物理記憶體的爭奪和踐踏,採用了虛擬記憶體。虛擬記憶體技術使得不同程序在執行過程中,它所看得到的是自己獨自占有了當前系統的4g記憶體。所有程序共享同一物理記憶體,每個程序只把自己目前需要的虛擬記憶體空間對映並儲存到物理記憶體上。事實上,在每個程序建立載入時...

虛擬位址空間

當處理器讀或寫入記憶體位置時,它會使用虛擬位址。作為讀或寫操作的一部分,處理器將虛擬位址轉換為實體地址。通過虛擬位址訪問記憶體有以下優勢 程序可用的虛擬位址範圍稱為該程序的 虛擬位址空間 每個使用者模式程序都有其各自的專用虛擬位址空間。對於 32 位程序,虛擬位址空間通常為 2 gb,範圍從 0x0...