S3C2440之MMU操作(MDK4.22)
1.ARM CPU上的地址轉(zhuǎn)換過程涉及到了3個概念,虛擬地址VA,變換地址MVA,物理地址PA。當沒有啟動MMU的時候,CPU核,CACHE,MMU見到的都是PA。
本文引用地址:http://2s4d.com/article/201611/318144.htm啟動MMU之后,CPU核對外發(fā)出VA,VA被轉(zhuǎn)換為MVA,供給CACHE和MMU使用,MMU再將MVA轉(zhuǎn)換為PA,最終找到真實的地址。
CPU看見的VA,CACHE和MMU看不見VA,看見的是MVA;設(shè)備只看到VA。
轉(zhuǎn)換算法:如果VA<32M,那么使用進程PID來轉(zhuǎn)換,PID通過CP15的C13讀取。
if(VA<32M) then
MVA = VA | (PID << 25);
else
MVA = VA; //VA >= 32M
2.協(xié)處理器的cp15寄存器c2的31-14位存放一級頁表的地址,一級頁表有4096項,每項4字節(jié),共16k,所以c2的0到13位不使用
若為段映射,只需要一級頁表,每段1M,4096*1M=4G空間;若為頁映射就需要二級頁表,目標的物理頁有大頁,小頁,極小頁。
3.一級頁表的描述符和二級頁表描述符
注意到一級描述符是用來指引二級描述符的,除了段的直接指引到物理內(nèi)存,若使用二級頁表的話,那么二級頁表類型有粗頁表,細頁表兩種。
粗頁表256項,每項指引真是內(nèi)存為4K大小,本身占256*4=1k字節(jié);細頁表1024項,每項指引1k大小,本身二級頁表占1024*4=4k字節(jié)。
所以注意到,若要對應(yīng)真實物理頁的大頁的話,怎么辦呢?利用粗頁的話,需要16個粗頁二級描述符;利用細頁的話,需要64個二級描述符。
4段的轉(zhuǎn)換舉例
5內(nèi)存訪問權(quán)限問題
注意到一級頁表中的描述符中有domain字段,4位,共16種情況
對應(yīng)的為cp15中的c3寄存器設(shè)置。
00無訪問權(quán)限,任何訪問都會導(dǎo)致domain fault異常
01客戶模式,使用段描述符,頁描述符進行權(quán)限檢查
10保留
11管理模式,不進行權(quán)限檢查,運行任何訪問
cp15中的c3 + domain + cp15寄存器c1中的R/S/A位 + 描述符AP共同決定訪問權(quán)限
6TIB和Cache的作用
TLB是為了減輕頁表訪問所帶來的訪問內(nèi)存負擔(dān),利用程序訪問的局部性原理,選擇高速且容量較小的存儲器存儲近期使用的頁表條目。
一般做法:在啟動MMU之前使無效整個TLB;更改頁表表項的時候,使無效所涉及到的虛擬地址所對應(yīng)到的TLB條目。
Cache的作用,在主存和CPU通用寄存器之間設(shè)置一個高速,容量相對較小的存儲器。把正在執(zhí)行的指令的附近一部分數(shù)據(jù)或者指令從主存調(diào)入這個
存儲器,供CPU在一段時間內(nèi)使用。Cache的(1)clean操作是將cache或writerbuffer已經(jīng)臟的數(shù)據(jù)寫入主存(2)invalidate不將數(shù)據(jù)寫入主存,使之不能
再使用而已。
cp15的寄存器1的12位Icr位開啟Icaches;第2位寫1開啟Dcaches;Writterbuffer和Dcache緊密結(jié)合,沒有專門的控制為開啟,停止它。
程序部分:
本程序?qū)?-1M映射為本身,將0xa0000000~0xa000fffff映射為0x56000000~0x560ffffff,將0xb0000000~0xb3ffffff映射為0x30000000~0x3fffffff
涉及到代碼文件有s3c2440.s文件,init.c文件,led.c文件,led.sct文件
s3c2440.s主要是調(diào)用一些初始化程序,init.c是初始化代碼,led.c只是利用新的虛擬地址尋找gpio,點亮led。
編譯器MDK4.22a
led.sct文件如下所示:
LR_ROM1 0x00000000 0x00200000 { ; load region size_region
NANDFLASH 0x00000000 0x00200000 { ; load address = execution address
*.o (initcode, +First)
.ANY (+RO)
}
}
LR_ROM2 2048 2048 {
SDRAM 0xb0004000 {
led.o (*)
}
}
存在多個加載域,會產(chǎn)生多個bin,可以參見的另一篇文章講到如何連接多個bin文件S3C2440開發(fā)工具realview MDK4.22使用入門
init.c文件:
//creat page table
void create_page_table(void)
{
#define MMU_FULL_ACCESS(3<<10)
#define MMU_DOMAIN(0<<5)
#define MMU_SPECIAL(1<<4)
#define MMU_CACHEABLE(1<<3)
#define MMU_BUFFERABLE(1<<2)
#define MMU_SECTION(2<<0)
#define MMU_SECDESC(MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL |
MMU_SECTION)
#define MMU_SECDESC_WB(MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL |
MMU_SECTION | MMU_CACHEABLE | MMU_BUFFERABLE)
#define MMU_SECTION_SIZE0x00100000
ulong virtualaddr, physicaladdr;
ulong *mmu_tlb_base = (ulong*)0x30000000;
/*<1>0~1M map to 0~1M virtualaddr == physicaladdr*/
virtualaddr = 0;
physicaladdr = 0;
//mmu page table store at 0x30000000
//vritualaddr>>20 is index of mmu page table
*(mmu_tlb_base + (virtualaddr>>20)) = (physicaladdr&0xfff00000) | MMU_SECDESC_WB;
/*<2>0xa0000000~0xa000fffff map to 0x56000000~0x560fffff*/
virtualaddr = 0xa0000000;
physicaladdr = 0x56000000;
*(mmu_tlb_base + (virtualaddr>>20)) = (physicaladdr&0xfff00000) | MMU_SECDESC;
/*<3>0xb0000000~0xb3ffffff map to 0x30000000~0x33fffffff total=64m totaldescs=64*/
virtualaddr = 0xb0000000;
physicaladdr = 0x30000000;
while(virtualaddr < (ulong)0xb4000000)
{
*(mmu_tlb_base + (virtualaddr>>20)) = (physicaladdr&0xfff00000) | MMU_SECDESC_WB;
virtualaddr += MMU_SECTION_SIZE;
physicaladdr += MMU_SECTION_SIZE;
}
}
//init MMU
void mmu_init(void)
{
ulong ttb = 0x30000000;
__asm{
mov r0,#0
mcr p15,0,r0,c7,c7,0 //invalidate Icache Dcache
mcrp15,0,r0,c7,c10,4//drain writer buffer
mcr p15,0,r0,c8,c7,0 //invalidate TLB
mov r4,ttb
mcr p15,0,r4,c2,c0,0 //set page table base-addr
mvn r0,#0 //invert all bits:0x0000000->0xffffffff
mcr p15,0,r0,c3,c0,0 //set domain(all is 0b11)
mrc p15,0,r0,c1,c0,0 //read control register
bic r0,r0,#0x3000
bic r0,r0,#0x0300
bic r0,r0,#0x0087
orr r0,r0,#0x0002
orr r0,r0,#0x0004
orr r0,r0,#0x1000
orr r0,r0,#0x0001
mcr p15,0,r0,c1,c0,0
};
}
評論