ARM Cortex-A学习(2):协处理器CP15详解
系统控制协处理器CP15的作用是提供对内核部分功能的控制。主要功能包括:
- 整个系统控制和配置
- 缓存配置和管理
- 内存管理单元(
MMU)的配置和管理 - 用于L2缓存的预加载引擎
- 系统性能监控
文章目录
1 读写CP15寄存器
读CP15寄存器
MRC(Move to Register from Coprocessor)指令用于将CP15中的寄存器读到通用寄存器中:
MRC{cond} p15, <opcode_1>, <rd>, <CRn>, <CRm>, <opcode_2>
写CP15寄存器
MCR(Move to Coprocessor from Register)指令用于将通用寄存器的值写入CP15中的寄存器中:
MCR{cond} p15, <opcode_1>, <rd>, <CRn>, <CRm>, <opcode_2>
p15为协处理器cp15的编号- 这两条指令必须在特权模式下才能访问
参数
执行MRC和MCR指令实际上就是组成这样一个32位的ARM指令集:

-
cond:条件字段,表示指令执行的条件。例如,EQ表示等于。如果省略,则该指令总是执行。 -
opcode_1:操作码1,用于指定要执行的协处理器操作的具体类型。 -
L:1为MRC、0为MCR -
CRn和CRm: 控制寄存器编号,用于选择在协处理器中的控制寄存器 -
Rd: 目标寄存器,用于存储从协处理器读取的数据 -
opcode_2: 操作码2,与CRm一起用于指定在控制寄存器中执行的特定操作。
2 CP15的寄存器
2.1 简介
CP15共16组寄存器:C0-C15,每组寄存器都包含多个寄存器。前面看到读写CP15寄存器有很多的参数,我们就可以通过提供不同的控制寄存器编号和操作码,来读取不同寄存器组下的不同寄存器。这16个寄存器的大致功能如下:
| Function | CP15 Registers |
|---|---|
| System Configuration | c0 |
| System Control | c1 |
| Translation Base Control | c2 |
| Domain Access Control | c3 |
| Faults | c5/c6 |
| Cache Operations | c7 |
| TLB Operations | c8/c10 |
| Performance Monitor | c9 |
| L2 Control | c9 |
| Pre-load Engine | c11 |
| Interrupts | c12 |
| Process ID | c13 |
| Memory Arrays | c15 |
对于不同的Cortex-A核的不同ARM架构,CP15所包括的寄存器都会有一些区别,所以具体请查阅相关的ARM版本参考手册。
- 这里我整理了ARM11、ARMv7和最新的ARMv8/v9的架构参考手册:下载地址
比如对于最老的ARM11架构来说,在3.3小节有CP15不同参数访问的寄存器表格:

2.2 ARMv7实例
我手上有一块I.MX6ULL的板子,它所用的架构为ARMv7,这里就以ARMv7为例举几个读写CP15寄存器的例子。
在ARMv7中,有两种内存系统架构:VMSA(Virtual Memory System Architecture)和PMSA(Physical Memory System Architecture),分别用于处理虚拟内存和物理内存的映射和管理。比如跑Linux的时候要用MMU,用的就是VMSA,如果跑裸机的话,用的就是PMSA。
那不同的架构,对应的CP15协处理器访问的参数都不同,分别对应手册中的B3.12 CP15 registers for a VMSA implementation和B4.6 CP15 registers for a PMSA implementation。VMSA架构下,详细地配置如下:

下面就以VMSA为例,介绍一些常用的配置寄存器。
2.2.1 读取C0的MDIR寄存器
MDIR寄存器的字段实际上就是系统架构的一些信息,它的组成如下:

- 具体字段含义参考
B3.12.7 c0, Main ID Register (MIDR)
下面的汇编指令将MDIR寄存器的值读到r0寄存器中:
MRC p15, 0, r0, c0, c0, 0
MDIR寄存器为只读的,不可调用MCR写
2.2.2 读/写c1的SCTLR寄存器
SCTLR就是上面的System Control Registers(系统控制寄存器),它与使能MMU、I-Cache和D-Cache等功能有关,所以很重要。组成如下:

比如bit0就是打开/禁用MMU的位,如果使用了Linux,一般是需要打开的。

- 其它字段含义参考:
B3.12.17 c1, System Control Register (SCTLR)
在前面那张总图中没有明确操作码2的值,我们可以参考B3.12.16 CP15 c1, System control registers章节:

所以SCTLR寄存器的操作码2为0。
读SCTLR寄存器的值到r0:
MRC p15,0,r0,c1,c0,0
写r0的值到SCTLR寄存器
MCR p15,0,r0,c1,c0,0
2.2.3 读/写c12的VBAR寄存器
c12寄存器集的寄存器如下:

这里我们学习一下VBAR寄存器:

VBAR[31:5]表示程序的向量表地址,比如芯片自带的BootROM中,如果需要使用U-Boot来引导启动Linux,就需要设置向量表地址为U-Boot程序的向量表地址。
- 低5位表示异常的偏移,默认0为
Reset异常,通过设置这个字段,就可以在上电时进入别的异常- 这也暗示着程序向量表的基地址需要32位对齐
读VBAR寄存器的值到r0
MRC p15,0,r0,c12,c0,0
写r0的值到VBAR寄存器:
ldr r0, =0X80010000
MCR p15,0,r0,c12,c0,0
2.2.4 读c15的CBAR寄存器(Cortex-A7)
从最上面的表格我们可以看到c15为IMPLEMENTATION DEFINED registers,也就是不同的芯片厂商可以自己定义这个寄存器的位。这里就以Cortex-A7内核为例,它的架构就是ARMv7,我们来看看Cortex-A7手册中对于CP15的定义:

我们这里就了解一下CBAR寄存器,它的值为GIC(通用中断控制器)的基地址:

它的字段组成如下:

- 这些字段我们不必深究,这个是用来配置上电后的初始值的,我们只要知道这个寄存器的值会被Cortex-A7核赋值为
GIC的基地址就行了
读GIC基地址到r0:
MRC p15,4,r0,c15,c3,0;
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!