引言
爲什麼linux會發展成這個樣子,這當然是程序員對程序的要求決定的,
爲了滿足這些要求,提出了 進程地址空間抽象(1) , 其中 硬件上增加了新的模塊MMU(2), 軟件上根據MMU的使用手冊(3)更新了系統
另外在 進程地址空間抽象 的基礎上, 軟件上更新了很多新的內存特性(4).
這裏主要講 新的模塊MMU(2),且我們這裏只看arm的mmu
ARM-MMU文檔
科普文檔
- MMU 是 soc 芯片裏面的一個硬件單元
- 去arm官網去搜mmu,得到結果
- 其中有一個 介紹性文檔 : LearnTheArchitecture-MemoryManagement-101811_0100_00_en.pdf
專業文檔
- 去http://infocenter.arm.com搜mmu,得到一個 RF 和 很多TRM(MMU-40x,MMU-500,MMU600,MMU-600AE)
- arm-mmu 的 RF : IHI0062D_c_system_mmu_architecture_specification.pdf
- arm-mmu 的TRM : corelink_mmu500_memory_management_unit_r2p4_technical_reference_manual_DDI0517F_en.pdf
MMU 與 內存管理的關係
爲了 實現 進程地址空間抽象 , 在 硬件內存管理這方面由MMU負責
硬件內存管理幹了什麼
硬件內存管理(MMU)描述瞭如何控制對 系統內存 的訪問。
每當操作系統或應用程序訪問內存時,硬件都會執行內存管理。
硬件內存管理是一種將內存區域動態分配給應用程序的方法。 // 這個動態分配是什麼意思
硬件內存管理的行爲導致的效果
支持虛擬內存系統
軟件只能看到虛擬地址,處理器會將其轉換爲物理地址。
這些物理地址被提供給內存系統,並指向內存中的實際物理位置。
// 動態分配???
It is optional which write allocation policies an implementation supports.
The allocate on write and no allocate on write cache policies indicate which allocation policy is preferred for a memory region, but it should not be relied on that the memory system implements that policy.
實現支持哪些寫分配策略是可選的。
寫時分配和不寫時分配緩存策略指示內存區域首選哪個分配策略,但不應依賴於內存系統實現該策略。
MMU工作流程(三種描述方式)
- MMU工作流程文字描述
虛擬地址和物理地址的轉換 總覽
映射轉換(翻譯) 的過程
所需成員:
cpu mmu mmu中的TLBs mmu中的TableWalkUnit cache 主存中的轉換表(頁表) 主存中其他部分
1.取指令,譯碼
2.執行load指令(讀一個內存地址中的值(value)到r0,內存地址爲虛擬地址 va)
2.1 獲取 物理地址 pa
2.1.1 從 TLBs 中 獲取 pa ,如果獲取不到則執行2.1.2
2.1.2 mmu中的TableWalkUnit 從 主存中的轉換表(頁表) 中獲取 pa
2.2 根據物理地址 pa 獲取 value
2.2.1 從 cache 中獲取 value,如果獲取不到則執行2.2.2
2.2.2 從 主存中其他部分 中獲取 value.
主內存 中的 轉換表 填充了 映射轉換
映射轉換
虛擬地址通過映射轉換爲物理地址。
虛擬地址和物理地址之間的映射存儲在轉換表(有時稱爲頁表)
轉換表:
轉換表位於內存中,並由軟件(通常是OS或管理程序)進行管理。
轉換表不是靜態的,並且可以根據軟件需求的變化來更新這些表。
這將更改虛擬地址和物理地址之間的映射。
-
MMU工作流程圖解
-
MMU工作流程僞代碼描述
/*
level-fetch:
zhanweifu
first-level-fetch // 獲取第1級頁表項的函數
second-level-fetch // 獲取第2級頁表項的函數
third-level-fetch // 獲取第3級頁表項的函數
fourth-level-fetch // 獲取第4級頁表項的函數
zhanweifu2
*/
void walktable(int vma,int *pa){
level-fetch = zhanweifu;
do{
level-fetch = next-level-fetch(level-fetch);
if (level-fetch == zhanweifu2){
throw execption;
return;
}
table-item=level-fetch(vma);
is-permission=do-permission-check(current-state,Attributes-of-table-item(table-item));
if(!is-permission){
throw execption;
return;
}
is-data-block-index = do-data-block-index-check(Attributes-of-table-item(table-item));
}while(!is-data-block-index);
pa = calc-pa(addr-base-of-table-item(table-item),vma);
return ;
}
int get_value(int pa){
is_cache_miss = get_value_from_cache(pa,&value);
if (is_cache_miss){
get_value_from_ddr(pa,&value);
}
return value;
}
int get_pa(int vma){
is_tlb_miss = tlb(vma,&pa)
if (is_tlb_miss){
try {
walktable(vma,&pa);
}catch (Exception XXX){
//TODO
}
}
return pa;
}
int mmu(int vma){
pa = get_pa(vma);
value = get_value(pa);
return value;
}
void cpu(void){ // main
try {
value = mmu(vma);
}catch (Exception alignment fault){
//TODO
}catch (Exception translation fault){
//TODO
}catch (Exception domain fault){
//TODO
}catch (Exception permission fault){
//TODO
}
}