ARM920T_內核MMU與cache應用分析

一、cache分類及應用場合

cache是內存和CPU之間的高速緩衝存儲器,其分爲icache(指令緩存)和dcache(數據緩存)。如果開啓了cache,當CPU運行時會將正在運行的指令地址附近的指令或者數據調入cache,這樣當運行下一條指令或用到下一條數據時直接從cache中查找,如果查找不到再訪問內存,以此加快CPU執行速度。icache可以直接開啓,而dcache需要開啓MMU之後才能開啓。

在啓動文件中開啓icache的代碼可以放在時鐘速度配置完成之後,代碼如下:

    bl enable_icache

enable_icache:
    mrc p15, 0, r0, c1, c0, 0
    orr r0, r0, #(1<<12)
    mcr p15, 0, r0, c1, c0, 0
    mov pc, lr

二、MMU的應用

當CPU執行小的應用程序時,只要代碼大小在芯片存儲容量範圍內,CPU每次都可以直接訪問內存執行指令,但是當代碼很大超出芯片存儲容量時,則不能運行。此時需要MMU(內存管理單元),MMU可以將物理地址重映射,開啓MMU之後CPU每次訪問的都是虛擬地址,而每一個虛擬地址或者多個虛擬地址對應一個物理地址。32位的CPU虛擬地址範圍爲4G,映射方式爲在物理存儲地址上建立映射表。每個表有多個條目,每個條目大小1M,所以表的大小爲:    條目數 = 4G/1M = 4096 ,一個條目32位佔4Byte, 表大小 = 4096 * 4Byte = 16KB。因而只要在nand上佔據16KB的空間即可重映射4G的訪問範圍。

CPU發出的VA(虛擬地址)經過CP13的C13轉換爲MVA(modified virtual address),MMU所看到的地址其實是MVA,通常外在來看不加以細分,權當VA處理。MMU常用section轉換方式進行虛擬地址到物理地址的轉換,其格式如下:

高12位爲PA(物理地址)的高12位,AP設置訪問權限(常設置爲11,特權模式/用戶模式下可讀可寫,所有模式下允許任何訪問),domain(域設置,arm9有16個域,此處設置0選擇域0),C(是否開啓cache),B(是否開啓Write buffer),其他位用默認值。

重映射代碼如下:

#define MMU_SECDESC_AP      (3<<10)
#define MMU_SECDESC_DOMAIN  (0<<5)
#define MMU_SECDESC_NCNB    (0<<2)
#define MMU_SECDESC_WB      (3<<2)
#define MMU_SECDESC_TYPE    ((1<<4) | (1<<1))

#define MMU_SECDESC_FOR_IO   (MMU_SECDESC_AP | MMU_SECDESC_DOMAIN | MMU_SECDESC_NCNB | MMU_SECDESC_TYPE)
#define MMU_SECDESC_FOR_MEM   (MMU_SECDESC_AP | MMU_SECDESC_DOMAIN | MMU_SECDESC_WB | MMU_SECDESC_TYPE)


#define IO  1
#define MEM 0

void create_secdesc(unsigned int *ttb, unsigned int va, unsigned int pa, int io)
{
	int index;

	index = va / 0x100000;

	if (io)
		ttb[index] = (pa & 0xfff00000) | MMU_SECDESC_FOR_IO;
	else
		ttb[index] = (pa & 0xfff00000) | MMU_SECDESC_FOR_MEM;
}

/* 
 *    VA           PA           CB
 *    0            0            00
 *    0x40000000   0x40000000   11
 *
 *    64M sdram:
 *    0x30000000   0x30000000   11
 *    ......
 *    0x33f00000   0x33f00000   11
 *    
 *    register: 0x48000000~0x5B00001C
 *    0x48000000   0x48000000   00
 *    .......
 *    0x5B000000   0x5B000000   00
 *
 *    Framebuffer : 0x33c00000
 *    0x33c00000   0x33c00000   00
 *
 *    link address:
 *    0xB0000000   0x30000000   11
 */
void create_page_table(void)
{
	/* ttb: translation table base */
	unsigned int *ttb = (unsigned int *)0x32000000;

	unsigned int va, pa;
	int index;

	/* 2.1 for sram/nor flash */
	create_secdesc(ttb, 0, 0, IO);

	/* 2.2 for sram when nor boot */
	create_secdesc(ttb, 0x40000000, 0x40000000, MEM);

	/* 2.3 for 64M sdram */
	va = 0x30000000;
	pa = 0x30000000;
	for (; va < 0x34000000;)
	{
		create_secdesc(ttb, va, pa, MEM);
		va += 0x100000;
		pa += 0x100000;
	}

	/* 2.4 for register: 0x48000000~0x5B00001C */
	va = 0x48000000;
	pa = 0x48000000;
	for (; va <= 0x5B000000;)
	{
		create_secdesc(ttb, va, pa, IO);
		va += 0x100000;
		pa += 0x100000;
	}

	/* 2.5 for Framebuffer : 0x33c00000 */
	create_secdesc(ttb, 0x33c00000, 0x33c00000, IO);

	/* 2.6 for link address */
	create_secdesc(ttb, 0xB0000000, 0x30000000, MEM);
}

啓動文件中代碼如下:

	/* 創建頁表 */
	bl create_page_table

	/* 啓動MMU */
	bl mmu_enable


mmu_enable: 
	/* 把頁表基址告訴cp15 */
	ldr r0, =0x32000000
	mcr p15, 0, r0, c2, c0, 0

	/* 設置域爲0xffffffff, 不進行權限檢查 */
	ldr r0, =0xffffffff
	mcr p15, 0, r0, c3, c0, 0

	/* 使能icache,dcache,mmu */
	mrc p15, 0, r0, c1, c0, 0
	orr r0, r0, #(1<<12)  /* enable icache */
	orr r0, r0, #(1<<2)  /* enable dcache */
	orr r0, r0, #(1<<0)  /* enable mmu */
	mcr p15, 0, r0, c1, c0, 0	

	mov pc, lr

有幾個需要注意的關鍵點:

1. 由於代碼重定位腳本中將nand中的代碼重定位至0xB0000000,所以應該在重定位之前MMU進行地址的重映射,將0XB0000000映射到0X30000000,也就是nnad啓動時SDRAM的起始地址,有關重定位參考此鏈接S3C2440代碼重定位分析

2.在makefile時注意將mmu.c放至靠前的位置,必須在nand的前4K範圍完成地址重映射,代碼重定位,否則芯片將直接無法啓動。

3.當使用NOR啓動時,0地址映射時不能開啓cache和write buffer。

代碼重定位腳本:

SECTIONS{
	. = 0xB0000000;
	
	__code_start = .;
	
	. = ALIGN(4);	
	.text  	:	{*(.text)}
	
	. = ALIGN(4);
	.rodata		:	{*(.rodata)}
	
	. = ALIGN(4);
	.data  	: 	{*(.data)}
	
	. = ALIGN(4);
	__bss_start = .;
	.bss : { *(.bss) *(.COMMON) }
	_end = .;
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章