buildroot构建项目(五)--- u-boot 2017.11 适配开发板修改 3 ---- 系统启动初始化之二
一、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寄存器为控制寄存器,详细定义如下:
- 操作指令
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 中的代码不需要修改。
1 /* 2 * flush v4 I/D caches 3 */ 4 mov r0, #0 5 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ 6 mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ 7 8 /* 9 * disable MMU stuff and caches 10 */ 11 mrc p15, 0, r0, c1, c0, 0 /* 将CP15 的寄存器 C1 的值读到 R0中 */ 12 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS) 13 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM) 14 orr r0, r0, #0x00000002 @ set bit 1 (A) Align 15 orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache 16 mcr p15, 0, r0, c1, c0, 0