参考的书籍主要是<深度探索嵌入式操作系统> 彭东 著 第三章的内容 结合uboot 编译rpi遇到的问题
mmu主要是物理地址和虚拟地址的转换
cache主要有icache指令缓存和dcache数据缓存。比如在cpu执行for循环的时候需要重复访问一句指令或者一个数据。访问内存是慢一点的。cache是比内存更快一点的
在第二个阶段的board_r的initr_caches中
static int initr_caches(void)
{
/* Enable caches */
enable_caches();
return 0;
}
enable_caches在arm/cpu/arm11当中
void enable_caches(void)
{
icache_enable();
dcache_enable();
}
分别使用
cache_enable(CR_I); 开启icache
cache_enable(CR_C);开启dcache
基本的CR_X定义在
arch\arm\include\asm\system.h中有
#define CR_M (1 << 0) /* MMU enable*/
#define CR_C (1 << 2) /* Dcache enable*/
#define CR_I (1 << 12) /* Icache enable*/
arch\arm\lib\cache-cp15.c中对于cache_enable定义,主要看这一部分
/* cache_bit must be either CR_I or CR_C */
cache_bit必须是CR_I或者CR_C。也就是cache_enable只对于ICACHE和DCACHE有效
static void cache_enable(uint32_t cache_bit)
{
uint32_t reg;
如果是开启dcache。那么必须先开启mmu。因为dcache只有在mmu开启的时候才有效
/* The data cache is not active unless the mmu is enabled too */
if ((cache_bit == CR_C) && !mmu_enabled())
mmu_setup();
reg = get_cr();/* get control reg. */
cp_delay();
set_cr(reg | cache_bit);
}
开启mmu调用的是mmu_setup() 后续看。
先看统一的
arm\include\asm\system.h定义。armv6系列不支持虚拟化lape所以就是
{
unsigned int val;
asm volatile("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val)
:
: "cc");
将p15协处理器的c1的寄存器的值放到val中
return val;}
static inline void set_cr(unsigned int val)
{
asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR" :
: "r" (val)
: "cc");
将val的值放到p15协处理器的c1的寄存器中
isb();
将0写入p15协处理器的c7寄存器中,附加寄存器c5和4操作码。
通过查表知道这个操作是清空预取缓冲区,把预取缓冲区的数据回写到存储器中。
/*
isb在asm/barriers.h中等同于
asm volatile ("mcr p15, 0, %0, c7, c5, 4" : : "r" (0))
*/
}
主要通过操作arm cp15协处理 寄存器来实现 (还有其他的cpXXX协处理器操作其他功能)。
常用操作协处理器的指令有mrc和mcr {}中表示可选<>表示必选
把数据从协处理寄存器放到普通Rn寄存器中
mrc{cond} <coproc>,<opcode_1>,<Rd>,<CRn>,<CRm> {,opcode_2}
把数据从普通Rn寄存器放到协处理寄存器中
mcr{cond} <coproc>,<opcode_1>,<Rd>,<CRn>,<CRm> {,opcode_2}
1 {cond}是条件,满足条件就执行,没有的话无条件执行。
2 <coproc>表示要处理的协处理器编号
3<opcode_1> 是协处理寄存器的操作码1
4<Rd>需要操作的普通寄存器d
5<CRn>需要操作的协处理寄存器n
6<CRm>需要操作的附加的协处理寄存器m
7{,opcode_2}协处理器的操作码2可能需要多个
比如c0可能对应两个物理寄存器。操作的时候需要通过opcode_2来区分到底是哪一个
static inline void mmu_setup(void)
{
int i;
u32 reg;
空函数
arm_init_before_mmu();
/* Set up an identity-mapping for all 4GB, rw for everyone */
在rpi定义里面有#define CONFIG_NR_DRAM_BANKS 1
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++)
dram_bank_mmu_setup(i);
}
/* Copy the page table address to cp15 */
asm volatile("mcr p15, 0, %0, c2, c0, 0"
: : "r" (gd->arch.tlb_addr) : "memory");
/* Set the access control to all-supervisor */
asm volatile("mcr p15, 0, %0, c3, c0, 0"
: : "r" (~0));
arm_init_domains();
/* and enable the mmu */
reg = get_cr(); /* get control reg. */
cp_delay();
set_cr(reg | CR_M);
}
{
u32 *page_table = (u32 *)gd->arch.tlb_addr;
u32 value = TTB_SECT_AP;
/* Add the page offset */
value |= ((u32)section << MMU_SECTION_SHIFT);
DCACHE_OFF = 0x12,
DCACHE_WRITETHROUGH = 0x1a,
DCACHE_WRITEBACK = 0x1e,
DCACHE_WRITEALLOC = 0x16,
};
value |= option;
/* Set PTE */
page_table[section] = value;
}
{
bd_t *bd = gd->bd;
int i;
debug("%s: bank: %d\n", __func__, bank);
{
gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
gd->bd->bi_dram[0].size = get_effective_memsize();
}
for (i = bd->bi_dram[bank].start >> MMU_SECTION_SHIFT;i < (bd->bi_dram[bank].start >> MMU_SECTION_SHIFT) +(bd->bi_dram[bank].size>>MMU_SECTION_SHIFT);i++)
set_section_dcache(i, DCACHE_WRITEBACK);
}
-
虚拟地址的[31:20]位存放一级页表的入口index,[19:0]位存放段偏移;
-
从TTBR(translation table base register,协处理器CP15中的一个寄存器,用于存放一级页表的基址)寄存器中获取一级页表的基址;
-
一级页表基址+ VA[31:20] = 该虚拟地址对应的页表描述符的入口地址;
-
页表描述符的[31:20]位为该虚拟地址对应的物理段基址;
-
物理段基址+ VA[19:0]段偏移= 物理地址
cp_delay();
set_cr(reg | CR_M);
cp_delay();
set_cr(reg &(~ CR_M) );