ARM中MMU使用实例
本开发板SDRAM的物理地址范围处于0x30000000 - 0x33FFFFFF,S3C2410/S3C2440的寄存器地址范围都处于0x48000000 - 0x5FFFFFFF。在第5章中,通过往GPBCON和GPBDAT这两个寄存器的物理地址0x56000010、0x56000014写入特定数据来驱动4个LED。
本章的实例中,将开启MMU,并将虚拟地址空间0xA0000000 - 0xA0100000映射到物理地址空间0x56000000 - 0x56100000上,这样,就可以通过操作地址0xA0000010、0xA0000014来达到驱动这4个LED的同样的效果。
另外,将虚拟地址空间0xB0000000 - 0xB3FFFFFF映射到物理地址空间0x30000000 - 0x33FFFFFF上,并在连接程序时将一部分代码的运行地址指定为0xB0004000(这个数值有些奇怪,看下去就会明白),看看能否使程序跳转到0xB0004000处执行。
本章程序只使用一级页表,以段的方式进行地址映射。32位CPU的虚拟地址空间达到4GB,一级页表中使用4096个描述符来表示这4GB空间(每个描述符对应1MB的虚拟地址),每个描述符占用4字节,所以一级页表占16KB。本实例使用SDRAM的开始16KB来存放一级页表,所以剩下的内存开始物理地址为0x30004000。
将程序代码分为两部分:第一部分的运行地址设为0,它用来初始化SDRAM、复制第二部分代码到SDRAM中(存放在0x30004000开始处)、设置页表、启动MMU,最后跳到SDRAM中(地址0xB0004000)去继续执行;第二部分的运行地址设为0xB0004000,它用来驱动LED。
程序源代码有3个文件:head.S、init.c、leds.c
(1)、head.S代码详解
head.S文件如下:
@*************************************************************************
@ File:head.S
@功能:设置SDRAM,将第二部分代码复制到SDRAM,设置页表,启动MMU,
@然后跳到SDRAM继续执行
@*************************************************************************
.text
.global _start
_start:
ldr sp, =4096@设置栈指针,以下都是C函数,调用前需要@设好栈
bldisable_watch_dog@关闭WATCHDOG,否则CPU会不断重启
blmemsetup@设置存储控制器以使用SDRAM
blcopy_2th_to_sdram@将第二部分代码复制到SDRAM
blcreate_page_table@设置页表
blmmu_init@启动MMU
ldr sp, =0xB4000000@重设栈指针,指向SDRAM顶端(使用虚拟地址)
ldr pc, =0xB0004000@跳到SDRAM中继续执行第二部分代码
halt_loop:
bhalt_loop
head.S中调用的函数都在init.c中实现。
值得注意的是,在第15行开启MMU后,无论是CPU取指还是CPU读写数据,使用的都是虚拟地址。
在第14行设置页表时,在create_page_table函数中令head.S、init.c程序所在内存的虚拟地址和物理地址一样,这使得head.S和init.c中的代码在开启MMU后能够没有任何障碍地继续运行。
(2)init.c代码详解。
init.c中的disable_watch_dog、memsetup函数实现的功能在前面两章已经讨论过,不再重复,下面列出代码方便阅读。
/*
* init.c:进行一些初始化,在Steppingstone中运行
*它和head.S同属第一部分程序,此时MMU未开启,使用物理地址
*/
/* WATCHDOG寄存器*/
#define WTCON(*(volatile unsigned long *)0x53000000)
/*存储控制器的寄存器起始地址*/
#define MEM_CTL_BASE0x48000000
/*
*关闭WATCHDOG,否则CPU会不断重启
*/
void disable_watch_dog(void)
{
WTCON = 0;//关闭WATCHDOG很简单,往这个寄存器写0即可
}
/*
*设置存储控制器以使用SDRAM
*/
void memsetup(void)
{
/* SDRAM 13个寄存器的值*/
unsigned longconstmem_cfg_val[]={ 0x22011110,//BWSCON
0x00000700,//BANKCON0
0x00000700,//BANKCON1
0x00000700,//BANKCON2
0x00000700,//BANKCON3
0x00000700,//BANKCON4
0x00000700,//BANKCON5
0x00018005,//BANKCON6
0x00018005,//BANKCON7
0x008C07A3,//REFRESH
0x000000B1,//BANKSIZE
0x00000030,//MRSRB6
0x00000030,//MRSRB7
};
inti = 0;
volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
for(; i < 13; i++)
p[i] = mem_cfg_val[i];
}
copy_2th_to_sdram函数用来将第二部分代码(即由leds.c编译得来的代码)从Steppingstone中复制到SDRAM中,在连接程序时,第二部分代码的加载地址被指定为2048,重定位地址为0xB0004000,所以系统从NAND Flash启动后,第二部分代码就存储在Steppingstone中地址2048之后,需要把它复制到0x30004000处(此时尚未开启MMU,虚拟地址0xB0004000对应的物理地址在后面设为0x30004000)。Steppingstone总大小为4KB,不妨把地址2048之后的所有数据复制到SDRAM中,所以源数据的结束地址为4096。
copy_2th_to_sdr
ARMMM 相关文章:
- ARM·MMU(11-24)
- ARM MMU工作原理剖析(11-23)
- ARM中MMU的作用(11-11)
- ARM中MMU之地址转换(11-09)
- ARM中MMU地址转换理解(11-09)
- Windows CE 进程、线程和内存管理(11-09)