uboot之关闭缓存和mmu详解

大家在学习uboot 的时候,肯定会遇到这种情况:当设置完时钟分频以后,uboot就会执行cpu_init_crit汇编函数,这个函数的主要作用就是关闭缓存和mmu,然后调用lowlevel_init函数进行系统总线的初始化。

为什么启动的时候,需要关闭缓存和mmu呢?我们先了解一下他们的作用。

缓存是主存(内存)和CPU通用寄存器之间设置的一个高速的、容量相对较小的存储器,把正在执行的指令地址附近的一部分指令或数据从主存调入这个存储器,供CPU在一段时间内使用,以提高程序的运行速度。

mmu可以实现虚拟内存和内存保护等功能,完成对内存的操作和管理。
CACHE是高速缓冲存储器。CPU工作速度是很快的,而外部内存是工作很慢的,所以当CPU对内存访问的时候,是要等待内存访问结束的。所以中间CPU就在等待,这就浪费了时间。所以在CPU和内存之间加一个CACHE,当CPU写数据到内存中的时候,就先写入到CACHE中,然后CACHE再写入到内存中。CPU写CACHE是很快的,所以就提高了写数据的效率。读数据的话,CPU先在CACHE中去找数据,没有找到的话,CACHE将数据从内存中取出来,再给CPU,同时把这个数据存起来。当CPU在CACHE中找到数据的话,就直接使用这个数据,就不用再去内存中取数据了。

Caches是CPU内部的一个2级缓存,它的作用是将常用的数据和指令放在CPU内部。Caches是通过CP15管理的,刚上电的时候,CPU还不能管理Caches。上电的时候指令Cache可关闭,也可不关闭,但数据Cache一定要关闭,否则可能导致刚开始的代码里面,去取数据的时候,从Cache里面取,而这时候RAM中数据还没有Cache过来,导致数据预取异常 。说到Caches就必须提到一个关键字Volatile,它的本质:是告诉编译器不要对我的代码进行优化,作用是让编写者感觉变量的变化情况。因为在优化时,会将常用的代码取出来放到Caches中,它没有从实际的物理地址去取,它直接从CPU的缓存中去取,但常用的代码就是为了检测一些常用变量的变化,如果正在取数据的时候发生跳变,那么就检测不到变量的变化了,所以在这种情况下要用Volatile关键字告诉编译器不要做优化,让cpu每次都从实际的物理地址中去取指令。其实这也是为什么要关闭数据缓存的原因,如果汇编指令读取的时候缓存中的数据,而实际物理地址的数据发生了变化,将导致cpu读取不到真实的最新的值。然而在C语言中是不会关闭Caches的,如果编写者要检测外界物理数据的变化,或变化太快,从Caches中取数据会有误差,就加一个关键字Volatile。

同样,在板子启动的时候是没有对mmu进行初始化的,而且这个时候也用不到mmu,为了避免他们影响启动时的初始化,所以需要先关闭mmu和缓存。

2440的协处理器CP15总共有c0~c15这16个协处理器寄存器,各自具有一定的功能定义。但总的来说,cp15主要跟以下功能有关:
1、获取device id和cache type等一些CPU相关信息。
2、MMU操作。包括MMU的使能和禁止,虚拟地址到物理地址的映射机制建立
3、访问权限控制。主要用来实现安全机制和linux的写时复制(copy on write)。
4、设置时钟模式。init.S中MMU_SetAsyncBusMode和MMU_SetFastBusMode这两个函数

和MMU有关的p15寄存器为c1(control register)和c2(TTB translation table base register)。其中c2比较简单,就是用来储存从虚拟地址到物理地址的地址转换表的基地址的(转换表存放在内存中,譬如可以放在0x30000000地址),因此我们在初始化mmu的时候,只要将规划的转换表基地址用mcr指令传送到该c2寄存器即可。而c1寄存器为控制寄存器,详细定义如下:
Register 1 - Control (read/write) 
All values set to 0 at power-up. 
o    Bit    0 - On-chip MMU turned off (0) or on (1) 用来关闭或使能MMU
o    Bit    1 - Address alignment fault disabled (0) or enabled (1) 关闭或打开地址对齐检查
o    Bit    2 - Data cache turned off (0) or on (1) 数据cache打开或关闭
o    Bit    3 - Write buffer turned off (0) or on (1) 
o    Bit    7 - Little-endian operation if 0, big-endian if 1 用来选择大小端格式
o    Bit    8 - System bit - controls the MMU permission system 
o    Bit    9 - ROM bit - controls the MMU permission system bit8(S bit ) and bit9(R bit)用来管理MMU访问权限,第3部分会详述
o    Bit  12 - Instruction cache turned off (0) or on (1)” 指令cache打开或关闭
o    Bit  13 - Base location of exception registers. 0x00000000(0) or 0xffff0000(1)上电启动地址。
o    Bit  14 - Round robin replacement ,random replacement(0) or round-robin replacement(1).不太懂这个
o    Bit  15 ~ Bit29   reserved
o    Bit  30  nF bit bit30 和 bit31共同用来决定总线模式。 iA:nF = 00 FastBus mode 
o    Bit  31  iA bit


Registe bits


Name


Function


Value


31


iA bit


Asynchronous clock select


见时钟模式表


30


nF bit


notFastBus select


见 时钟模式表


29:15


-


Reserved


Read = Unpredictable

Write = should be zero


14


RR bit


Round robin replacement


0 = Random replacement

1 = Round robin replacement


13


V bit


Base location of exception register(异常寄存器基地址)


0 = Low address = 0x0000 0000

1 = High address = 0xFFFF 0000


12


I bit


Instruction cache enable


0 = Instruction cache disable

1 = Instruction cache enable


11:10


-


Reserved


Read = 00

Write = 00


9


R  bit


ROM protection


见图1


8


S  bit


System protection


见图1


7


B  bit


Big-endian/little-endian


0 = Little-endian operation

1 = Big-endian operation


6:3


-


Reserved


Read = 1111

Write = 1111


2


C bit


Data cache enable


0 = data cache disable

1 = data cache enable


1


A bit


Alignment fault enable


Data address alignment fault checking

(地址对齐检查)

0 = 禁用地址对齐检查功能

1 = 使能地址对齐检查功能


0


M bit


MMU enable


0 = MMU disable

1 = MMU enable

结合以上对c1寄存器的位定义的分析,我们来看看下面这个函数:

[cpp] view plaincopy

void MMU_Init(void)

{

__asm{

mov r0,#0x30000000;     // r0=TTBase 即页表的基地址

mcr p15,0,r0,c2,c0,0;   // C2中存放地址转换表基地址

mvn r0, #0;             // 数据取反传送指令

mcr p15,0,r0,c3,c0,0;   // 访问类型为管理者权限

mrc p15,0,r0,c1,c0,0;   // 读出协处理器C1

orr r0,r0,#01;          // 或操作,使最低位为1

mcr p15,0,r0,c1,c0,0;   // 给C1赋值

}

}

函数中使用ARM寄存器r0作为和协处理器寄存器的接口。mcr p15,0,r0,c2,c0,0这句将r0中得值(0x30000000,这个是我们规划的转换表的基地址)放入(因此是mcr,所以是从ARM寄存器到p15协处理器寄存器)c2中。c2即是p15中的转换表基址。

[cpp] view plaincopy

mrc p15,0,r0,c1,c0,0;    // 读出协处理器C1

orr r0,r0,#01;          // 或操作,使最低位为1

mcr p15,0,r0,c1,c0,0;   // 给C1赋值

典型的读-改-写三步操作,目的就是将c1寄存器的bit0置1而同时不影响其他位。根据上面的寄存器定义可知,c1的bit0为MMU enable or disable,因此该三句代码实际上是打开了MMU。(注意MMU打开前后,地址空间发生了变化。MMU打开前程序是工作在物理地址空间的,而MMU打开后程序便工作在了虚拟地址空间)

c1中跟MMU有关的还有data cache和instruction cache的打开和关闭,S bit和 R bit联合组成的访问权限控制等位。另外,c1中还有其他一些我们可能会用到的信息位。
譬如:Bit7用来选择大小端模式,bootloader中一般会有代码,通过设置该位来告知CPU当前板子使用的是little endian or big endian。(因为该位上电默认是0,因此默认的模式为小端模式。); Bit13为上电启动地址,也就是reset excetion复位异常的入口地址。上电默认也是0,因此默认的上电启动地址为0x00000000。当我们使用mcr指令将该位置1时,便可以将reset exception设置到 0xffff0000,记得这个好像是为了WinCE的移植支持设计的。

下面是uboot中关闭mmu和cache的cpu_init_crit函数:

[plain] view plain copy

/*

*************************************************************************

*

* CPU_init_critical registers

*

* setup important registers

* setup memory timing

*

*************************************************************************

*/

#ifndef CONFIG_SKIP_LOWLEVEL_INIT

cpu_init_crit:

/*

* flush v4 I/D caches

*/

mov r0, #0

mcr p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache */

mcr p15, 0, r0, c8, c7, 0   /* flush v4 TLB */

/*

* disable MMU stuff and caches

*/

mrc p15, 0, r0, c1, c0, 0

bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)

bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)

orr r0, r0, #0x00000002 @ set bit 2 (A) Align

orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache

mcr p15, 0, r0, c1, c0, 0

/*

* 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

bl  lowlevel_init

mov lr, ip

mov pc, lr

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

在关闭CACHE之前,需要要做一件事,就是要将CACHE的原有的数据给清掉。因为有可能之前,里面就有一些数据了,这个操作也是由CP15下的一个寄存器控制的。

清除完cache中的数据后,就可以关闭mmu和cache了。

接下来就是跳转到lowlevel_init函数,进行其他的初始化。

原文来自:C博客/奔跑的路

时间: 2024-12-18 23:23:05

uboot之关闭缓存和mmu详解的相关文章

[转]hibernate缓存机制所有详解

以下文章来自http://www.blogjava.net/tbwshc/articles/380013.html Hibernate 所有缓存机制详解 hibernate提供的一级缓存 hibernate是一个线程对应一个session,一个线程可以看成一个用户.也就是说session级缓存(一级缓存)只能给一个线程用,别的线程用不了,一级缓存就是和线程绑定了. hibernate一级缓存生命周期很短,和session生命周期一样,一级缓存也称session级的缓存或事务级缓存.如果tb事务提

【运维基本功】centos6.5下巧用netstat命令的参数分析TCP连接与关闭过程,图文详解

前言 使用centos6.5系统自带的 netstat,grep,watch等命令,来分析网络连接状态,要求对 TCP 有限状态机的概念有较深入的理解. 同时,这也是除了使用强大的专业第三方协议分析器,如 wireshark 以外,最有效的办法. 写本博文的目的其中之一就是要告诉大家,不使用 wireshark 等第三方工具,自己也能做到一定粒度的网络连接,状态分析,调试等等. 用到的命令总结如下: watch -n 1 -d 'netstat -antupeo | grep --color 8

缓存varnish配置详解

一 工作原理 在当前主流的Web服务架构体系中,Cache担任着越来越重要的作用.常见的基于浏览器的C/S架构,Web Cache更是节约服务器资源的关键.而最近几年由FreeBSD创始人之一Kamp开发的varnish更是一个不可多得的Web Cache Server.严格意义上说,Varnish是一个高性能的反向代理软件,只不过与其出色的缓存功能相比,企业更愿意使用其搭建缓存服务器.同时,由于其工作在Web Server的前端,有一部分企业已经在生产环境中使用其作为旧版本的squid的替代方

U-boot在S3C2440上的移植详解(一)

http://www.embeddedlinux.org.cn/html/jishuzixun/201303/16-2499.html 一.移植环境 主  机:VMWare--Fedora 9 开发板:Mini2440--64MB Nand,Kernel:2.6.30.4 编译器:arm-linux-gcc-4.3.2.tgz u-boot:u-boot-2009.08.tar.bz2 二.移植步骤 本次移植的功能特点包括: 支持Nand Flash读写 支持从Nor/Nand Flash启动

memcache缓存函数方法详解

1.Memcache::add用法  代码:bool Memcache::add ( string $key , mixed $var [, int $flag [, int $expire ]] ) 说明: 如果$key不存在的时候,使用这个函数来存储$var的值.功能相同的函数是memcache_add(). 参数: $key :将要存储的键值. $var :存储的值,字符型和整型会按原值保存,其他类型自动序列化以后保存. $flag:是否用MEMCACHE_COMPRESSED来压缩存储的

php-fpm进程关闭与重启脚本详解

先来理解一下什么是php-fpm PHP-FPM是一个PHP FastCGI管理器,是只用于PHP的. PHP-FPM其实是PHP源代码的一个补丁,旨在将FastCGI进程管理整合进PHP包中.必须将它patch到你的PHP源代码中,在编译安装PHP后才可以使用. 现在我们可以在最新的PHP 5.3.2的源码树里下载得到直接整合了PHP-FPM的分支,据说下个版本会融合进PHP的主分支去.相对Spawn-FCGI,PHP-FPM在CPU和内存方面的控制都更胜一筹,而且前者很容易崩溃,必须用cro

HTML5应用程序缓存Application Cache详解.RP

什么是Application Cache HTML5引入了应用程序缓存技术,意味着web应用可进行缓存,并在没有网络的情况下使用,通过创建cache manifest文件,可以轻松的创建离线应用. Application Cache带来的三个优势是: ① 离线浏览 ② 提升页面载入速度 ③ 降低服务器压力 而且主要浏览器皆以支持Application Cache,就算不支持也不会对程序造成什么影响 离线存储技术 HTML5提出了两大离线存储技术:localstorage与Application

 iOS 网络请求缓存:NSURLCache详解

我读过一些开源项目的网络请求缓存的代码,基本上都是采用在本地存文件的方式进行缓存.如果你打算在你的项目中加入网络请求的缓存,可能你并不需要自己造一个轮子,了解一下 NSURLCache 就足够.本文为大家接收的就是ios开发中的NSURLCache相关使用,一起来看看吧. 缓存 首先, NSURLCache 提供的是内存以及磁盘的综合缓存机制.许多文章谈到,使用NSURLCache 之前需要在 AppDelegate 中缓存空间的设置: - (BOOL)application:(UIApplic

HTML5应用程序缓存Application Cache详解

什么是Application Cache HTML5引入了应用程序缓存技术,意味着web应用可进行缓存,并在没有网络的情况下使用,通过创建cache manifest文件,可以轻松的创建离线应用. Application Cache带来的三个优势是: ① 离线浏览 ② 提升页面载入速度 ③ 降低服务器压力 而且主要浏览器皆以支持Application Cache,就算不支持也不会对程序造成什么影响 离线存储技术 HTML5提出了两大离线存储技术:localstorage与Application