首先我們基於平坦型物理記憶體,單個node,下面是基於64位armv8架構得到,其他架構也有類似結論:arm64:
ffffffc000080000 t _text
ffffffc000080160 t stext
ffffffc000083000 t vectors
ffffffc0010890b8 b __bss_start
ffffffc0010890b8 d _edata
ffffffc00191ab58 b mem_map
ffffffc00191ab60 b max_mapnr
ffffffc001c7dd28 b __bss_stop
ffffffc001c7e000 b idmap_pg_dir
ffffffc001c82000 b _end
arm:
c0008000 t _text
c0008000 t stext
c0008090 t __create_page_tables
c0008168 t __turn_mmu_on_loc
c0008174 t secondary_startup
c00081e0 t __secondary_switched
c00081ec t __secondary_data
c00081f8 t __enable_mmu
c0008220 t __vet_atags
c0008280 t __exception_text_start
c0008280 t _stext
c0008280 t asm_do_irq
c0008284 t do_undefinstr
c0caccb8 b suspend_time
c0caccc0 b last_transmit
c0caccc8 b activity_lock
c0caccd0 b klist_remove_lock
c0caccd4 b __bss_stop
c0caccd4 b _end
對於arm來說,32位和64位明顯不同。
對整個核心空間**和資料來說,由於他們是直接對映的,我們這裡討論起來非常簡單
對於這些位址,核心通過巨集__pa()找到這些虛擬位址對應的實體地址。或者通過__va()找到實體地址對應
的虛擬位址。
arch/arm64/include/asm/memory.h
#define __pa(x) __virt_to_phys((unsigned long)(x))
#define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x)))
#define pfn_to_kaddr(pfn) __va((pfn) << page_shift)
#define virt_to_pfn(x) __phys_to_pfn(__virt_to_phys(x))
繼續看定義:
include/asm-generic/memory-module.h
#define __virt_to_phys(x) (((phys_addr_t)(x) - page_offset + phys_offset))
#define __phys_to_virt(x) ((unsigned long)((x) - phys_offset + page_offset))
#define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> page_shift))
#define __pfn_to_phys(pfn) ((phys_addr_t)(pfn) << page_shift)
#define __pfn_to_page(pfn) (mem_map + ((pfn) - arch_pfn_offset))
#define __page_to_pfn(page) ((unsigned long)((page) - mem_map) + arch_pfn_offset)
如經典32為x86和arm為0xc0000000,即3gb處。對於64位來說,一般為0xffffffc000000000
比如說,如果phys_offset為1gb,ddr大小為2gb,那麼有效訪問ddr空間的位址必須是
0x40000000--0xc0000000之間。
在我們上面給出的system.map中的虛擬位址可以看到,
核心虛擬位址起始位址起始為0xffffffc000000000,這個由核心定義的page_offset給出。
而核心真正開始的使用的位址為0xffffffc000080000這裡有個偏移量,大小為128個頁(4kb)。總大小為512kb位元組。
在本實驗上測試,得到phys_offset為0x8800000,即136mb開始處。
可以看到,乙個核心中的虛擬位址,即0xffffffc000000000以上的位址,如果尋找其實體地址,使用__pa()巨集非常簡單,
比如上面的mem_map的虛擬位址為0xffffffc00191ab58,其減去起始虛擬位址0xffffffc000000000後為0x0191ab58,
= 0xa11ab58 可以看到,mem_map的實體地址為0xa11ab58。
那麼對於這個實體地址,對應的頁幀號為多少呢?即pfn為多少,這時需要使用上面的__phys_to_pfn().
可以看到,直接進行右移即可。例如對於上面的mem_map來說,其頁幀為0xa11a。
那麼對於乙個pfn,其對應的物理page描述符是多少呢?這時需要使用巨集__pfn_to_page(),注意這裡使用的
arch_pfn_offset,其就是偏移phys_offset對應的頁幀號,上面為0x8800000則對應頁幀為0x8800,則上面mem_map對應的頁幀號
為0xa11a - 0x8800 = 0x191a ,然後再根據mem_map陣列,即 mem_map[0x191a]為mem_map的頁描述符。
Linux 核心空間虛擬位址和實體地址相互轉換
個人學習筆記,可能會有錯誤之處,敬請諒解。一直以來感覺虛擬位址和實體地址之間的相互轉換非常麻煩,虛擬位址到實體地址的轉換由cpu硬體完成,但實體地址到虛擬位址怎麼轉換啊?況且有時候在軟體上也希望通過乙個虛擬位址得到實體地址,這時候自然不能依賴cpu的硬體了,該怎麼轉換呢?define va x vo...
linux實體地址和虛擬位址定義
線性位址 linear address 是邏輯位址到物理位址變換之間的中間層 如果啟用了分頁機制,那麼線性位址可以再經過變換以產生乙個實體地址 如果沒有啟用分頁機制,那麼線性位址直接就是實體地址 分頁管理 cpu的頁式記憶體管理單元,負責把乙個線性位址,最終翻譯為乙個實體地址 例如乙個32位的機器,...
虛擬位址與實體地址
乙個程式編譯連線後形成的位址空間是乙個虛擬位址空間,但是程式最終還是要執行在物理記憶體中。因此,應用程式所給出的任何虛位址最終必須被轉化為實體地址,所以,虛擬位址空間必須被對映到物理記憶體空間中,這個對映關係需要通過硬體體系結構所規定的資料結構來建立。這就是我們所說的段描述符表和頁表,linux主要...