一、MMU學習
MMU其實就是一個頁表。將虛擬地址通過查表的方式,對應到物理地址去他由一個或一組芯片組成,一般存在與協處理器中。
1.將虛擬地址轉化為物理地址
2.訪問權限管理
1.1得出mmu功能
這個圖就說明了MMU的作用:
有三個任務在運行,運行的地址都是0x400000,如果不進行處理,肯定是不行的。所以加入了MMU,MMU其實就是一個頁表。將虛擬地址通過查表的方式,對應到物理地址去。雖然三個任務的運行地址都是0x400000,但是這個地址是虛擬地址,在頁表中,將每個任務的虛擬地址對應到不同的物理地址,這樣,就實現了各個任務雖然是同一個虛擬地址,但是在不同的物理地址中運行。
1.2映射方式(ARM920T_TRM1_S 57頁)
映射方式:映射方式有兩種,段映射和頁映射。段映射只用到一級頁表,頁映射用到一級頁表和二級頁表。
映射粒度:段映射的映射粒度有兩種,1M section和16M supersection;頁映射的映射粒度也有兩種,4K small page和64K large page。
1.3頁表
MMU要自動進行虛擬地址到物理地址的轉化,首先要找到一級頁表,而一級頁表的基地址(TTB:translation table base)則是保存在CP15的C2寄存器中。因此,當程序員創建好相應的頁表後,需要將頁表基地址寫入該寄存器。
MMU有一級轉換和二級轉換,其實就是查幾次表。對於一級轉換,就是只查一次頁表,就確定了物理地址。這個在S3C6410中,方式是段映射。對於二級轉換,就要查兩次頁表或者三次,才能確定物理地址,這個在S3C6410中。有兩種方式,一種細頁方式,一種粗頁方式。這兩種的區別就是每一頁對應的大小不一樣而已。
通過虛擬地址的[31:20],找到對應的轉換描述符,這個轉換描述符其實就是一個存在ram中的32位的一個數據。通過判斷這個描述符的最後兩位,判斷是什麼轉換。
1.3.1一級頁表描述符
一級頁表描述符後兩位如果是10則表示為段轉換。
如果是段轉換,就按照段轉換的格式去轉化物理地址
如果是頁轉換,就在去找第二級的頁表,然後再按照二級頁表的格式去轉化物理地址。
B:表示是否使能write buffer(使用buffer可以提高cpu運行效率-à當CPU訪問內存數據時但是內存沒准備此時cpu可以將數據暫時存放於buffer)
C: 表示是否開啟cache(cahce用來保存cpu可能要經常訪問內存區域的數據,以便於快速訪問)
XN:
Domain:用來說明該段屬於哪一個域,ARM11共有16個域(由CP15的C3來設置),每個域可以設定不同的權限。將段分配到某個域,就使這段的權限和設定的域權限一樣。 (手冊arm11 P195)
P:表示段區間有ECC,ARM11不支持,所以這一位為0.
AP:訪問權限,這個配合域,說明該段地址的訪問權限。(手冊arm11 P329)
APX: 提供額外的訪問權限。
S:表示區域是否共享。0不共享,1共享。這個手冊上說,是為了多核使用的。目前用不到,設置為0.
nG:
Section base address:這個就是段的物理地址的高12位。
1.4段轉換
ARM11是32位的,對於段轉換,每一個段代表物理的1MB地址,一級頁表總共有4096個轉換符,所以夠表示的空間是4G。頁表的首地址就是TTB,這個地址是很重要的,因為有了這個地址才能知道頁表是存在什麼地方的,才能通過偏移找到對應的描述符。所以,是有一個寄存器來保存這個地址的,這個寄存器就在CP15的c2寄存器。
通過虛擬地址的高12位偏移,找到頁表中的對應描述符,判斷描述符的最後兩位,確定是什麼轉換。10的話就表示是段轉換。
判斷是段轉換後,將描述符的高12位取出,這個就是物理的基地址,在和虛擬地址的後20位拼接,就得到對應的物理地址。
對於段轉換,每一個段代表物理的1MB地址。為什麼是1MB了。因為總共是有4096個描述符,而ARM11是32位的,所以能夠表示的空間是4G。
以段的方式進行映射時,虛擬地址MVA到物理地址PA的轉換過程如下:
①頁表基址寄存器位[31:14]和MVA[31:20]組成一個低兩位為0的32位地址,MMU利用這個地址找到描述符
②取出段描述符的位[31:20](段基址),它和MVA[19:0]組成一個32位的物理地址(這就是MVA對應的PA)
1.5頁轉換(ARM11 360頁)
二級轉換
1.6程序設計
1.6.1建立頁表
使用段映射的方式,那麼就要將段映射的描述符寫入到相應的內存中去。
首先將頁表放在ddr的第一個位置,也就是0x50000000。所以需要將這個地址寫入到TTB中。
其次,開啟MMU後,使用的就是虛擬地址了,所以還要建立程序段的頁表,不然一旦開啟MMU,CPU去取指令,這個時候發出的就是虛擬地址,但是又沒有建立虛擬地址到物理地址的映射表。這樣的話,就取不到指令了,程序就崩潰了。所以還需要對代碼區建立映射頁表。代碼區的映射就是將虛擬地址直接轉換為物理地址使用。
將這個地址給映射到0x7F000000區域去。
unsigned long *ttb = (unsigned long *)0x50000000;//獲取基地址
unsigned long vaddr, paddr;
vaddr = 0xA0000000;
paddr = 0x7f000000;
*(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC;
//獲得一級描述符的地址 並且賦值
首先申明一個ttb指針,這個指針就指向一級表的基地址,也就是ddr的首地址,0x50000000。然後再申明兩個變量,一個表示虛擬地址,一個表示物理地址。
根據前面的一級段描述符格式,往對應的內存單元寫入數據即可。段描述符的高12位是物理地址的高12位,所以首先有一個物理地址和0xFFF00000與的操作,將物理地址的高12位寫入到段描述符。
這裡使用*(ttb + (vaddr >> 20))來對對應的頁描述符進行賦值。在一級頁表中,是通過虛擬地址的高12位來決定偏移是多少。高12位也就是位移20位,所以這裡就是加上虛擬地址右移20位的值,也就是取出高12位的值。注意,這裡是指針操作,假設這個時候虛擬地址的高12位值是5,那麼寫的地址不是0x50000005,而是0x50000014。因為指針的數據類型是long型,4個字節,所以加1,地址就會加4,加5,地址就會加5*4=20。
後面位的配置:
設置為訪問權限是11,也就是不進行訪問權限的檢查。將域設置為0。CACHE和write BUFFER都給關掉。因為這只是對一個寄存器的操作,沒有必要使用CACHE和write BUFFER。
這樣,就建立好了GPIO的頁表。訪問虛擬地址0xc7000000,也就是訪問物理地址0x7f000000。整個段空間是1Mb。
1.6.2建立代碼區的頁表
這個時候,代碼已經是在內存中運行的了。所以,直接將內存的所有地址空間進行映射,空間是64MB大小。
使用的宏
其實就是多一個開啟CACHE和WRITE BUFFER。
內存映射是映射一片區域,從0x50000000地址開始到0x54000000這64M的虛擬地址給映射到0x50000000地址開始到0x54000000這64M物理地址上去。這樣,即使使用虛擬地址去取ddr中數據,也是能夠取到的。
因為一個段是映射的1MB空間,所以總共需要64個段,十六進制也就是0x40。所以在while裡面判斷是虛擬地址要小於0x54000000。再者,每一個段表示1MB空間,所以虛擬地址和物理地��都要加1MB。也就是0x100000。
這樣,就將頁表給建立好了。如果還需要使用其他地址區域,就都得為這些區域建立映射表。
1.6.3開啟mmu
TTB是很重要的,保存的是一級頁表的首地址。首先就應該先要設置這個TTB。往CP15的C2寄存器裡面寫入這個值就好了,因為這個寄存器就是保存的TTB。
然後是設置域的權限,將域的權限設置為11,不進行訪問權限檢查。設置CP15的c3寄存器。
最後打開MMU。設置CP15的c1寄存器組的c0。是對CP15進行操作,用C語言是實現不了的,使用嵌入匯編。
就設置好了MMU,並打開了MMU。之後使用的地址都是虛擬地址了。而且該虛擬地址必須是要在頁表中建立的,不然的話,就會產生異常。