系统控制协处理器CP15
的作用是提供对内核部分功能的控制。主要功能包括:
MMU
)的配置和管理读CP15寄存器
MRC
(Move to Register from Coprocessor
)指令用于将CP15中的寄存器读到通用寄存器中:
MRC{cond} p15, , , , ,
写CP15寄存器
MCR
(Move to Coprocessor from Register
)指令用于将通用寄存器的值写入CP15中的寄存器中:
MCR{cond} p15, , , , ,
p15
为协处理器cp15的编号参数
执行MRC
和MCR
指令实际上就是组成这样一个32位的ARM指令集:
cond
:条件字段,表示指令执行的条件。例如,EQ
表示等于。如果省略,则该指令总是执行。
opcode_1
:操作码1,用于指定要执行的协处理器操作的具体类型。
L
:1为MRC
、0为MCR
CRn
和CRm
: 控制寄存器编号,用于选择在协处理器中的控制寄存器
Rd
: 目标寄存器,用于存储从协处理器读取的数据
opcode_2
: 操作码2,与 CRm
一起用于指定在控制寄存器中执行的特定操作。
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架构来说,在3.3小节有CP15不同参数访问的寄存器表格:
我手上有一块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
为例,介绍一些常用的配置寄存器。
MDIR
寄存器的字段实际上就是系统架构的一些信息,它的组成如下:
B3.12.7 c0, Main ID Register (MIDR)
下面的汇编指令将MDIR
寄存器的值读到r0
寄存器中:
MRC p15, 0, r0, c0, c0, 0
MDIR
寄存器为只读的,不可调用MCR
写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
c12
寄存器集的寄存器如下:
这里我们学习一下VBAR
寄存器:
VBAR[31:5]
表示程序的向量表地址,比如芯片自带的BootROM中,如果需要使用U-Boot来引导启动Linux,就需要设置向量表地址为U-Boot程序的向量表地址。
Reset
异常,通过设置这个字段,就可以在上电时进入别的异常
读VBAR寄存器的值到r0
MRC p15,0,r0,c12,c0,0
写r0的值到VBAR寄存器:
ldr r0, =0X80010000
MCR p15,0,r0,c12,c0,0
从最上面的表格我们可以看到c15
为IMPLEMENTATION DEFINED registers
,也就是不同的芯片厂商可以自己定义这个寄存器的位。这里就以Cortex-A7内核为例,它的架构就是ARMv7,我们来看看Cortex-A7手册中对于CP15的定义:
我们这里就了解一下CBAR
寄存器,它的值为GIC
(通用中断控制器)的基地址:
它的字段组成如下:
GIC
的基地址就行了读GIC基地址到r0:
MRC p15,4,r0,c15,c3,0;