ARM Cortex-A学习(2):协处理器CP15详解
C0-C15,每组寄存器都包含多个寄存器。前面看到读写CP15寄存器有很多的参数,我们就可以通过提供不同的控制寄存器编号和操作码,来读取不同寄存器组下的不同寄存器。Functionc0c1c2c3Faultsc5/c6c7c8/c10c9L2 Controlc9c11Interruptsc12Process IDc13c15对于不同的Cortex-A核的不同ARM架构,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;
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)