/*Nand 启动sdram的起始地址*/
#define SRAM_START_ADDR 0x00000000
/*内存空间地址*/
#define VMRAM_ADDR_START 0xa0000000
#define SDRAM_ADDR_START 0x30000000
#define SDRAM_ADDR_END 0x34000000
/*IO空间地址*/
#define VMIO_ADDR_START 0xb0000000
#define PHIO_ADDR_START 0x56000000
#define PHIO_ADDR_END 0x56010000
/*用SDRAM起始地址开始的16KB,存放页表*/
#define PAGE_TABLE_BASE 0x30000000
/*MASK*/
#define PAGE_TABLE_BASE_MASK 0xffffc000
#define VIRADDR_MASK 0xfff00000
#define PHYADDR_MASK 0xfff00000
/*页表项内容*/
#define PAGE_TABLE_SECTION_AP (0x01 << 10)
#define APGE_TABLE_SECTION_DOMAIN (0x0 << 5)
#define PAGE_TABLE_SECTION_CACHE_WB (0x0 << 2)
#define PAGE_TABLE_SECTION_4BIT (1 << 4)
#define PAGE_TABLE_SECTION_TYPE (0x2)
/*段大小*/
#define SECTION_SIZE 0x100000
//根据虚拟地址和页表基地址确定页表项所在的物理地址
unsigned int get_pgtindex_addr(unsigned int viraddr,unsigned int pgtaddr)
{
unsigned int addr;
/*[31:14]页表基地地址
*[13: 2]虚拟地址>>20位得到的page index
*[1 : 0]总是为0,因为每一项占用4byte
*/
addr = (pgtaddr & PAGE_TABLE_BASE_MASK) | (((viraddr & VIRADDR_MASK) >> 20) << 2);
return addr;
}
//获取页表项
unsigned int get_page_entry(unsigned int phyaddr)
{
unsigned int entry_value;
/*[31:20]section base address
*[19:12]
*[11:10]AP
*[9]
*[8:5]Domain
*[4]:1
*[3]:C
*[2]:B
*[1:0]:Type
*/
entry_value = (phyaddr & PHYADDR_MASK) | PAGE_TABLE_SECTION_AP |\
PAGE_TABLE_SECTION_CACHE_WB | PAGE_TABLE_SECTION_4BIT|\
PAGE_TABLE_SECTION_TYPE;
return entry_value;
}
/*创建一级页表:段描述符*/
void create_page_table()
{
int i;
unsigned int pgt_index_addr;
unsigned int viraddr,phyaddr,pgtaddr;
/*我们代码的起始运行地址0x00000000
*在这里需要注意的是:当我们开启MMU后,
*cpu发出的地址都会被MMU拦截,要想程序
*正常运行,pc所用的的地址必须是虚拟地址。
*然而此时cpu执行下一条指令实际运行的地址是
*物理地址,但是MMU会将此物理地址当作虚拟虚拟地址
*处理。晕,乱套了。为了解决这个问题,我们通常的做法
*是,让开启MMU的附近地址指令的虚拟地址和物理地址空间
*做一个等价的映射。在这里我们将0x00000000开始的1M物理空间
*映射到0x00000000开始的虚拟地址空间。
*/
phyaddr = SRAM_START_ADDR;
viraddr = phyaddr;
pgtaddr = PAGE_TABLE_BASE;
pgt_index_addr = get_pgtindex_addr(viraddr,pgtaddr);
*(volatile unsigned int *)pgt_index_addr = get_page_entry(phyaddr);
#if 1
/*映射64MSDRAM*/
for(phyaddr = SDRAM_ADDR_START,viraddr = VMRAM_ADDR_START;\
phyaddr < SDRAM_ADDR_END;phyaddr += SECTION_SIZE,\
viraddr += SECTION_SIZE)
{
pgtaddr = PAGE_TABLE_BASE;
pgt_index_addr = get_pgtindex_addr(viraddr,pgtaddr);
*(volatile unsigned int *)pgt_index_addr = get_page_entry(phyaddr);
}
#endif
/*映射IO地址空间*/
phyaddr = PHIO_ADDR_START;
viraddr = VMIO_ADDR_START;
pgtaddr = PAGE_TABLE_BASE;
pgt_index_addr = get_pgtindex_addr(viraddr,pgtaddr);
*(volatile unsigned int *)pgt_index_addr = get_page_entry(phyaddr);
return;
}
/*
Care must be taken if the translated address differs from the
untranslated address as several instructions following the
enabling of the MMU may have been prefetched with the MMU off
(using physical = virtual address - flat translation) and enabling
the MMU may be considered as a branch with delayed execution. A similar
situation occurs when the MMU is disabled. Consider the following code
sequence:
MRC p15, 0, R1, c1, C0, 0: Read control rejectio
ORR R1, #0x1
MCR p15,0,R1,C1, C0,0 ; Enable MMUS
Fetch Flat
Fetch Flat
Fetch Translated
*/
void init_mmu()
{
unsigned long mmu_table_base = PAGE_TABLE_BASE;
asm(
/*set Translation Table Base(TTB) register*/
"mrc p15,0,r0,c2,c0,0\n"
"mov r0,%0\n"
"mcr p15,0,r0,c2,c0,0\n"
/*set Domain Access Control register*/
"mrc p15,0,r0,c3,c0,0\n"
"mvn r0,#0\n"
"mcr p15,0,r0,c3,c0,0\n"
/*Enable MMU*/
"mrc p15,0,r0,c1,c0,0\n"
"orr r0, #0x1\n"
"mcr p15,0,r0,c1,c0,0\n"
"mov r0,r0\n"
"mov r0,r0\n"
"mov r0,r0\n"
:
:"r"(mmu_table_base)
:"r0"
);
return;
}