uboot中的mmu和cache开启(基本协处理器操作)

参考的书籍主要是<深度探索嵌入式操作系统> 彭东 著 第三章的内容 结合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所以就是

static inline unsigned int get_cr(void)
{
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可能需要多个


CP15协处理器是一个统称。CP15包括了16个32bit的寄存器 c0-c15具体每个寄存器功能要查表。

比如c0可能对应两个物理寄存器。操作的时候需要通过opcode_2来区分到底是哪一个


看到gercr和setcr主要是操作了cp15协处理器的c1寄存器
c1寄存器是存储系统的控制寄存器
第0位CR_M控制MMU开启关闭
第2位CR_C控制数据cache的开启关闭
第12位CR_I控制指令cache的开启关闭
0表示关闭 1表示开启

因此对于开启icache和dcache就是简单地设置了一个cp15的cr1对应的标志位。目前只了解cache的开启和关闭就行了。
但是使用dcache之前开启了mmu,mmu是有必要了解清楚的。

mmu_setup()也在cache-cp15.c中

/* to activate the MMU we need to set up virtual memory: use 1M areas */
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 */
        // #define MMU_SECTION_SHIFT20
/*
i<(4GB>>20) 也就是1MB i<4096
*/
这里uboot的mmu用段来表示。也就是1M为大小,1级页表4096个条目恰好是4GB。
还可以用64KB 4kb1kb来表示。那就需要多级页表了。

for (i = 0; i < ((4096ULL * 1024 * 1024) >> MMU_SECTION_SHIFT); i++)
{
 设置1M页表的每一项内容
 每一个页表项的31:20bit是内存空间的物理地址。段页是1M,因此低20位一定为0.刚好可以做控制位。具体可以看段页表低20bit各个位内容。
 set_section_dcache(i, DCACHE_OFF);
}

在rpi定义里面有#define CONFIG_NR_DRAM_BANKS 1
因此只要执行一次dram_bank_mmu_setup(0)
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++)
 {
将所有是有效的内存设置DCACHE为DCACHE_WRITEBACK
dram_bank_mmu_setup(i);
}

/* Copy the page table address to cp15 */
将页表地址tlb_addr放到c2寄存器当中。c2存放一级页表基地址。这个地址是物理地址
asm volatile("mcr p15, 0, %0, c2, c0, 0"
    : : "r" (gd->arch.tlb_addr) : "memory");

将0xFFFFFFFF放到c3寄存器当中。c3寄存器每两位定义了一个访问权限,。0b11表示不做权限检查,0xffffffff就是全部是1,任何人都能访问。
/* 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 */
以下是开启MMU的代码
reg = get_cr(); /* get control reg. */
cp_delay();
set_cr(reg | CR_M);
}

在reserve_mmu里面对于 tlb_addr和tlb_size都有初始化 tlbsize=4096*4 也就是tlb表为64KB

设置页表项的函数。
void set_section_dcache(int section, enum dcache_option option)
{
u32 *page_table = (u32 *)gd->arch.tlb_addr;
//#define TTB_SECT_AP (3 << 10) 访问控制位。是段页项的10 11bit因此左移10. 11代表的是可读可写。
//但是由于后面C3寄存器被设置为任何人都能访问,因此这里的AP位是无效的。
//C3寄存器 为01时。AP位才有效,和C1的R S位来确定访问权限。
u32 value = TTB_SECT_AP;

/* Add the page offset */
设置页表条目内存空间的物理地址。
前面的的for循环从0-4095因此4096个页表的基地址依次是
0x00000000 0x00100000 0x00200000 ... ... 0xFFF00000 每个段1M恰好4GB
value |= ((u32)section << MMU_SECTION_SHIFT);

添加cachebit设置

enum dcache_option {
DCACHE_OFF = 0x12,
DCACHE_WRITETHROUGH = 0x1a,
DCACHE_WRITEBACK = 0x1e,
DCACHE_WRITEALLOC = 0x16,
};
DCACHE_OFF =0x12=0b  1(4bit) 0(3bit) 0(2bit) 1(1bit) 0(0bit)
1:0bit 是 10 表示当前条目是段页
3:2bit是   00表示无缓存
4bit是向后兼容 最好为1
        
/* Add caching bits */
value |= option;
/* Set PTE */
page_table[section] = value;
}

对于rpi只执行了一次dram_bank_mmu_setup(0)

void dram_bank_mmu_setup(int bank)
{
bd_t *bd = gd->bd;
int i;
debug("%s: bank: %d\n", __func__, bank);
/*
bi_dram的初始化是
__weak void dram_init_banksize(void)
{
gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
gd->bd->bi_dram[0].size = get_effective_memsize();
}
 
CONFIG_SYS_SDRAM_BASE  是0
get_effective_memsize();返回的是ram_size大小 448MB
*/
这里也就是将所有的有效内存都设置为DCACHE_WRITEBACK

因此这里就是从i从  0-448都设置为DCACHE_WRITEBACK
        448-4095都是DCACHE_OFF

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);
 }
}

对于1M段mmu 虚拟地址到物理地址的转换。
  1. 虚拟地址的[31:20]位存放一级页表的入口index[19:0]位存放段偏移;

  2. TTBRtranslation table base register,协处理器CP15中的一个寄存器,用于存放一级页表的基址)寄存器中获取一级页表的基址;

  3. 一级页表基址+ VA[31:20] = 该虚拟地址对应的页表描述符的入口地址;

  4. 页表描述符的[31:20]位为该虚拟地址对应的物理段基址;

  5. 物理段基址+ VA[19:0]段偏移物理地址



如果其他已经设置好了可以写简单的函数操作cp15 的cr1寄存器的0bit来开启关闭mmu。
void enable_mmu()
{
u32 reg;
reg = get_cr(); /* get control reg. */
cp_delay();
set_cr(reg | CR_M);
}

void disable_mmu()
{
u32 reg;
reg = get_cr(); /* get control reg. */
cp_delay();
set_cr(reg
&(~ CR_M) );
}

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值