【補充】 關於*(mmu_tlb_base + (virtuladdr >> 20))的理解

這裏寫圖片描述 
來看代碼:

unsigned long virtuladdr, physicaladdr;
unsigned long *mmu_tlb_base = (unsigned long *)0x30000000;//對應上圖TTB
virtuladdr = 0xA0000000;//對應上圖MVA
physicaladdr = 0x56000000;//對應上圖PA
*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
                                            MMU_SECDESC;
                                            //*(mmu_tlb_base + (virtuladdr >> 20)) = 
                                            //*(TTB[31-14]+MVA[31-20]+00) = *(描述符地址) 
//這裏作用就是將描述符的值給定(bit[31-20]爲PA的[31-20],bit[19-0]自己給定一些段描述符的操作),CPU系統自動根據此發生操作,獲得實際PA地址。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我們根據上面可以得到:段描述符的地址=Translation base(高18位)-TTB bit[31-14]+Table index(低12位)-MVA bit[31-20]+00(低兩位)不少人會以爲*(mmu_tlb_base | virtuladdr>>18)纔是正確的。

解釋:

首先mmu_tlb_base是一個unsigned long *型,而virtuladdr是unsigned long型,位或操作會出錯!

這裏寫圖片描述

查閱資料可知,一級頁表的地址TTB必須16KB對齊,且位[14:0]必爲0!

所以我們用+|是一樣的。而我們的mmu_tlb_base是unsigned long*型的,

在32位中,mmu_tlb_base + 1 = mmu_tlb_base + 1*sizeof(unsigned long*)=mmu_tlb_base + 4

所以我們mmu_tlb_base + (virtuladdr >> 20) = mmu_tlb_base +( (virtuladdr >> 20))* 4 = mmu_tlb_base +( (virtuladdr >> 20))<<2 = mmu_tlb_base + (virtuladdr >>18

實驗驗證:

#include <stdio.h>

int main(int argc,char ** argv)
{
    unsigned long *a = (unsigned long *)0x30000000;
    unsigned long b = 0xA0000000;
    printf("a+(b>>20) = %#x.\n\n",a+(b>>20));
    printf("a | ((b>>20)<<2) = %#x",0x30000000 | ((b>>20)<<2));
    return 0;
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

結果:

這裏寫圖片描述

發佈了20 篇原創文章 · 獲贊 35 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章