系统控制协处理器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的编号
  • 这两条指令必须在特权模式下才能访问

参数

执行MRCMCR指令实际上就是组成这样一个32位的ARM指令集:

在这里插入图片描述

  • cond:条件字段,表示指令执行的条件。例如,EQ 表示等于。如果省略,则该指令总是执行。

  • opcode_1:操作码1,用于指定要执行的协处理器操作的具体类型。

  • L:1为MRC、0为MCR

  • CRnCRm: 控制寄存器编号,用于选择在协处理器中的控制寄存器

  • Rd: 目标寄存器,用于存储从协处理器读取的数据

  • opcode_2: 操作码2,与 CRm 一起用于指定在控制寄存器中执行的特定操作。

2 CP15的寄存器

2.1 简介

CP15共16组寄存器:C0-C15,每组寄存器都包含多个寄存器。前面看到读写CP15寄存器有很多的参数,我们就可以通过提供不同的控制寄存器编号和操作码,来读取不同寄存器组下的不同寄存器。这16个寄存器的大致功能如下:

FunctionCP15 Registers
System Configurationc0
System Controlc1
Translation Base Controlc2
Domain Access Controlc3
Faultsc5/c6
Cache Operationsc7
TLB Operationsc8/c10
Performance Monitorc9
L2 Controlc9
Pre-load Enginec11
Interruptsc12
Process IDc13
Memory Arraysc15

对于不同的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 implementationB4.6 CP15 registers for a PMSA implementationVMSA架构下,详细地配置如下:

在这里插入图片描述

下面就以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)

从最上面的表格我们可以看到c15IMPLEMENTATION DEFINED registers,也就是不同的芯片厂商可以自己定义这个寄存器的位。这里就以Cortex-A7内核为例,它的架构就是ARMv7,我们来看看Cortex-A7手册中对于CP15的定义:

在这里插入图片描述

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

在这里插入图片描述

它的字段组成如下:

在这里插入图片描述

  • 这些字段我们不必深究,这个是用来配置上电后的初始值的,我们只要知道这个寄存器的值会被Cortex-A7核赋值为GIC的基地址就行了

读GIC基地址到r0:

MRC p15,4,r0,c15,c3,0;
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐