一、虚拟地址
linux在运行时需要隔离不同进程的内存地址,使用虚拟内存就可以隔离不同进程的内存地址。32位地址可以包括0-4G的地址,将4G地址分为4K表项(每项大小为1M),将每段地址的首地址保存在片外内存SDRAM的前4K中,生成地址页表。地址页表保存了物理地址和虚拟地址之间的映射。
当使用mmu时,程序运行速度会变快,mmu会使用data cach(数据)和instructions cach(指令),同时编译器的优化也起作用了(延时函数的变量需要使用volatile描述,否则会被优化,使得延时失效)。
二、实现分析
1、地址页表
// MMU_SECDESC为访问权限
*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | MMU_SECDESC;
三、实现过程
1、伪代码
1、设置栈指针
2、关闭看门狗
3、初始化存储控制器
4、将第二阶段代码拷贝至SDRAM
5、设置页表
6、启动MMU
7、重置栈指针(使用虚拟地址)
8、跳转到SDRAM第二阶段代码
2、启动(start.S)
.text
.global _start
_start:
ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈
bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
bl memsetup @ 设置存储控制器以使用SDRAM
bl copy_2th_to_sdram @ 将第二部分代码复制到SDRAM
bl create_page_table @ 设置页表
bl mmu_init @ 启动MMU
ldr sp, =0xB4000000 @ 重设栈指针,指向SDRAM顶端(使用虚拟地址)
ldr pc, =0xB0004000 @ 跳到SDRAM中继续执行第二部分代码
@ ldr pc, =main
3、初始化代码(init.c)
/*
* init.c: 进行一些初始化,在Steppingstone中运行
* 它和head.S同属第一部分程序,此时MMU未开启,使用物理地址
*/
/* WATCHDOG寄存器 */
#define WTCON (*(volatile unsigned long *)0x53000000)
/* 存储控制器的寄存器起始地址 */
#define MEM_CTL_BASE 0x48000000
/*
* 关闭WATCHDOG,否则CPU会不断重启
*/
void disable_watch_dog(void)