ARM 裸机开发学习笔记(3)内存管理单元MMU
在学习ARM裸机中的内存管理单元MMU时,又回头翻看了在学习linux进程时学到的关于MMU的知识。在此,对两者进行一个小结。
1. linux中的MMU
- 如上图所示:对于程序计数器位数为32位的处理器来说,他的地址发生器所能发出的地址数目为2^32=4G个,于是这个处理器所能访问的最大内存空间就是4G。而实际的物理内存可能为1G,小于这个数目。
- 但是,程序总是逐段被运行的,而且在一段时间内会稳定运行在某一段程序里实际上,一个程序在运行之前,没有必要全部装入内存,而仅需要将那些当前要运行的部分先装入内存,其余部分在用到时再从磁盘调入,而当内存耗光时再将暂时不用的部分调出到磁盘。这使得一个大程序可以在较小的内存空间中运行,也使得内存中可以同时装入更多的程序并发执行,从用户的角度看,该系统所具有的内存容量将比实际内存容量大得多,人们把这样的存储器称为虚拟存储器。所具有的地址称为虚拟地址。
- 从虚拟地址到物理地址的映射记录由内存管理单元MMU完成。映射的地址转换表记录在进程控制块pcb中。
- 由此,即使多个进程中的变量可能是同一虚拟地址,但具体映射到物理内存上时不同的地址。实现了多个进程之间互不干扰,各自执行。
- 其中不同进程的3g-4g内核空间映射到的是物理内存中的相同一片区域,由此可以实现进程之间的通信。
2.ARM裸机中的MMU使用
在linux中MMU的具体映射不用程序员设置,而在ARM裸机开发中,需要建立映射,开启MMU。下图为映射原理框图:
-
连接1处,即CPU发出的地址。站在CPU角度分析,不会区分虚拟地址和物理地址。如果MMU没有使能的话,那么CPU发出的地址就直接到达存储管理器,是物理地址。而如果MMU使能的情况,CPU发出地址为虚拟地址,经过MMU转换为物理地址。并送到存储管理器。
-
连接2处,即MMU转换完成(如果MMU使能)的物理地址,或者存储管理器接收的物理地址。因此,存储管理器操作的都是物理地址。
-
连接3处,需要存储管理器对于SDRAM需要的信息进行初始化配置,在前面一节已具体描述。
3 实验验证
期望结果:通过虚拟地址点亮led灯。
实验流程:sc2440通过nand flash烧写程序,烧写到片内的sram中。其中,将程序分成两部分:第一部分的运行地址设为0,它用来初始化SDRAM、复制第二部分的代码到SDRAM中(存放在0x30004000开始处)、设置页表、启动MMU,最后跳到SDRAM中(地址0xB0004000)去继续执行。第二部分的运行地址设为0xB0004000,它用来驱动LED。
@*************************************************************************
@ File:head.S
@ 功能:设置SDRAM,将第二部分代码复制到SDRAM,设置页表,启动MMU,
@ 然后跳到SDRAM继续执行
@*************************************************************************
.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中继续执行第二部分代码
halt_loop:
b halt_loop
初始化程序如下:
/*
* 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)
{
WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可
}
/*
* 设置存储控制器以使用SDRAM
*/
void memsetup(void)
{
/* SDRAM 13个寄存器的值 */
unsigned long