一、MMU介绍

1.1 虚拟地址与物理地址

  建立两个应用程序,hello1.c和hello2.c,然后运行:

  hello1.c

  

  hello2.c

  

  运行结果如下:

  

  可以看到两个结果打印的地址是一样的,都为 0x601040,这说明两段程序都运行于同一个地址中。我们的死循环程序又保证了两个程序在同时运行。

   

  对于2440来说,如下图:

  

  CPU只管发出地址,读写数据。不管地址是否是物理地址还是虚拟地址。

  写程序的时候,链接地址也没有物理地址和虚拟地址。链接地址是CPU看到的,是从CPU的角度来说的。

1.2 虚拟地址转换成物理地址

  对与ARM来说,虚拟地址(VA)转换成物理地址(PA)是通过表格来转换的。这个表格就是页表。

  建立映射的简单步骤是:

  • 建立表格:虚拟地址到物理地址的映射
  • 表格地址告诉给MMU:表格在内存中,将表格的首地址告诉MMU
  • 启动MMU  

二、代码

2.1 start.S (arch\arm\cpu\arm920t)

  start.S中的cpu_init_crit进行了MMU的使能设置,u-boot启动的时候的是不使能MMU的。MMU的使能涉及到CP15协处理器。

  代码段如下:

     /*
* disable MMU stuff and caches
*/
mrc p15, , r0, c1, c0, /* 将 CP15 的寄存器 C1 的值读到 r0 中 */
/* C1寄存器的8,9,13位被清除
* S(bit[8])在基于 MMU 的存储系统中,本位用作系统保护
* R(bit[9])在基于 MMU 的存储系统中,本位用作 ROM 保护
* V(bit[13])
* 对于支持高端异常向量表的系统,本控制位控制向量表的位置
* 0 :选择低端异常中断向量 0x0~0x1c
* 1 :选择高端异常中断向量0xffff0000~ 0xffff001c
* 对于不支持高端异常向量表的系统,读取时该位返回0,写入时忽略
*/
bic r0, r0, #0x00002300 @ clear bits , : (--V- --RS)
/* C1寄存器的0,1,2,7位被清除
* M(bit[0])
* 0 :禁止 MMU 或者 PU
* 1 :使能 MMU 或者 PU
* 如果系统中没有MMU及PU,读取时该位返回0,写入时忽略该位
* A(bit[1])
* 0 :禁止地址对齐检查
* 1 :使能地址对齐检查
* C(bit[2])
* 当数据cache和指令cache分开时,本控制位禁止/使能数据cache。
* 当数据cache和指令cache统一时,该控制位禁止/使能整个cache。
* 0 :禁止数据 / 整个 cache
* 1 :使能数据 / 整个 cache
* 如果系统中不含cache,读取时该位返回0.写入时忽略
* 当系统中不能禁止cache 时,读取时返回1.写入时忽略
* B(bit[7])
* 对于存储系统同时支持big-endian和little-endian的ARM系统,本控制位配置系统的存储模式
* 0 : little endian
* 1 : big endian
* 对于只支持little-endian的系统,读取时该位返回0,写入时忽略
* 对于只支持big-endian的系统,读取时该位返回1,写入时忽略
*/
bic r0, r0, #0x00000087 @ clear bits , : (B--- -CAM)
/* C1寄存器的bit1置1,即使能地址对齐 */
orr r0, r0, #0x00000002 @ set bit (A) Align
/* C1寄存器的bit12置1,即使能指令 cache */
/* I(bit[12])
* 当数据cache和指令cache是分开的,本控制位禁止/使能指令cache
* 0 :禁止指令 cache
* 1 :使能指令 cache
* 如果系统中使用统一的指令cache和数据cache或者系统中不含cache,读取该位时返回0,写入时忽略。
* 当系统中的指令cache不能禁止时,读取时该位返回1,写入时忽略
*/
orr r0, r0, #0x00001000 @ set bit (I) I-Cache
mcr p15, , r0, c1, c0, /* 将 r0 的值写到 CP15 的寄存器 C1 中 */ /*
* before relocating, we have to setup RAM timing
* because memory timing is board-dependend, you will
* find a lowlevel_init.S in your board directory.
*/
mov ip, lr /* 保存函数地址,用于返回 */

  之后start.S 中的代码会进入 _main(crt0.S (arch\arm\lib))中运行。

2.2 crt0.S (arch\arm\lib)

  ctr0.S中运行 _main 函数,再此函数中,运行到 board_init_f(单板启动前初始化),然后执行到链表 init_sequence_f,在其中对MMU进行初始化 reserve_mmu。

2.2.1 reserve_mmu

 static int reserve_mmu(void)
{
/* reserve TLB table */
gd->arch.tlb_size = PGTABLE_SIZE; //PGTABLE_SIZE = 4096 *4 预留16kb的MMU页表
gd->relocaddr -= gd->arch.tlb_size;//gd->relocaddr = gd->relocaddr - 16K = 0x33ffc000 /* round down to next 64 kB limit */
gd->relocaddr &= ~(0x10000 - );//64kb对齐 gd->relocaddr = 0x33ff0000 gd->arch.tlb_addr = gd->relocaddr;//gd->arch.tlb_addr = 0x33ff0000
debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr,
gd->arch.tlb_addr + gd->arch.tlb_size);
return ;
}

  PGTABLE_SIZE的大小我们可以看 u-boot.dis中得到:

  

  第一行就是 PGTABLE_SIZE 得大小。

  在执行完链表以后,跳回_main中继续执行,然后执行到board_init_r(Board_r.c (common)板启动后初始化代码)。

  在board_init_r同样会执行一个链表,init_sequence_r。在链表中执行各种初始化函数,然后在执行到 board_init 中,在board_init中,进行icache_enable和dcache_enable。

  这两个函数都会调用 cache_enable 函数。在其中就有MMU的设置。

2.2.2 cache_enable

  cache_enable

 static void cache_enable(uint32_t cache_bit)
{
uint32_t reg; /* 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_setup 函数

 /* 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 */
for (i = ; i < ; i++)
set_section_dcache(i, DCACHE_OFF); //传入DCACHE_OFF参数,建立页表地址 for (i = ; i < CONFIG_NR_DRAM_BANKS; i++) {
dram_bank_mmu_setup(i); //设置DRAM的页表大小和地址
} /* Set the access control to all-supervisor */
asm volatile("mcr p15, 0, %0, c3, c0, 0"
: : "r" (~)); //MMU进行初始化 arm_init_domains(); //空函数 /* and enable the mmu */
reg = get_cr(); /* get control reg. */
cp_delay();
set_cr(reg | CR_M);
} arch/arm/include/asm/system.h
/* Size of an MMU section */
enum {
MMU_SECTION_SHIFT = ,
MMU_SECTION_SIZE = << MMU_SECTION_SHIFT,
}; /* 页表建立函数,每一页为1M,页的起始地址为section */
void set_section_dcache(int section, enum dcache_option option)
{
u32 *page_table = (u32 *)gd->arch.tlb_addr; //page_table取出来,16K
u32 value; value = (section << MMU_SECTION_SHIFT) | ( << ); //2的20次方为1M
value |= option;
page_table[section] = value;
} __weak void dram_bank_mmu_setup(int bank)
{
bd_t *bd = gd->bd;
int i; debug("%s: bank: %d\n", __func__, bank);
for (i = bd->bi_dram[bank].start >> ;
i < (bd->bi_dram[bank].start >> ) + (bd->bi_dram[bank].size >> );
i++) { set_section_dcache(i, DCACHE_WRITETHROUGH);
}
}

  

u-boot移植(八)---代码修改---存储控制器--MMU的更多相关文章

  1. u-boot移植(七)---代码修改---存储控制器

    一.CPU访问芯片的条件 CPU通过访问存储控制器,来读取外部设备的数据. CPU想访问一个芯片,需要如下条件(配置信息): 地址线 数据线:8位/16位/32位数据宽度 时钟/频率 其他芯片相关的特 ...

  2. -boot移植(十一)---代码修改---支持nandflash

    一.移植前的修改 1.1 include/configs/jz2440修改 原来的定义: 可以看出,要先定义CONFIG_CMD_NAND才能使能NANDFlash. 这个在我们文件中的82行有定义, ...

  3. Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用

    Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用 原创 2017-04-13 嘟嘟MD 嘟爷java超神学堂 前言 前面几章介绍了一些基础,但都是静 ...

  4. u-boot移植(五)---代码修改---时钟修改、SDRAM

    最开始已经建立了新单板以及配置文件,现在就需要做的是代码的修改,配置成适合目标板使用的u-boot. 一.时钟修改 在代码流程分析中,我们知道,系统的启动是: 设置 CPU 为管理员模式 关闭看门狗 ...

  5. u-boot移植(十二)---代码修改---支持DM9000网卡

    一.准备工作 1.1 原理图 CONFIG_DM9000_BASE 片选信号是接在nGCS4引脚,若要确定网卡的基地址,则要根据片选信号的接口去确定. 在三星2440的DATASHEET中memory ...

  6. s3c2440存储控制器和地址以及启动的理解

    转自:http://blog.sina.com.cn/s/blog_5ddb672b0100fkcf.html 1.首先应该先了解Flash ROM的种类 NOR FLASH地址线和数据线分开,来了地 ...

  7. JZ2440 裸机驱动 第6章 存储控制器

    本章目标:     了解S3C2410/S3C2440地址空间的布局     掌握如何通过总线形式访问扩展的外设,比如内存.NOR Flash.网卡等 ························ ...

  8. 使用八种牛云存储解决方案ios7.1的app部署问题

    使用八种牛云存储解决方案ios7.1的app部署问题 一个.问题叙述性说明 开发完ios版本号的app.须要将.ipa文件和.plist文件打包上传,供用户下载,在线安装.用户安装过程简单描写叙述例如 ...

  9. spring boot / cloud (八) 使用RestTemplate来构建远程调用服务

    spring boot / cloud (八) 使用RestTemplate来构建远程调用服务 前言 上周因家里突发急事,请假一周,故博客没有正常更新 RestTemplate介绍: RestTemp ...

随机推荐

  1. CSS全屏布局的6种方式

    前面的话 全屏布局在实际工作中是很常用的,比如管理系统.监控平台等.本文将介绍关于全屏布局的6种思路 float [1]float + calc 通过calc()函数计算出.middle元素的高度,并 ...

  2. BZOJ4764弹飞大爷——LCT

    题目描述 自从WC退役以来,大爷是越来越懒惰了.为了帮助他活动筋骨,也是受到了弹飞绵羊一题的启发,机房的小伙伴们 决定齐心合力构造一个下面这样的序列.这个序列共有N项,每项都代表了一个小伙伴的力量值, ...

  3. Chrome 屏蔽广告

    转载: http://blog.csdn.net/yenange/article/details/76145216 1. 上网站: http://www.adtchrome.com/ Chorme下载 ...

  4. P3201 [HNOI2009]梦幻布丁

    题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1的四个布丁一共有3段颜色. 输入输出格式 输入格式: 第 ...

  5. Java生成多数值二元运算结果集

    看之前大学写过的24点程序中用到的核心计算算法——计算四个值能否计算出24,当时用的c++写的,现用Java重写一遍 程序实现了多个数值(可重复),每个数值只能运算一次,二元运算的条件下获得所有结果集 ...

  6. MT【218】交点个数

    若函数$f(x)=x^3+ax^2+bx+c$有极值点$x_1,x_2$,且$f(x_1)=x_1$,则关于$x$的方程$3(f(x))^2+2af(x)+b=0$的不同实数根个数为_____ 注意到 ...

  7. MT【217】韦达定理应用

    若2018次方程$x^{2018}-4036x^{2017}+a_{2016}x^{2016}+\cdots+a_1x+a_0=0$ 有2018个正实数, 则对于所有可能的方程$\sum\limits ...

  8. Java编程,打印昨天的当前时刻

    public class Demo {  /*  * Java编程,打印昨天的当前时刻  */ public static void main(String[] args){  Calendar ca ...

  9. 洛谷 P1879 [USACO06NOV]玉米田 解题报告

    P1879 [USACO06NOV]玉米田Corn Fields 题目描述 农场主\(John\)新买了一块长方形的新牧场,这块牧场被划分成\(M\)行\(N\)列\((1 ≤ M ≤ 12; 1 ≤ ...

  10. 前端学习 -- Html&Css -- ie6 png 背景问题

    在IE6中对图片格式png24支持度不高,如果使用的图片格式是png24,则会导致透明效果无法正常显示 解决方法: 1.可以使用png8来代替png24,即可解决问题,但是使用png8代替png24以 ...