一、cpu_init_crit

  当执行完时钟初始化后,程序执行:

  bl    cpu_init_crit

  跳转到CPU初始化处进行,在其中主要是执行 caches 的关闭 和 MMU的关闭,之后跳转到 lowlevel_init 中执行,进行系统总线的初始化。

1.1 缓存和MMU的作用

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

  mmu可以实现虚拟内存和内存保护等功能,完成对内存的操作和管理。

1.1.1 CACHE

  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。

1.1.2 MMU

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

1.1.3 协处理器CP15

  • 2440的协处理器 CP15 总共有 c0~c15 这16个协处理器寄存器,各自具有一定的功能定义。但总的来说,cp15 主要跟以下功能有关:

    • 获取 device id 和 cache type 等一些CPU相关信息。
    • MMU 操作。包括 MMU 的使能和禁止,虚拟地址到物理地址的映射机制建立
    • 访问权限控制。主要用来实现安全机制和 linux 的写时复制(copy on write)。 
    • 设置时钟模式。init.S 中 MMU_SetAsyncBusMode 和 MMU_SetFastBusMode 这两个函数

  和MMU有关的p15寄存器为 c1(control register)和 c2(TTB translation table base register)。其中 c2 比较简单,就是用来储存从虚拟地址到物理地址的地址转换表的基地址的(转换表存放在内存中,譬如可以放在0x30000000地址),因此我们在初始化mmu的时候,只要将规划的转换表基地址用mcr指令传送到该c2寄存器即可。而c1寄存器为控制寄存器,详细定义如下:  

  

  • 操作指令

  

  

  

  

  

  

  

  CP15 中的寄存器 C1 的编码格式及含义说明如下:
 

C1中的控制位

含义

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.写入时忽略

W(bit[3])

0 :禁止写缓冲

1 :使能写缓冲

如果系统中不含写缓冲时,读取时该位返回0.写入时忽略

当系统中不能禁止写缓冲时,读取时返回1.写入时忽略

P(bit[4])

对于向前兼容26位地址的ARM处理器,本控制位控制PROG32控制信号

0 :异常中断处理程序进入 32 位地址模式

1 :异常中断处理程序进入26 位地址模式

如果本系统中不支持向前兼容26位地址,读取该位时返回1,写入时忽略

D(bit[5])

对于向前兼容26位地址的ARM处理器,本控制位控制DATA32控制信号

0 :禁止 26 位地址异常检查

1 :使能 26 位地址异常检查

如果本系统中不支持向前兼容26位地址,读取该位时返回1,写入时忽略

L(bit[6])

对于ARMv3及以前的版本,本控制位可以控制处理器的中止模型

0 :选择早期中止模型

1 :选择后期中止模型

B(bit[7])

对于存储系统同时支持big-endian和little-endian的ARM系统,本控制位配置系统的存储模式

0 : little endian

1 : big endian

对于只支持little-endian的系统,读取时该位返回0,写入时忽略

对于只支持big-endian的系统,读取时该位返回1,写入时忽略

S(bit[8])

在基于 MMU 的存储系统中,本位用作系统保护

R(bit[9])

在基于 MMU 的存储系统中,本位用作 ROM 保护

F(bit[10])

由生产商定义

Z(bit[11])

对于支持跳转预测的ARM系统,本控制位禁止/使能跳转预测功能

0 :禁止跳转预测功能

1 :使能跳转预测功能

对于不支持跳转预测的ARM系统,读取该位时返回0,写入时忽略

I(bit[12])

当数据cache和指令cache是分开的,本控制位禁止/使能指令cache

0 :禁止指令 cache

1 :使能指令 cache

如果系统中使用统一的指令cache和数据cache或者系统中不含cache,读取该位时返回0,写入时忽略。当系统中的指令cache不能禁止时,读取时该位返回1,写入时忽略

V(bit[13])

对于支持高端异常向量表的系统,本控制位控制向量表的位置

0 :选择低端异常中断向量 0x0~0x1c

1 :选择高端异常中断向量0xffff0000~ 0xffff001c

对于不支持高端异常向量表的系统,读取时该位返回0,写入时忽略

PR(bit[14])

如果系统中的cache的淘汰算法可以选择的话,本控制位选择淘汰算法

0 :常规的 cache 淘汰算法,如随机淘汰

1 :预测性淘汰算法,如round-robin 淘汰算法

如果系统中cache的淘汰算法不可选择,写入该位时忽略。读取该位时,根据其淘汰算法是否可以比较简单地预测最坏情况返回0或者1

L4(bit[15])

对于ARM版本5及以上的版本,本控制位可以提供兼容以前的ARM版本的功能

0 :保持 ARMv5 以上版本的正常功能

1 :将 ARMv5 以上版本与以前版本处理器 兼容,不根据跳转地址的 bit[0] 进行 ARM 指令和 Thumb 状态切换: bit[0] 等于 0 表示 ARM 指令,等于 1 表示 Thumb 指令

Bits[31:16])

这些位保留将来使用,应为UNP/SBZP

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  

  

  

  

  

  

  

  

  

1.1.4 代码修改

  u-boot 中的代码不需要修改。

     /*
* flush v4 I/D caches
*/
mov r0, #
mcr p15, , r0, c7, c7, /* flush v3/v4 cache */
mcr p15, , r0, c8, c7, /* flush v4 TLB */ /*
* disable MMU stuff and caches
*/
mrc p15, , r0, c1, c0, /* 将CP15 的寄存器 C1 的值读到 R0中 */
bic r0, r0, #0x00002300 @ clear bits , : (--V- --RS)
bic r0, r0, #0x00000087 @ clear bits , : (B--- -CAM)
orr r0, r0, #0x00000002 @ set bit (A) Align
orr r0, r0, #0x00001000 @ set bit (I) I-Cache
mcr p15, , r0, c1, c0,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

 

buildroot构建项目(五)--- u-boot 2017.11 适配开发板修改 3 ---- 系统启动初始化之二的更多相关文章

  1. buildroot构建项目(六)--- u-boot 2017.11 适配开发板修改 4 ---- 系统启动初始化之三

    一.内存控制器 在关闭了MMU和caches 之后 就进入lowlevel_init 函数,对内存控制器进行初始化.lowlevel_init.S (board\samsung\mini2440) 1 ...

  2. buildroot构建项目(八)--- u-boot 2017.11 适配开发板修改 5 ---- 系统启动初始化之五

    执行完 board_init_f 后,跳回到 crt0.S中继续执行汇编语言 ldr r0, [r9, #GD_START_ADDR_SP] /* sp = gd->start_addr_sp, ...

  3. buildroot构建项目(七)--- u-boot 2017.11 适配开发板修改 4 ---- 系统启动初始化之四

    设置完寄存器控制器后,则跳出cpu_init_crit,进入_main 函数.即进入crt0.S (arch\arm\lib)  跟着代码流程慢慢走 一.crt0.S 1.1 第一步执行代码 /* 预 ...

  4. buildroot构建项目(四)--- u-boot 2017.11 适配开发板修改 2 ---- 系统启动初始化之一

    一.代码分析 上一节已经分析了链接文件,知道了首先代码是从 _start 开始,之后设置了中断向量表,然后从 start.s 开始运行. _start:vectors.S (arch\arm\lib) ...

  5. buildroot构建项目(三)--- u-boot 2017.11 适配开发板修改 1

    当前虽然编译成功了,但是对于我们自己的目标板并不太适用.还得做一系列得修改. 一.lds 文件分析 u-boot 中最重要得链接文件即是,u-boot.lds.我们可以查看我们编译出来得 u-boot ...

  6. buildroot构建项目(二)--- u-boot 2017.11 建立 2440 开发板

    一.准备工作 在建立之前,先需要将下载的u-boot 拷贝一份出来解压,在此工程下进行更改和创建.同时根据前面搜索到的 mini2440开发板所在的版本,下载一份u-boot 拷贝出 mini2440 ...

  7. buildroot构建项目(一)---buildroot介绍

    1.1 什么是buildroot Buildroot是Linux平台上一个构建嵌入式Linux系统的框架.整个Buildroot是由Makefile脚本和Kconfig配置文件构成的.你可以和编译Li ...

  8. 2017.11.17 C++系列---用malloc动态给c++二维数组的申请与释放操作

    方法一:利用二级指针申请一个二维数组. #include<stdio.h> #include<stdlib.h> int main() { int **a; //用二级指针动态 ...

  9. iTOP-IMX6UL 实战项目:ssh 服务器移植到 arm 开发板

    实验环境:迅为提供的Ubuntu12.04.2 以及虚拟机 编译器:arm-2009q3 编译器 开发板系统:QT系统   开发板使用手册中给Windows 系统安装了 ssh 客户端,给 Ubunt ...

随机推荐

  1. Cuba项目配置IDEA,如何dubug

    1.在cuba中编辑端口,如下图: 2.在IDEA中添加一个远程链接,添加为对应的端口号,然后运行debug即可 如果两个端口号不对应,就会报出以下的错误:unable to open debugge ...

  2. hihocoder部分题解

    hihocoder1609 数组分拆II [dp] 给定数组,问有多少种拆法,使得每一段不出现重复的数字,且要保证分组数最少.(1e5) 题解: O(n) d[i]表示1~i最小划分的段数, f[i] ...

  3. emwin之CHECKBOX控件的通知代码的响应规则

    @2018-08-28 [小记] 在 case WM_INIT_DIALOG: 中使用 CHECKBOX_SetState()函数改变了复选框状态,就会产生 WM_NOTIFICATION_VALUE ...

  4. SSM框架中的前后端分离

    认识前后端分离 在传统的web应用开发中,大多数的程序员会将浏览器作为前后端的分界线.将浏览器中为用户进行页面展示的部分称之为前端,而将运行在服务器,为前端提供业务逻辑和数据准备的所有代码统称为后端. ...

  5. time_t和difftime

    在C++中,下面这段代码可以获取一段时间差. time_t t1 = time(NULL); Sleep(); time_t t2 = time(NULL); cout << diffti ...

  6. 1093. Count PAT's

    The string APPAPT contains two PAT's as substrings. The first one is formed by the 2nd, the 4th, and ...

  7. react中实现点击跳转到新页面方法

    实现点击跳转到新页面,可以有两种形式,一个是本地页面打开,一个是本地页面不变跳转到新的页面. (一)页面点击本地页面打开新页面 引入ant的Button组件 <Button style={{ba ...

  8. git branch 分支管理

    在多人协作的情况下,master通常是稳定的分支.可以再建一些"develop","testing"等名称的分支.主管master的人做开发的话最好也建立自己的 ...

  9. HTML:<input type="text">文本框不可编辑的方式

    1.<input type="text" name="name" value="姓名" disabled /> 该方式显示的文本 ...

  10. 2018acm-icpc江苏邀请赛后记

    这场比赛可真难. 不得不说矿大的环境大大出乎了我的意料,无论是校园面积还是基础设施都很好,唯一美中不足的大概是吃了一顿晚饭每个菜都有辣,幸好饭票发的很多,一个人四张饭票,一张饭票可以换3根香蕉,于是我 ...