上一张里忘说的一个理论,TLB,快表
TLB (Translation Lookaside Buffers)即转换快表,又简称快表,可以理解为MMU内部专用的存放页表的cache,保存着最近使用的PTE乃至全部页表。MMU接收到虚拟地址后,首先在TLB中查找,如果找到该VA对应的PTE就直接转换,找不到再去外存页表查找,并置换进TLB。TLB属于片上SRAM,访问速度快,通过TLB缓存PTE可以节省MMU访问外存页表的时间,从而加速虚实地址转换。TLB和CPU cache的工作原理一样,只是TLB专用于为MMU缓存页表。
在系统上电,初始化MMU时,TLB是需要清空的,ARM920T需要配置CP15协处理器的 C10寄存器
先来回顾 如何通过程序给出的一个虚拟地址找到对应的物理地址的:
初始化MMU其实就是在为这个过程做填充准备
1 生成PTE 也就是页表项
对物理地址的后20位清零
设定段页大小为1M
2 将生成的PTE放到指定物理地址上
地址页表基地址baddr
保证页表基地址mask到该地址所在的段地址上 baddr&0xffffc000
页表项PTE的偏移是虚拟地址的前12位再<<2 也就是占用14位
所以第二步要与上0xffffc000 清零后14位
初始化MMU的步骤:
- find a available memory zone to store TTB
(ARM920T mmu requires the page table stored 16KB aligned) - fill map relation in the page table
- write base address of the page table to cp15-c2 register
- disable tlb and cache
- enable mmu(mmu ctrl register is cp15-c1)
#include "../include/hylicos_types.h"
#include "../include/hylicos_headctrl.h"
void init_platform()
{
s3c2440mmu_init(); //init s3c2440 mmu
s3c2440vector_init(); //init s3c2440 interrupt vectors
return;
}
#ifdef CFG_S3C2440A_PLATFORM
LKHEAD_T void s3c2440mmu_init()
{
/*
* 1. find a available memory zone to store TTB
* (ARM920T mmu requires the page table stored 16KB aligned)
* 2. fill map relation in the page table
* 3. write base address of the page table to cp15-c2 register
* 4. enable mmu(mmu ctrl register is cp15-c1)
*/
uint_t paddr = 0;
u32_t pte_desc= 0;
/* 1. 0x3000_4000 cause physical address from 0x3000_0000 to 0x33ff_ffff */
u32_t* pgd_baseaddr= (u32_t* )PAGE_TLB_DIR;
/* 2. simply use biggest page-->1MB since page table has 4096 PTE*/
for(uint_t i=0; i<PAGE_TLB_SIZE; i++)
{
pte_desc = paddr | PTE_SECT_AP | PTE_SECT_NOCW | PTE_SECT_BIT | PTE_SECT_DOMAIN; //made a pte descriptor
pgd_baseaddr[i] = pte_desc; //index i
paddr += 0x100000; // 1MB
}
pgd_baseaddr[0] = SDRAM_MAPVECTPHY_ADDR | PTE_SECT_AP | PTE_SECT_DOMAIN | PTE_SECT_NOCW | PTE_SECT_BIT;
/* pdg has been built. let's do step 3 */
s3c2440mmu_save_pgd(pgd_baseaddr);
/* mask cache and tlb before enable mmu */
s3c2440mmu_mask_cache();
/* set domain to control visit privilege */
s3c2440mmu_set_domain(~0);
/* step 4: enable mmu */
s3c2440mmu_enable();
return ;
}
LKHEAD_T void s3c2440mmu_save_pgd(u32_t pgd_baseaddr)
{
__asm__ __volatile__(
/* write pgd to cp15 c2 reg */
"mcr p15,0,%[pgdreg],c2,c0,\n\t"
:
/* attribute a general register to store pdg_baseaddr value */
: [pgdreg] "r" (pgd_baseaddr)
: "cc", "memory"
);
return;
}
LKHEAD_T void s3c2440mmu_set_domain(u32_t domain)
{
__asm__ __volatile__(
/* config cp15 c3reg to set domain with 0xffff */
"mcr p15,0,%[domainval],c3,c0,0 \n\t"
:
: [domainval] "r" (domain)
: "cc", "memory"
);
return;
}
LKHEAD_T void s3c2440mmu_mask_cache()
{
__asm__ __volatile__(
"mov r0,#0 \r\t"
"mcr p15, 0, r0, c7, c7, 0 \n\t" //disable data cache and cmd cache
"mcr p15, 0, r0, c7, c10, 4 \n\t" //clear write cache
"mcr p15, 0, r0, c8, c7, 0 \n\t" //disable data tlb and cmd tlb
:
:
: "cc", "memory", "r0"
);
return;
}
LKHEAD_T void s3c2440mmu_enable()
{
__asm__ __volatile__(
"mrc p15,0,r0,c1,c0,0 \n\t"
"orr r0 ,#1 \n\t"
"mcr p15,0,r0,c1,c0,0 \n\t"
"nop \n\t"
"nop \n\t"
"nop \n\t"
"nop \n\t"
"nop \n\t"
"nop \n\t"
"nop \n\t"
:
:
: "r0","cc","memory"
);
return;
}
LKHEAD_T void s3c2440vector_init()
{
s3c2440vector_copy();
return;
}
LKHEAD_T void s3c2440vector_copy()
{
u32_t* src_end = (u32_t* )(&__end_hylic_hal_vector);//linker define and will be substitud with a virtual address
u32_t* src_pos = (u32_t* )(&vector); //vector(virtual) src <--> unkown(physical)
u32_t* dst = (u32_t* )(CPU_VECTOR_VIRADR); //CPU_VECTOR_VIRADR(virtual 0) target <--> 0x3000_0000
for(uint_t i=0; i<4096; i++) //clear 0 from 0(virtual) / 0x3000_0000(physical) to x+4096
{
dst[i] = 0;
}
for( ;src_pos < src_end; src_pos++,dst++) //copy vector table from vector(virtual)
{
*dst = *src_pos;
}
return;
}
#endif /* End Of CFG_S3C2440A_PLATFORM */