fuzidage
专注嵌入式、linux驱动 、arm裸机研究

导航

 

1 GNU 汇编格式

label:instruction @ comment

label 即标号,表示地址位置,有些指令前面可能会有标号,这样就可以通过这个标号得到指令的地址,标号也可以用来表示数据地址。注意 label 后面的“:”,任何以“:”结尾的标识符都会被识别为一个标号。
instruction 即指令,也就是汇编指令或伪指令。
@符号,表示后面的是注释,就跟 C 语言里面的“/”和“/”一样,其实在 GNU 汇编文件中我们也可以使用“/*”和“*/”来注释。
comment 就是注释内容。

add:
MOVS R0, #0X12 @设置 R0=0X12

注意: ARM 中的指令、伪指令、伪操作、寄存器名等可以全部使用大写,也可以全部使用小写,但是不能大小写混用

1.1伪操作

1.1.1 .section

来定义一个段,汇编系统预定义了一些段名:

.text 表示代码段。
.data 初始化的数据段。
.bss 未初始化的数据段。
.rodata 只读数据段。

定义一个 testsetcion 段

.section .testsection

汇编程序的默认入口标号是_start,不过我们也可以在链接脚本中使用 ENTRY 来指明其它的入口点。

1.1.1 .global

.global _start
_start:
ldr r0, =0x12 @r0=0x12

.global 是伪操作,表示_start 是一个全局标号,类似 C 语言里面的全局变量一样,常见的伪操作有:

.byte 定义单字节数据,比如.byte 0x12。
.short 定义双字节数据,比如.short 0x1234。
.long 定义一个 4 字节数据,比如.long 0x12345678。
.equ 赋值语句,格式为:.equ 变量名,表达式,比如.equ num, 0x12,表示 num=0x12。
.align 数据字节对齐,比如:.align 4 表示 4 字节对齐。
.end 表示源文件结束。
.global 定义一个全局符号,格式为:.global symbol,比如:.global _start。

1.2 函数定义

函数名:
	函数体
	返回语句

GNU 汇编函数返回语句不是必须的,如下代码就是用汇编写的Cortex-A7 中断服务函数:

/* 未定义中断 */
Undefined_Handler:
	ldr r0, =Undefined_Handler
	bx r0
/* SVC 中断 */
SVC_Handler:
	ldr r0, =SVC_Handler
	bx r0
/* 预取终止中断 */
PrefAbort_Handler:
	ldr r0, =PrefAbort_Handler 
	bx r0

以函数 Undefined_Handler 为例我们来看一下汇编函数组成,“Undefined_Handler”就是函数名,“ldr r0, =Undefined_Handler”是函数体,“bx r0”是函数返回语句,“bx”指令是返回指令,函数返回语句不是必须的.

2 ARMv7汇编指令

2.1 数据移动指令

数据移动指令都是cpu内部寄存器之间的数据拷贝。

2.1.1 MOV

MOV R0,R1 @将寄存器 R1 中的数据传递给 R0,即 R0=R1
MOV R0, #0X12 @将立即数 0X12 传递给 R0 寄存器,即 R0=0X12

2.1.2 MRS

读取特殊寄存器的数据只能使用 MRS 指令:

MRS R0, CPSR @将 CPSR 里面的数据传递给 R0,即 R0=CPSR

2.1.3 MSR

和 MRS 刚好相反,通用寄存器写入到特殊寄存器

MSR CPSR, R0 @将 R0 中的数据复制到 CPSR 中,即 CPSR=R0

举个例子利用MRS MSR进行清bss (_bss_start, __bss_end定义在链接脚本):

.global _start
.global _bss_start
.global _bss_end

_bss_start:
	.word __bss_start
_bss_end:
	.word __bss_end

_start:
	//disable watchdog, disable icache dcache
	//init_clk
	//enter svc mode
	/*clear bss*/
	ldr r0, _bss_start
	ldr r1, _bss_end
	move r2, 0
clr_bss:
	stmia r0!, {r2} //复制一r2中的数据给r0, 并将指针r0增加4
	cmp r0, r1
	ble clr_bss /*if r0<r1, b clr_bss*/

2.1.4 CPS

特权模式下(除了用户模式,剩余的模式都是特权模式),可以通过CPS指令直接修改CPSR寄存器的M[4:0],让处理器进入不同的模式。
image

CPS #0x12 /*irq mode*/
CPS #0x13 /*svc mode*/

2.2 数据存取指令(访问存储器RAM)

2.2.1 LDR

数据加载指令,从指定地址读取到cpu寄存器。

LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, [R0] @读取地址 0X0209C004 中的数据到 R1 寄存器中

2.2.2 STR

数据存放指令,从cpu寄存器写入指定地址。

LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
LDR R1, =0X20000002 @R1 保存要写入到寄存器的值,即 R1=0X20000002
STR R1, [R0] @将 R1 中的值写入到 R0 中所保存的地址中

LDR 和 STR 都是按照4 byte进行读取和写入的,也就是操作的 32 位数据,如果要按照字节、半字进行操作的话可以在指令“LDR”后面加上 B 或 H,比如按字节操作的指令就是 LDRB 和STRB,按半字(16位)操作的指令就是 LDRH 和 STRH。

2.2.3 多寄存器加载存储指令LDMIA,STMIA等

1.LDMIA指令、LDMIB指令、LDMDB指令、LDMDA指令
LDM是LDR指令的增强型 , 将连续的数据加载到多组寄存器。
DB (Decrement Before)栈指针先减小再操作、DA(Decrement After)栈指针先操作再减小。
IB(Increment Before)栈指针先增加再操作、IA(Increment After)栈指针先操作再增加。

LDMIA指令,IA表示每次传送后地址加4
LDMIB指令,IB表示每次传送前地址加4
LDMDA指令,DA表示每次传送后地址减4
LDMDB指令,DB表示每次传送前地址减4

LDMIA R14,{R0-R3,R12} /*从R14寄存器指向的地址取出5个32位数据分别存进到R0-R4以及R12*/

//等效于
//R0=*R14
//R1=*(R14+4)
//R2=*(R14+8)
//R3=*(R14+12)
//R12=*(R14+16)

LDMIA R1!,{R4-R11} /*从R1指向的地址取8个32位数据存入R4-R11, 每取一次,让R1指针加4,因此最后R1指针加了32*/

2.STMIA指令、STMIB指令、STMDB指令、STMDA指令
同理,STM是STR指令的增强型 , 将多组寄存器数据保存进连续地址空间。

STMIA R13!,{R0-R1} /*将R0,R1寄存器中的数据存入R13指向的栈空间, r13指向的地址存入R0数据,再地址+4后存入R1的数据*/

2.3 入栈出栈指令

函调调用过程中离不开现场的保护和恢复。保存 R0~R15 寄存器的操作就叫做现场保护,恢复 R0~R15 寄存器的操作就叫做恢复现场。

2.3.1 PUSH

比如要将 R0~R3 和 R12 这 5 个寄存器压栈,当前的 SP (stack pointer)指针指向 0X80000000,我们知道栈空间的地址是向下增长的,堆空间地址向上增长。

PUSH {R0~R3, R12} @将 R0~R3 和 R12 压栈

那么压栈完成以后的堆栈如下:入栈保护现场完这5个寄存器后,SP指向0X7FFFFFEC(每压栈一个寄存器,SP地址减4)
image
再次保存LR寄存器,进行压栈:
image

PUSH {LR} @将 LR 进行压栈

2.3.2 POP

POP {LR} @先恢复 LR
POP {R0~R3,R12} @在恢复 R0~R3,R12

可以看出入栈出栈本质都是对SP指针进行加减,入栈减,出栈加,入栈把寄存器依次保存进SP指向的地址去,出栈从SP地址依次取出数据。

2.3.3 STMFD和LDMFD

入栈出栈的另外一种写法是“STMFD SP!”和“LDMFD SP!”。

STMFD SP!,{R0~R3, R12} @R0~R3,R12 入栈
STMFD SP!,{LR} @LR 入栈
bl xxx
LDMFD SP!, {LR} @先恢复 LR
LDMFD SP!, {R0~R3, R12} @再恢复 R0~R3, R12

STMFD 可以分为两部分:STM 和 FD,同理,LDMFD 也可以分为 LDM 和 FD。前面我们讲了 LDR 和 STR,这两个是数据加载和存储指令,但是每次只能读写存储器中的一个数据。STM 和 LDM 就是多存储和多加载,可以连续的读写存储器中的多个连续数据。
FD 是 Full Descending 的缩写,即满递减的意思。根据 ATPCS 规则,ARM 使用的 FD 类型的堆栈,SP 指向最后一个入栈的数值,堆栈是由高地址向下增长的,也就是前面说的向下增长的堆栈,因此最常用的指令就是 STMFD 和 LDMFD。STM 和 LDM 的指令寄存器列表中编号小的对应低地址,编号高的对应高地址.

2.4 跳转指令

2.4.1 B 指令

B 指令会将 PC 寄存器的值设置为跳转目标地址,如果要调用的函数不会再返回到原来的执行处,那就可以用 B 指令.

_start:
ldr sp,=0X80200000 @设置栈指针
b main @跳转到 main 函数

在汇编中初始化 C 运行环境,然后跳转到 C 文件的 main 函数中运行,上述代码只是初始化了 SP 指针,有些处理器还需要做其他的初始化,比如初始化 DDR 等等.

2.4.2 BL 指令

有返回的跳转,跳转之前会在寄存器 LR(R14)中保存当前 PC 寄存器值,所以可以通过将 LR 寄存器中的值重新加载到 PC 中来继续从跳转之前的代码处运行,这是子程序调用一个基本但常用的手段。
比如 Cortex-A 处理器的 irq 中断服务函数都是汇编写的,主要用汇编来实现现场的保护和恢复、获取中断号等。但是具体的中断处理过程都是 C 函数,所以就会存在汇编中调用 C 函数的问题。而且当 C 语言版本的中断处理函数执行完成以后是需要返回到irq 汇编中断服务函数,因为还要处理其他的工作,一般是恢复现场。

push {r0, r1} @保存 r0,r1
cps #0x13 @进入 SVC 模式,允许其他中断再次进去

bl system_irqhandler @加载 C 语言中断处理函数到 r2 寄存器中

cps #0x12 @进入 IRQ 模式
pop {r0, r1} 
str r0, [r1, #0X10] @中断执行完成,写 EOIR

跳转指令总结:
有多种跳转操作,比如:
①、直接使用跳转指令 B、BL、BX 等。
②、直接向 PC 寄存器里面写入数据。
image

2.5 算数运算指令

加减乘除,常用的运算指令用法:
image

2.6 逻辑运算指令

与或非指令用法:
image
来看一个例子利用arm汇编进行初始化C语言环境。让arm进入svc模式,才能访问特殊寄存器如cpsr, spsr, sp指针。

.global _start
_start:
	/* 进入SVC模式 */
	mrs r0, cpsr
	bic r0, r0, #0x1f  /* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 */
	orr r0, r0, #0x13  /* r0或上0x13,表示使用SVC模式 */
	msr cpsr, r0 /* 将r0 的数据写入到cpsr_c中 */

	ldr sp, =0X80200000 /* 设置栈指针 */
	b main /* 跳转到main函数 */

2.7 内存屏障指令

2.7.1 Data Memory Barrier(DMB):数据内存屏障

DMB指令确保在DMB之前的所有显式数据内存传输指令都已经在内存中读取或写入完成,同时确保任何后续的数据内存传输指令都将在DMB执行之后开始执行,否则有些数据传输指令可能会提前执行。保证了两个内存访问能按正确的顺序执行。
应用场景:
(1)DMA
在使用DMA控制器时,需要在CPU内存访问和DMA操作之间插入DMB屏障,以确保CPU当前的内存读写操作在DMA开始之前完成。

(2)多核系统中的信号量
在多核系统中,使用信号量进行核间同步。需要使用DMB来强制指定内存执行顺序,以避免潜在的竞态条件或数据不一致性。当一个核要访问共享资源之前,它会先检查信号量的状态。如果信号量已经被另一个核获取,当前核就必须等待,直到信号量状态变为可用。这个等待过程需要保证在一个核释放信号量之后,其他核能够立即看到信号量状态的变化,而不是因为处理器优化或缓存导致的无效读取而产生错误。

2.7.2 Data Synchronization Barrier(DSB):数据同步屏障

在多线程编程中,两个线程同时对共享的内存进行读写操作,由于读/写操作的重排序,就会导致数据的不一致, DSB指令时,它确保在DSB之前的所有显式数据内存传输指令都已经在内存中读取或写入完成,同时确保任何后续的指令都将在DSB执行之后开始执行。
应用场景:
例如启用或禁用特定的中断、配置时钟、设置系统控制位等。为了确保对SCS的修改在下一条指令执行之前生效,需要使用DSB指令进行数据同步。一些特殊的指令如SVC(Supervisor Call,特权级调用)、WFI(Wait For Interrupt,等待中断)、WFE(Wait For Event,等待事件)等操作,涉及到特权级的转换或者等待系统事件发生,需要使用DSB指令。

2.7.3 Instruction Synchronization Barrier(ISB):指令同步屏障

插入ISB指令,处理器会将流水线中的指令全部刷新,从而确保之前的指令不会影响后续指令的执行,并且后续指令将从正确的上下文开始重新获取。
应用场景:
在进行异常进入之前,处理器会执行ISB操作。这样做的目的是刷新指令流水线,确保异常处理程序的指令是从正确的地址开始执行,避免异常之前的指令对异常处理程序造成干扰。
在进行异常返回之前,处理器同样会执行ISB操作。这样做的目的是刷新指令流水线,确保返回时从正确的地址重新获取指令,避免异常处理程序的指令对正常任务造成干扰。

3 arm-v7 cpu运行模式

以前的 ARM 处理器有 7 中运行模型:User、FIQ、IRQ、Supervisor(SVC)、Abort、Undef和 System,其中 User 是非特权模式,其余 6 中都是特权模式。

到了Cortex-A7 处理器有 9 种处理模式:

模式 描述
User(USR) 用户模式,非特权模式,大部分程序运行的时候就处于此模式。
FIQ 快速中断模式,进入 FIQ 中断异常
IRQ 一般中断模式。
Supervisor(SVC) 超级管理员模式,特权模式,供操作系统使用。
Monitor(MON) 监视模式?这个模式用于安全扩展模式。
Abort(ABT) 数据访问终止模式,用于虚拟存储以及存储保护。
Hyp(HYP) Hyp(HYP) 超级监视模式?用于虚拟化扩展。
Undef(UND) Undef(UND) 未定义指令终止模式。
System(SYS) System(SYS) 系统模式,用于运行特权级的操作系统任务

九种模式所对应的寄存器:
image
arm920t cpu模式

4 arm-v7 cpu通用和特殊寄存器

ARM 架构提供了 16 个 32 位的通用寄存器(R0~R15)供软件使用,前 15 个(R0~R14)可以用作通用的数据存储,R15 是程序计数器 PC,用来保存将要执行的指令。ARM 还提供了一个当前程序状态寄存器 CPSR 和一个备份程序状态寄存器 SPSR,SPSR 寄存器就是 CPSR 寄存器的备份。
image

4.1 通用寄存器

R0~R15 就是通用寄存器,通用寄存器可以分为以下三类:
①、未备份寄存器,即 R0~R7。
②、备份寄存器,即 R8~R14。
③、程序计数器 PC,即 R15。

4.1.2 未备份寄存器R0-R7

未备份寄存器指的是 R0~R7 这 8 个寄存器,因为在所有的处理器模式下这 8 个寄存器都是同一个物理寄存器,在不同的模式下,这 8 个寄存器中的数据就会被破坏.

4.1.3 备份寄存器

4.1.3.1 R8~R12

R8~R12 这 5 个寄存器有2种物理寄存器.在快速中断模式下(FIQ)它们对应着 Rx_irq(x=8~12)物理寄存器,其他模式下对应着 Rx(8~12)物理寄存器. FIQ 模式下的 R8~R12 是独立的,因此中断处理程序可以不用执行保存和恢复中断现场的指令,从而加速中断的执行过程。

4.1.3.2 R13 (SP)

R13 一共有 8 个物理寄存器,其中一个是用户模式(User)和系统模式(Sys)共用的,剩下的 7 个分别对应 7 种不同的模式。R13 也叫做 SP,用来做为栈指针。基本上每种模式
都有一个自己的 R13 物理寄存器,应用程序会初始化 R13,使其指向该模式专用的栈地址,这就是常说的初始化 SP 指针.

4.1.3.2 R14 (LR)

R14 一共有 7 个物理寄存器,其中一个是用户模式(User)、系统模式(Sys)和超级监视模式(Hyp)所共有的,剩下的 6 个分别对应 6 种不同的模式.
LR被叫做链接寄存器:
①用来存放子函数的返回地址。
在子函数中,将 R14(LR)中的值赋给 R15(PC)即可完成子函数返回,比如在子程序中可以使用如下代码:

MOV PC, LR

②当异常发生以后,该异常模式对应的 R14寄存器被设置成该异常模式将要返回的地址.

subs pc, lr, #4				/* 将lr-4赋给pc */

比如下面代码示例:

0X2000 MOV R1, R0 ;执行
0X2004 MOV R2, R3 ;译指
0X2008 MOV R4, R5 ;取值 PC

当前正在执行 0X2000地址处的指令“MOV R1, R0”,但是 PC 里面已经保存了 0X2008 地址处的指令“MOV R4, R5”。假设此时发生了中断,中断发生的时候保存在 lr 中的是 pc 的值,也就是地址 0X2008。

4.1.3.2 R15 (PC)

R15 保存着当前执行的指令地址值加 8 个字节,这是因为 ARM的流水线机制导致的。ARM 处理器 3 级流水线:取指->译码->执行,这三级流水线循环执行,比如当前正在执行第一条指令的同时也对第二条指令进行译码,第三条指令也同时被取出存放在 R15(PC)中.
对于arm32位处理器:

R15 (PC)值 = 当前执行的程序位置 + 8 个字节

4.2 特殊寄存器

4.2.1 CPSR

当前程序状态寄存器(current program status register),所有模式共用一个 CPSR 物理寄存器,因此 CPSR 可以在任何模式下被访问。
image
N(bit31):当两个补码表示的 有符号整数运算的时候,N=1 表示运算对的结果为负数,N=0表示结果为正数。
Z(bit30):Z=1 表示运算结果为零,Z=0 表示运算结果不为零,对于 CMP 指令,Z=1 表示进行比较的两个数大小相等。
C(bit29):在加法指令中,当结果产生了进位,则 C=1,表示无符号数运算发生上溢,其它情况下 C=0。在减法指令中,当运算中发生借位,则 C=0,表示无符号数运算发生下溢,其它情况下 C=1。对于包含移位操作的非加/减法运算指令,C 中包含最后一次溢出的位的数值,对于其它非加/减运算指令,C 位的值通常不受影响。
V(bit28):对于加/减法运算指令,当操作数和运算结果表示为二进制的补码表示的带符号数时,V=1 表示符号位溢出,通常其他位不影响 V 位。
Q(bit27):仅 ARM v5TE_J 架构支持,表示饱和状态,Q=1 表示累积饱和,Q=0 表示累积不饱和。
IT1:0:和 IT7:2一起组成 IT[7:0],作为 IF-THEN 指令执行状态。
J(bit24):仅 ARM_v5TE-J 架构支持,J=1 表示处于 Jazelle 状态,此位通常和 T(bit5)位一起表示当前所使用的指令集:

J T 描述
0 0 ARM
0 1 Thumb
1 1 ThumbEE

GE3:0:SIMD 指令有效,大于或等于。
IT7:2:参考 IT[1:0]。
E(bit9):大小端控制位,E=1 表示大端模式,E=0 表示小端模式。
A(bit8):禁止异步中断位,A=1 表示禁止异步中断。
I(bit7):I=1 禁止 IRQ,I=0 使能 IRQ。
F(bit6):F=1 禁止 FIQ,F=0 使能 FIQ。
T(bit5):控制指令执行状态,表明本指令是 ARM 指令还是 Thumb 指令,通常和 J(bit24)一起表明指令类型,参考 J(bit24)位。
M[4:0]:处理器模式控制位
cpsr最常用就是来控制处理器模式

M[4:0] 处理器模式
10000 User 模式
10001 FIQ 模式
10010 IRQ 模式
10011 Supervisor(SVC)模式
10110 Monitor(MON)模式
10111 Abort(ABT)模式
11010 Hyp(HYP)模式
11011 Undef(UND)模式
11111 System(SYS)模式
	/* 进入SVC模式 */
	mrs r0, cpsr
	bic r0, r0, #0x1f 	/* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 	*/
	orr r0, r0, #0x13 	/* r0或上0x13,表示使用SVC模式					*/
	msr cpsr, r0		/* 将r0 的数据写入到cpsr_c中 					*/
	ldr sp, =0X80200000	/* 设置SVC模式下的栈首地址为0X80200000,大小为2MB */

4.2.2 SPSR

除了 User 和 Sys 这两个模式以外,其他 7 个模式每个都配备了一个专用的物理状态寄存器,叫做 SPSR(备份程序状态寄存器),当特定的异常中断发生时,SPSR 寄存器用来保存当前程序状态寄存器(CPSR)的值,当异常退出以后可以用 SPSR 中保存的值来恢复 CPSR。User 和 Sys 这两个模式不是异常模式,所以并没有配备 SPSR,因此不能在 User 和Sys 模式下访问 SPSR。

5 CP15协处理器

CP15 协处理器一般用于存储系统管理,但是在中断中也会使用到,比如进入reset复位异常向量时,需要利用协处理器命令进行ICache DCache的开关。CP15 协处理器一共有16 个 32 位寄存器(C0-C15),MRC和MCR用来访问CP15协处理器。

MRC: 将 CP15 协处理器中的寄存器数据读到 ARM 寄存器中。
MCR: 将 ARM 寄存器的数据写入到 CP15 协处理器寄存器中。
格式如下:

MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>

cond:指令执行的条件码,如果忽略的话就表示无条件执行。
opc1:协处理器要执行的操作码。
Rt:ARM 源寄存器,要写入到 CP15 寄存器的数据就保存在此寄存器中。
CRn:CP15 协处理器的目标寄存器。
CRm:协处理器中附加的目标寄存器或者源操作数寄存器,如果不需要附加信息就将CRm 设置为 C0,否则结果不可预测。
opc2:可选的协处理器特定操作码,当不需要的时候要设置为 0

例如:

MRC p15, 0, r0, c0, c0, 0 //将 CP15 中 C0 寄存器的值读取到 R0 寄存器

5.1 c0寄存器(MIDR)

使用 MRC 或者 MCR 指令访问 c0-c15 寄存器的时候,指令中的 CRn、opc1、CRm 和 opc2 通过不同的搭配,其得到的寄存器含义不同:
image
当CRn=c0,opc1=0,CRm=c0,opc2=0 的时候就表示此时的 c0 就是 MIDR 寄存器,也就是主 ID 寄存器,这个也是 c0 的基本作用。来看下c0作为MDIR寄存器时的含义:
image
bit31:24:厂商编号,0X41,ARM。
bit23:20:内核架构的主版本号,ARM 内核版本一般使用 rnpn 来表示,比如 r0p1,其中 r0
后面的 0 就是内核架构主版本号。
bit19:16:架构代码,0XF,ARMv7 架构。
bit15:4:内核版本号,0XC07,Cortex-A7 MPCore 内核。
bit3:0:内核架构的次版本号,rnpn 中的 pn,比如 r0p1 中 p1 后面的 1 就是次版本号。

5.2 c1寄存器(SCTLR)

image
CRn=c1,opc1=0,CRm=c0,opc2=0 的时候就表示此时的 c1 就是 SCTLR 寄存器,也就是系统控制寄存器,这个是 c1 的基本作用。
SCTLR 寄存器主要是完成控制功能的,比如使能或者禁止 MMU、I/D Cache 等。 SCTLR 寄存器展开如下:
image

bit13:V , 中断向量表基地址选择位,为 0 的话中断向量表基地址为 0X00000000,软件可以使用 VBAR 来重映射此基地址,也就是中断向量表重定位。为 1 的话中断向量表基地址为0XFFFF0000,此基地址不能被重映射。
bit12:I,I Cache 使能位,为 0 的话关闭 I Cache,为 1 的话使能 I Cache。
bit11:Z,分支预测使能位,如果开启 MMU 的话,此位也会使能。
bit10:SW,SWP 和 SWPB 使能位,当为 0 的话关闭 SWP 和 SWPB 指令,当为 1 的时候就使能 SWP 和 SWPB 指令。
bit9:3:未使用,保留。
bit2:C,D Cache 和缓存一致性使能位,为 0 的时候禁止 D Cache 和缓存一致性,为 1 时使能。
bit1:A,内存对齐检查使能位,为 0 的时候关闭内存对齐检查,为 1 的时候使能内存对齐检查。
bit0:M,MMU 使能位,为 0 的时候禁止 MMU,为 1 的时候使能 MMU。
举个读写SCTLR的例子:

MRC p15, 0, <Rt>, c1, c0, 0 ;读取 SCTLR 寄存器,数据保存到 Rt 中。

MCR p15, 0, <Rt>, c1, c0, 0 ;将 Rt 中的数据写到 SCTLR(c1)寄存器中。

再来一个关闭MMU,ICache,DCache的例子:

mrc     p15, 0, r0, c1, c0, 0     /* 读取CP15的C1寄存器到R0中       		        	*/
bic     r0,  r0, #(0x1 << 12)     /* 清除C1寄存器的bit12位(I位),关闭I Cache            	*/
bic     r0,  r0, #(0x1 <<  2)     /* 清除C1寄存器的bit2(C位),关闭D Cache    				*/
bic     r0,  r0, #0x2             /* 清除C1寄存器的bit1(A位),关闭对齐						*/
bic     r0,  r0, #(0x1 << 11)     /* 清除C1寄存器的bit11(Z位),关闭分支预测					*/
bic     r0,  r0, #0x1             /* 清除C1寄存器的bit0(M位),关闭MMU				       	*/
mcr     p15, 0, r0, c1, c0, 0     /* 将r0寄存器中的值写入到CP15的C1寄存器中	 				*/

5.3 c12寄存器(VBAR)

image
CRn=c12,opc1=0,CRm=c0,opc2=0 的时候就表示此时 c12 为 VBAR 寄存器,也就是中断向量表基地址寄存器

比如代码链接到DDR的某个位置作为起始地址,起始地址为0X87800000,而中断向量表肯定要放到最前面,也就是 0X87800000 这个地址处。所以就需要设置 VBAR 为 0X87800000,设置命令如下:

dsb
isb
ldr r0, =0x87800000 ; r0=0x87800000
MCR p15, 0, r0, c12, c0, 0 ;将 r0 里面的数据写入到 c12 中,即 c12=0X87800000
dsb
isb

5.3 c15寄存器(CBAR)

image
image

CBAR寄存器中保存了GIC(Generic Interrupt Controller)的基地址。GIC基地址偏移0x1000是分发器 block, 偏移0x2000是CPU 接口端 block。

MRC p15, 4, r1, c15, c0, 0 ; 获取 GIC 基础地址,基地址保存在 r1 中

6 参考链接

armv7都是32位处理器,典型的有CorTex-A A7 A8 A9 A15 A17。armv8采用64位处理器,典型的比如手机处理器,有Cortex A53 A76 A77都是64位架构。
https://developer.arm.com/documentation/ddi0406/cd?lang=en
image

https://developer.arm.com/documentation/den0013/d/?lang=en
image

https://developer.arm.com/documentation/ddi0464/latest/
image

7 附件1:armv7裸机启动汇编示例:

点击查看代码
.global _start  				/* 全局标号 */

_start:
	ldr pc, =Reset_Handler		/* 复位中断 					*/	
	ldr pc, =Undefined_Handler	/* 未定义中断 					*/
	ldr pc, =SVC_Handler		/* SVC(Supervisor)中断 		*/
	ldr pc, =PrefAbort_Handler	/* 预取终止中断 					*/
	ldr pc, =DataAbort_Handler	/* 数据终止中断 					*/
	ldr	pc, =NotUsed_Handler	/* 未使用中断					*/
	ldr pc, =IRQ_Handler		/* IRQ中断 					*/
	ldr pc, =FIQ_Handler		/* FIQ(快速中断)未定义中断 			*/

/* 复位中断 */	
Reset_Handler:

	cpsid i						/* 关闭全局中断 */

	/* 关闭I,DCache和MMU 
	 * 采取读-改-写的方式。
	 */
	mrc     p15, 0, r0, c1, c0, 0     /* 读取CP15的C1寄存器到R0中       		        	*/
    bic     r0,  r0, #(0x1 << 12)     /* 清除C1寄存器的bit12位(I位),关闭I Cache            	*/
    bic     r0,  r0, #(0x1 <<  2)     /* 清除C1寄存器的bit2(C位),关闭D Cache    				*/
    bic     r0,  r0, #0x2             /* 清除C1寄存器的bit1(A位),关闭对齐						*/
    bic     r0,  r0, #(0x1 << 11)     /* 清除C1寄存器的bit11(Z位),关闭分支预测					*/
    bic     r0,  r0, #0x1             /* 清除C1寄存器的bit0(M位),关闭MMU				       	*/
    mcr     p15, 0, r0, c1, c0, 0     /* 将r0寄存器中的值写入到CP15的C1寄存器中	 				*/

	
#if 0
	/* 汇编版本设置中断向量表偏移 */
	ldr r0, =0X87800000

	dsb
	isb
	mcr p15, 0, r0, c12, c0, 0
	dsb
	isb
#endif
    
	/* 设置各个模式下的栈指针,
	 * 注意:IMX6UL的堆栈是向下增长的!
	 * 堆栈指针地址一定要是4字节地址对齐的!!!
	 * DDR范围:0X80000000~0X9FFFFFFF
	 */
	/* 进入IRQ模式 */
	mrs r0, cpsr
	bic r0, r0, #0x1f 	/* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 	*/
	orr r0, r0, #0x12 	/* r0或上0x13,表示使用IRQ模式					*/
	msr cpsr, r0		/* 将r0 的数据写入到cpsr_c中 					*/
	ldr sp, =0x80600000	/* 设置IRQ模式下的栈首地址为0X80600000,大小为2MB */

	/* 进入SYS模式 */
	mrs r0, cpsr
	bic r0, r0, #0x1f 	/* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 	*/
	orr r0, r0, #0x1f 	/* r0或上0x13,表示使用SYS模式					*/
	msr cpsr, r0		/* 将r0 的数据写入到cpsr_c中 					*/
	ldr sp, =0x80400000	/* 设置SYS模式下的栈首地址为0X80400000,大小为2MB */

	/* 进入SVC模式 */
	mrs r0, cpsr
	bic r0, r0, #0x1f 	/* 将r0寄存器中的低5位清零,也就是cpsr的M0~M4 	*/
	orr r0, r0, #0x13 	/* r0或上0x13,表示使用SVC模式					*/
	msr cpsr, r0		/* 将r0 的数据写入到cpsr_c中 					*/
	ldr sp, =0X80200000	/* 设置SVC模式下的栈首地址为0X80200000,大小为2MB */

	cpsie i				/* 打开全局中断 */
#if 0
	/* 使能IRQ中断 */
	mrs r0, cpsr		/* 读取cpsr寄存器值到r0中 			*/
	bic r0, r0, #0x80	/* 将r0寄存器中bit7清零,也就是CPSR中的I位清零,表示允许IRQ中断 */
	msr cpsr, r0		/* 将r0重新写入到cpsr中 			*/
#endif

	b main				/* 跳转到main函数 			 	*/

/* 未定义中断 */
Undefined_Handler:
	ldr r0, =Undefined_Handler
	bx r0

/* SVC中断 */
SVC_Handler:
	ldr r0, =SVC_Handler
	bx r0

/* 预取终止中断 */
PrefAbort_Handler:
	ldr r0, =PrefAbort_Handler	
	bx r0

/* 数据终止中断 */
DataAbort_Handler:
	ldr r0, =DataAbort_Handler
	bx r0

/* 未使用的中断 */
NotUsed_Handler:

	ldr r0, =NotUsed_Handler
	bx r0

IRQ_Handler:
	push {lr}					/* 保存lr地址 */
	push {r0-r3, r12}			/* 保存r0-r3,r12寄存器 */

	mrs r0, spsr				/* 读取spsr寄存器 */
	push {r0}					/* 保存spsr寄存器 */

	mrc p15, 4, r1, c15, c0, 0 /* 从CP15的C0寄存器内的值到R1寄存器中
								* 参考文档ARM Cortex-A(armV7)编程手册V4.0.pdf P49
								* Cortex-A7 Technical ReferenceManua.pdf P68 P138
								*/							
	add r1, r1, #0X2000			/* GIC基地址加0X2000,也就是GIC的CPU接口端基地址 */
	ldr r0, [r1, #0XC]			/* GIC的CPU接口端基地址加0X0C就是GICC_IAR寄存器,
								 * GICC_IAR寄存器保存这当前发生中断的中断号,我们要根据
								 * 这个中断号来绝对调用哪个中断服务函数
								 */
	push {r0, r1}				/* 保存r0,r1 */
	
	cps #0x13					/* 进入SVC模式,允许其他中断再次进去 */
	
	push {lr}					/* 保存SVC模式的lr寄存器 */
	ldr r2, =system_irqhandler	/* 加载C语言中断处理函数到r2寄存器中*/
	blx r2						/* 运行C语言中断处理函数,带有一个参数,保存在R0寄存器中 */

	pop {lr}					/* 执行完C语言中断服务函数,lr出栈 */
	cps #0x12					/* 进入IRQ模式 */
	pop {r0, r1}				
	str r0, [r1, #0X10]			/* 中断执行完成,写EOIR */

	pop {r0}						
	msr spsr_cxsf, r0			/* 恢复spsr */

	pop {r0-r3, r12}			/* r0-r3,r12出栈 */
	pop {lr}					/* lr出栈 */
	subs pc, lr, #4				/* 将lr-4赋给pc */
	
	

/* FIQ中断 */
FIQ_Handler:

	ldr r0, =FIQ_Handler	
	bx r0

8 附件2:GIC指令和寄存器定义(内联汇编方式)

点击查看代码
#ifndef __CORTEX_CA7_H
#define __CORTEX_CA7_H
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 core_ca7.h
作者	   : 左忠凯
版本	   : V1.0
描述	   : Cortex-A7内核通用文件。
其他	   : 本文件主要实现了对GIC操作函数
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/1/4 左忠凯创建
***************************************************************/
#include <stdint.h>
#include <string.h>


#define FORCEDINLINE  __attribute__((always_inline))
#define __ASM            __asm                         	/* GNU C语言内嵌汇编关键字 */ 
#define __INLINE         inline                      	/* GNU内联关键字 */             
#define __STATIC_INLINE  static inline					


#define     __IM     volatile const      /* 只读 */
#define     __OM     volatile            /* 只写 */
#define     __IOM    volatile            /* 读写 */
#define __STRINGIFY(x) #x

/* C语言实现MCR指令 */
#define __MCR(coproc, opcode_1, src, CRn, CRm, opcode_2)                          \
    __ASM volatile ("MCR " __STRINGIFY(p##coproc) ", " __STRINGIFY(opcode_1) ", " \
                    "%0, " __STRINGIFY(c##CRn) ", " __STRINGIFY(c##CRm) ", "      \
                    __STRINGIFY(opcode_2)                                         \
                    : : "r" (src) )

/* C语言实现MRC指令 */                    
#define __MRC(coproc, opcode_1, CRn, CRm, opcode_2)                               \
  ({                                                                              \
    uint32_t __dst;                                                               \
    __ASM volatile ("MRC " __STRINGIFY(p##coproc) ", " __STRINGIFY(opcode_1) ", " \
                    "%0, " __STRINGIFY(c##CRn) ", " __STRINGIFY(c##CRm) ", "      \
                    __STRINGIFY(opcode_2)                                         \
                    : "=r" (__dst) );                                             \
    __dst;                                                                        \
  })

/* 其他一些C语言内嵌汇编 */  
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_APSR(uint32_t apsr)
{
  __ASM volatile ("MSR apsr, %0" : : "r" (apsr) : "cc");
}

__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_CPSR(void)
{
  uint32_t result;

  __ASM volatile ("MRS %0, cpsr" : "=r" (result) );
  return(result);
}

__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_CPSR(uint32_t cpsr)
{
  __ASM volatile ("MSR cpsr, %0" : : "r" (cpsr) : "cc");
}

__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FPEXC(void)
{
  uint32_t result;

  __ASM volatile ("VMRS %0, fpexc" : "=r" (result) );
  return result;
}

__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FPEXC(uint32_t fpexc)
{
  __ASM volatile ("VMSR fpexc, %0" : : "r" (fpexc));
}


/*******************************************************************************
 *        		一些内核寄存器定义和抽象
  定义如下几个内核寄存器:
  - CPSR
  - CP15
 ******************************************************************************/

/* CPSR寄存器 
 * 参考资料:ARM Cortex-A(armV7)编程手册V4.0.pdf P46
 */
typedef union
{
  struct
  {
    uint32_t M:5;                        /*!< bit:  0.. 4  Mode field */
    uint32_t T:1;                        /*!< bit:      5  Thumb execution state bit */
    uint32_t F:1;                        /*!< bit:      6  FIQ mask bit */
    uint32_t I:1;                        /*!< bit:      7  IRQ mask bit */
    uint32_t A:1;                        /*!< bit:      8  Asynchronous abort mask bit */
    uint32_t E:1;                        /*!< bit:      9  Endianness execution state bit */
    uint32_t IT1:6;                      /*!< bit: 10..15  If-Then execution state bits 2-7 */
    uint32_t GE:4;                       /*!< bit: 16..19  Greater than or Equal flags */
    uint32_t _reserved0:4;               /*!< bit: 20..23  Reserved */
    uint32_t J:1;                        /*!< bit:     24  Jazelle bit */
    uint32_t IT0:2;                      /*!< bit: 25..26  If-Then execution state bits 0-1 */
    uint32_t Q:1;                        /*!< bit:     27  Saturation condition flag */
    uint32_t V:1;                        /*!< bit:     28  Overflow condition code flag */
    uint32_t C:1;                        /*!< bit:     29  Carry condition code flag */
    uint32_t Z:1;                        /*!< bit:     30  Zero condition code flag */
    uint32_t N:1;                        /*!< bit:     31  Negative condition code flag */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} CPSR_Type;


/* CP15的SCTLR寄存器 
 * 参考资料:Cortex-A7 Technical ReferenceManua.pdf P105
 */
typedef union
{
  struct
  {
    uint32_t M:1;                        /*!< bit:     0  MMU enable */
    uint32_t A:1;                        /*!< bit:     1  Alignment check enable */
    uint32_t C:1;                        /*!< bit:     2  Cache enable */
    uint32_t _reserved0:2;               /*!< bit: 3.. 4  Reserved */
    uint32_t CP15BEN:1;                  /*!< bit:     5  CP15 barrier enable */
    uint32_t _reserved1:1;               /*!< bit:     6  Reserved */
    uint32_t B:1;                        /*!< bit:     7  Endianness model */
    uint32_t _reserved2:2;               /*!< bit: 8.. 9  Reserved */
    uint32_t SW:1;                       /*!< bit:    10  SWP and SWPB enable */
    uint32_t Z:1;                        /*!< bit:    11  Branch prediction enable */
    uint32_t I:1;                        /*!< bit:    12  Instruction cache enable */
    uint32_t V:1;                        /*!< bit:    13  Vectors bit */
    uint32_t RR:1;                       /*!< bit:    14  Round Robin select */
    uint32_t _reserved3:2;               /*!< bit:15..16  Reserved */
    uint32_t HA:1;                       /*!< bit:    17  Hardware Access flag enable */
    uint32_t _reserved4:1;               /*!< bit:    18  Reserved */
    uint32_t WXN:1;                      /*!< bit:    19  Write permission implies XN */
    uint32_t UWXN:1;                     /*!< bit:    20  Unprivileged write permission implies PL1 XN */
    uint32_t FI:1;                       /*!< bit:    21  Fast interrupts configuration enable */
    uint32_t U:1;                        /*!< bit:    22  Alignment model */
    uint32_t _reserved5:1;               /*!< bit:    23  Reserved */
    uint32_t VE:1;                       /*!< bit:    24  Interrupt Vectors Enable */
    uint32_t EE:1;                       /*!< bit:    25  Exception Endianness */
    uint32_t _reserved6:1;               /*!< bit:    26  Reserved */
    uint32_t NMFI:1;                     /*!< bit:    27  Non-maskable FIQ (NMFI) support */
    uint32_t TRE:1;                      /*!< bit:    28  TEX remap enable. */
    uint32_t AFE:1;                      /*!< bit:    29  Access flag enable */
    uint32_t TE:1;                       /*!< bit:    30  Thumb Exception enable */
    uint32_t _reserved7:1;               /*!< bit:    31  Reserved */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} SCTLR_Type;

/* CP15 寄存器SCTLR各个位定义 */
#define SCTLR_TE_Pos                     30U                                    /*!< SCTLR: TE Position */
#define SCTLR_TE_Msk                     (1UL << SCTLR_TE_Pos)                  /*!< SCTLR: TE Mask */

#define SCTLR_AFE_Pos                    29U                                    /*!< SCTLR: AFE Position */
#define SCTLR_AFE_Msk                    (1UL << SCTLR_AFE_Pos)                 /*!< SCTLR: AFE Mask */

#define SCTLR_TRE_Pos                    28U                                    /*!< SCTLR: TRE Position */
#define SCTLR_TRE_Msk                    (1UL << SCTLR_TRE_Pos)                 /*!< SCTLR: TRE Mask */

#define SCTLR_NMFI_Pos                   27U                                    /*!< SCTLR: NMFI Position */
#define SCTLR_NMFI_Msk                   (1UL << SCTLR_NMFI_Pos)                /*!< SCTLR: NMFI Mask */

#define SCTLR_EE_Pos                     25U                                    /*!< SCTLR: EE Position */
#define SCTLR_EE_Msk                     (1UL << SCTLR_EE_Pos)                  /*!< SCTLR: EE Mask */

#define SCTLR_VE_Pos                     24U                                    /*!< SCTLR: VE Position */
#define SCTLR_VE_Msk                     (1UL << SCTLR_VE_Pos)                  /*!< SCTLR: VE Mask */

#define SCTLR_U_Pos                      22U                                    /*!< SCTLR: U Position */
#define SCTLR_U_Msk                      (1UL << SCTLR_U_Pos)                   /*!< SCTLR: U Mask */

#define SCTLR_FI_Pos                     21U                                    /*!< SCTLR: FI Position */
#define SCTLR_FI_Msk                     (1UL << SCTLR_FI_Pos)                  /*!< SCTLR: FI Mask */

#define SCTLR_UWXN_Pos                   20U                                    /*!< SCTLR: UWXN Position */
#define SCTLR_UWXN_Msk                   (1UL << SCTLR_UWXN_Pos)                /*!< SCTLR: UWXN Mask */

#define SCTLR_WXN_Pos                    19U                                    /*!< SCTLR: WXN Position */
#define SCTLR_WXN_Msk                    (1UL << SCTLR_WXN_Pos)                 /*!< SCTLR: WXN Mask */

#define SCTLR_HA_Pos                     17U                                    /*!< SCTLR: HA Position */
#define SCTLR_HA_Msk                     (1UL << SCTLR_HA_Pos)                  /*!< SCTLR: HA Mask */

#define SCTLR_RR_Pos                     14U                                    /*!< SCTLR: RR Position */
#define SCTLR_RR_Msk                     (1UL << SCTLR_RR_Pos)                  /*!< SCTLR: RR Mask */

#define SCTLR_V_Pos                      13U                                    /*!< SCTLR: V Position */
#define SCTLR_V_Msk                      (1UL << SCTLR_V_Pos)                   /*!< SCTLR: V Mask */

#define SCTLR_I_Pos                      12U                                    /*!< SCTLR: I Position */
#define SCTLR_I_Msk                      (1UL << SCTLR_I_Pos)                   /*!< SCTLR: I Mask */

#define SCTLR_Z_Pos                      11U                                    /*!< SCTLR: Z Position */
#define SCTLR_Z_Msk                      (1UL << SCTLR_Z_Pos)                   /*!< SCTLR: Z Mask */

#define SCTLR_SW_Pos                     10U                                    /*!< SCTLR: SW Position */
#define SCTLR_SW_Msk                     (1UL << SCTLR_SW_Pos)                  /*!< SCTLR: SW Mask */

#define SCTLR_B_Pos                      7U                                     /*!< SCTLR: B Position */
#define SCTLR_B_Msk                      (1UL << SCTLR_B_Pos)                   /*!< SCTLR: B Mask */

#define SCTLR_CP15BEN_Pos                5U                                     /*!< SCTLR: CP15BEN Position */
#define SCTLR_CP15BEN_Msk                (1UL << SCTLR_CP15BEN_Pos)             /*!< SCTLR: CP15BEN Mask */

#define SCTLR_C_Pos                      2U                                     /*!< SCTLR: C Position */
#define SCTLR_C_Msk                      (1UL << SCTLR_C_Pos)                   /*!< SCTLR: C Mask */

#define SCTLR_A_Pos                      1U                                     /*!< SCTLR: A Position */
#define SCTLR_A_Msk                      (1UL << SCTLR_A_Pos)                   /*!< SCTLR: A Mask */

#define SCTLR_M_Pos                      0U                                     /*!< SCTLR: M Position */
#define SCTLR_M_Msk                      (1UL << SCTLR_M_Pos)                   /*!< SCTLR: M Mask */

/* CP15的ACTLR寄存器
 * 参考资料:Cortex-A7 Technical ReferenceManua.pdf P113
 */
typedef union
{
  struct
  {
    uint32_t _reserved0:6;               /*!< bit: 0.. 5  Reserved */
    uint32_t SMP:1;                      /*!< bit:     6  Enables coherent requests to the processor */
    uint32_t _reserved1:3;               /*!< bit: 7.. 9  Reserved */
    uint32_t DODMBS:1;                   /*!< bit:    10  Disable optimized data memory barrier behavior */
    uint32_t L2RADIS:1;                  /*!< bit:    11  L2 Data Cache read-allocate mode disable */
    uint32_t L1RADIS:1;                  /*!< bit:    12  L1 Data Cache read-allocate mode disable */
    uint32_t L1PCTL:2;                   /*!< bit:13..14  L1 Data prefetch control */
    uint32_t DDVM:1;                     /*!< bit:    15  Disable Distributed Virtual Memory (DVM) transactions */
    uint32_t _reserved3:12;              /*!< bit:16..27  Reserved */
    uint32_t DDI:1;                      /*!< bit:    28  Disable dual issue */
    uint32_t _reserved7:3;               /*!< bit:29..31  Reserved */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} ACTLR_Type;

#define ACTLR_DDI_Pos                    28U                                     /*!< ACTLR: DDI Position */
#define ACTLR_DDI_Msk                    (1UL << ACTLR_DDI_Pos)                  /*!< ACTLR: DDI Mask */

#define ACTLR_DDVM_Pos                   15U                                     /*!< ACTLR: DDVM Position */
#define ACTLR_DDVM_Msk                   (1UL << ACTLR_DDVM_Pos)                 /*!< ACTLR: DDVM Mask */

#define ACTLR_L1PCTL_Pos                 13U                                     /*!< ACTLR: L1PCTL Position */
#define ACTLR_L1PCTL_Msk                 (3UL << ACTLR_L1PCTL_Pos)               /*!< ACTLR: L1PCTL Mask */

#define ACTLR_L1RADIS_Pos                12U                                     /*!< ACTLR: L1RADIS Position */
#define ACTLR_L1RADIS_Msk                (1UL << ACTLR_L1RADIS_Pos)              /*!< ACTLR: L1RADIS Mask */

#define ACTLR_L2RADIS_Pos                11U                                     /*!< ACTLR: L2RADIS Position */
#define ACTLR_L2RADIS_Msk                (1UL << ACTLR_L2RADIS_Pos)              /*!< ACTLR: L2RADIS Mask */

#define ACTLR_DODMBS_Pos                 10U                                     /*!< ACTLR: DODMBS Position */
#define ACTLR_DODMBS_Msk                 (1UL << ACTLR_DODMBS_Pos)               /*!< ACTLR: DODMBS Mask */

#define ACTLR_SMP_Pos                    6U                                      /*!< ACTLR: SMP Position */
#define ACTLR_SMP_Msk                    (1UL << ACTLR_SMP_Pos)                  /*!< ACTLR: SMP Mask */


/* CP15的CPACR寄存器
 * 参考资料:Cortex-A7 Technical ReferenceManua.pdf P115
 */
typedef union
{
  struct
  {
    uint32_t _reserved0:20;              /*!< bit: 0..19  Reserved */
    uint32_t cp10:2;                     /*!< bit:20..21  Access rights for coprocessor 10 */
    uint32_t cp11:2;                     /*!< bit:22..23  Access rights for coprocessor 11 */
    uint32_t _reserved1:6;               /*!< bit:24..29  Reserved */
    uint32_t D32DIS:1;                   /*!< bit:    30  Disable use of registers D16-D31 of the VFP register file */
    uint32_t ASEDIS:1;                   /*!< bit:    31  Disable Advanced SIMD Functionality */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} CPACR_Type;

#define CPACR_ASEDIS_Pos                 31U                                    /*!< CPACR: ASEDIS Position */
#define CPACR_ASEDIS_Msk                 (1UL << CPACR_ASEDIS_Pos)              /*!< CPACR: ASEDIS Mask */

#define CPACR_D32DIS_Pos                 30U                                    /*!< CPACR: D32DIS Position */
#define CPACR_D32DIS_Msk                 (1UL << CPACR_D32DIS_Pos)              /*!< CPACR: D32DIS Mask */

#define CPACR_cp11_Pos                   22U                                    /*!< CPACR: cp11 Position */
#define CPACR_cp11_Msk                   (3UL << CPACR_cp11_Pos)                /*!< CPACR: cp11 Mask */

#define CPACR_cp10_Pos                   20U                                    /*!< CPACR: cp10 Position */
#define CPACR_cp10_Msk                   (3UL << CPACR_cp10_Pos)                /*!< CPACR: cp10 Mask */


/* CP15的DFSR寄存器
 * 参考资料:Cortex-A7 Technical ReferenceManua.pdf P128
 */
typedef union
{
  struct
  {
    uint32_t FS0:4;                      /*!< bit: 0.. 3  Fault Status bits bit 0-3 */
    uint32_t Domain:4;                   /*!< bit: 4.. 7  Fault on which domain */
    uint32_t _reserved0:2;               /*!< bit: 8.. 9  Reserved */
    uint32_t FS1:1;                      /*!< bit:    10  Fault Status bits bit 4 */
    uint32_t WnR:1;                      /*!< bit:    11  Write not Read bit */
    uint32_t ExT:1;                      /*!< bit:    12  External abort type */
    uint32_t CM:1;                       /*!< bit:    13  Cache maintenance fault */
    uint32_t _reserved1:18;              /*!< bit:14..31  Reserved */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} DFSR_Type;

#define DFSR_CM_Pos                      13U                                    /*!< DFSR: CM Position */
#define DFSR_CM_Msk                      (1UL << DFSR_CM_Pos)                   /*!< DFSR: CM Mask */

#define DFSR_Ext_Pos                     12U                                    /*!< DFSR: Ext Position */
#define DFSR_Ext_Msk                     (1UL << DFSR_Ext_Pos)                  /*!< DFSR: Ext Mask */

#define DFSR_WnR_Pos                     11U                                    /*!< DFSR: WnR Position */
#define DFSR_WnR_Msk                     (1UL << DFSR_WnR_Pos)                  /*!< DFSR: WnR Mask */

#define DFSR_FS1_Pos                     10U                                    /*!< DFSR: FS1 Position */
#define DFSR_FS1_Msk                     (1UL << DFSR_FS1_Pos)                  /*!< DFSR: FS1 Mask */

#define DFSR_Domain_Pos                  4U                                     /*!< DFSR: Domain Position */
#define DFSR_Domain_Msk                  (0xFUL << DFSR_Domain_Pos)             /*!< DFSR: Domain Mask */

#define DFSR_FS0_Pos                     0U                                     /*!< DFSR: FS0 Position */
#define DFSR_FS0_Msk                     (0xFUL << DFSR_FS0_Pos)                /*!< DFSR: FS0 Mask */


/* CP15的IFSR寄存器 
 * 参考资料:Cortex-A7 Technical ReferenceManua.pdf P131
 */
typedef union
{
  struct
  {
    uint32_t FS0:4;                      /*!< bit: 0.. 3  Fault Status bits bit 0-3 */
    uint32_t _reserved0:6;               /*!< bit: 4.. 9  Reserved */
    uint32_t FS1:1;                      /*!< bit:    10  Fault Status bits bit 4 */
    uint32_t _reserved1:1;               /*!< bit:    11  Reserved */
    uint32_t ExT:1;                      /*!< bit:    12  External abort type */
    uint32_t _reserved2:19;              /*!< bit:13..31  Reserved */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} IFSR_Type;

#define IFSR_ExT_Pos                     12U                                    /*!< IFSR: ExT Position */
#define IFSR_ExT_Msk                     (1UL << IFSR_ExT_Pos)                  /*!< IFSR: ExT Mask */

#define IFSR_FS1_Pos                     10U                                    /*!< IFSR: FS1 Position */
#define IFSR_FS1_Msk                     (1UL << IFSR_FS1_Pos)                  /*!< IFSR: FS1 Mask */

#define IFSR_FS0_Pos                     0U                                     /*!< IFSR: FS0 Position */
#define IFSR_FS0_Msk                     (0xFUL << IFSR_FS0_Pos)                /*!< IFSR: FS0 Mask */


/* CP15的ISR寄存器
 * 参考资料:ARM ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf P1640
 */
typedef union
{
  struct
  {
    uint32_t _reserved0:6;               /*!< bit: 0.. 5  Reserved */
    uint32_t F:1;                        /*!< bit:     6  FIQ pending bit */
    uint32_t I:1;                        /*!< bit:     7  IRQ pending bit */
    uint32_t A:1;                        /*!< bit:     8  External abort pending bit */
    uint32_t _reserved1:23;              /*!< bit:14..31  Reserved */
  } b;                                   /*!< Structure used for bit  access */
  uint32_t w;                            /*!< Type      used for word access */
} ISR_Type;

#define ISR_A_Pos                        13U                                    /*!< ISR: A Position */
#define ISR_A_Msk                        (1UL << ISR_A_Pos)                     /*!< ISR: A Mask */

#define ISR_I_Pos                        12U                                    /*!< ISR: I Position */
#define ISR_I_Msk                        (1UL << ISR_I_Pos)                     /*!< ISR: I Mask */

#define ISR_F_Pos                        11U                                    /*!< ISR: F Position */
#define ISR_F_Msk                        (1UL << ISR_F_Pos)                     /*!< ISR: F Mask */


/* Mask and shift a bit field value for use in a register bit range. */
#define _VAL2FLD(field, value)    ((value << field ## _Pos) & field ## _Msk)

/* Mask and shift a register value to extract a bit filed value. */
#define _FLD2VAL(field, value)    ((value & field ## _Msk) >> field ## _Pos)


/*******************************************************************************
 *       			CP15 访问函数
 ******************************************************************************/

FORCEDINLINE __STATIC_INLINE uint32_t __get_SCTLR(void)
{
  return __MRC(15, 0, 1, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_SCTLR(uint32_t sctlr)
{
  __MCR(15, 0, sctlr, 1, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_ACTLR(void)
{
  return __MRC(15, 0, 1, 0, 1);
}

FORCEDINLINE __STATIC_INLINE void __set_ACTLR(uint32_t actlr)
{
  __MCR(15, 0, actlr, 1, 0, 1);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_CPACR(void)
{
  return __MRC(15, 0, 1, 0, 2);
}

FORCEDINLINE __STATIC_INLINE void __set_CPACR(uint32_t cpacr)
{
  __MCR(15, 0, cpacr, 1, 0, 2);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_TTBR0(void)
{
  return __MRC(15, 0, 2, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_TTBR0(uint32_t ttbr0)
{
  __MCR(15, 0, ttbr0, 2, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_TTBR1(void)
{
  return __MRC(15, 0, 2, 0, 1);
}

FORCEDINLINE __STATIC_INLINE void __set_TTBR1(uint32_t ttbr1)
{
  __MCR(15, 0, ttbr1, 2, 0, 1);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_TTBCR(void)
{
  return __MRC(15, 0, 2, 0, 2);
}

FORCEDINLINE __STATIC_INLINE void __set_TTBCR(uint32_t ttbcr)
{
  __MCR(15, 0, ttbcr, 2, 0, 2);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_DACR(void)
{
  return __MRC(15, 0, 3, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_DACR(uint32_t dacr)
{
  __MCR(15, 0, dacr, 3, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_DFSR(void)
{
  return __MRC(15, 0, 5, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_DFSR(uint32_t dfsr)
{
  __MCR(15, 0, dfsr, 5, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_IFSR(void)
{
  return __MRC(15, 0, 5, 0, 1);
}

FORCEDINLINE __STATIC_INLINE void __set_IFSR(uint32_t ifsr)
{
  __MCR(15, 0, ifsr, 5, 0, 1);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_DFAR(void)
{
  return __MRC(15, 0, 6, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_DFAR(uint32_t dfar)
{
  __MCR(15, 0, dfar, 6, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_IFAR(void)
{
  return __MRC(15, 0, 6, 0, 2);
}

FORCEDINLINE __STATIC_INLINE void __set_IFAR(uint32_t ifar)
{
  __MCR(15, 0, ifar, 6, 0, 2);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_VBAR(void)
{
  return __MRC(15, 0, 12, 0, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_VBAR(uint32_t vbar)
{
  __MCR(15, 0, vbar, 12, 0, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_ISR(void)
{
  return __MRC(15, 0, 12, 1, 0);
}

FORCEDINLINE __STATIC_INLINE void __set_ISR(uint32_t isr)
{
  __MCR(15, 0, isr, 12, 1, 0);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_CONTEXTIDR(void)
{
  return __MRC(15, 0, 13, 0, 1);
}

FORCEDINLINE __STATIC_INLINE void __set_CONTEXTIDR(uint32_t contextidr)
{
  __MCR(15, 0, contextidr, 13, 0, 1);
}

FORCEDINLINE __STATIC_INLINE uint32_t __get_CBAR(void)
{
  return __MRC(15, 4, 15, 0, 0);
}

/*******************************************************************************
 *                 GIC相关内容
 *有关GIC的内容,参考:ARM Generic Interrupt Controller(ARM GIC控制器)V2.0.pdf
 ******************************************************************************/

/*
 * GIC寄存器描述结构体,
 * GIC分为分发器端和CPU接口端
 */
typedef struct
{
        uint32_t RESERVED0[1024];
  __IOM uint32_t D_CTLR;                 /*!< Offset: 0x1000 (R/W) Distributor Control Register */
  __IM  uint32_t D_TYPER;                /*!< Offset: 0x1004 (R/ )  Interrupt Controller Type Register */
  __IM  uint32_t D_IIDR;                 /*!< Offset: 0x1008 (R/ )  Distributor Implementer Identification Register */
        uint32_t RESERVED1[29];
  __IOM uint32_t D_IGROUPR[16];          /*!< Offset: 0x1080 - 0x0BC (R/W) Interrupt Group Registers */
        uint32_t RESERVED2[16];
  __IOM uint32_t D_ISENABLER[16];        /*!< Offset: 0x1100 - 0x13C (R/W) Interrupt Set-Enable Registers */
        uint32_t RESERVED3[16];
  __IOM uint32_t D_ICENABLER[16];        /*!< Offset: 0x1180 - 0x1BC (R/W) Interrupt Clear-Enable Registers */
        uint32_t RESERVED4[16];
  __IOM uint32_t D_ISPENDR[16];          /*!< Offset: 0x1200 - 0x23C (R/W) Interrupt Set-Pending Registers */
        uint32_t RESERVED5[16];
  __IOM uint32_t D_ICPENDR[16];          /*!< Offset: 0x1280 - 0x2BC (R/W) Interrupt Clear-Pending Registers */
        uint32_t RESERVED6[16];
  __IOM uint32_t D_ISACTIVER[16];        /*!< Offset: 0x1300 - 0x33C (R/W) Interrupt Set-Active Registers */
        uint32_t RESERVED7[16];
  __IOM uint32_t D_ICACTIVER[16];        /*!< Offset: 0x1380 - 0x3BC (R/W) Interrupt Clear-Active Registers */
        uint32_t RESERVED8[16];
  __IOM uint8_t  D_IPRIORITYR[512];      /*!< Offset: 0x1400 - 0x5FC (R/W) Interrupt Priority Registers */
        uint32_t RESERVED9[128];
  __IOM uint8_t  D_ITARGETSR[512];       /*!< Offset: 0x1800 - 0x9FC (R/W) Interrupt Targets Registers */
        uint32_t RESERVED10[128];
  __IOM uint32_t D_ICFGR[32];            /*!< Offset: 0x1C00 - 0xC7C (R/W) Interrupt configuration registers */
        uint32_t RESERVED11[32];
  __IM  uint32_t D_PPISR;                /*!< Offset: 0x1D00 (R/ ) Private Peripheral Interrupt Status Register */
  __IM  uint32_t D_SPISR[15];            /*!< Offset: 0x1D04 - 0xD3C (R/ ) Shared Peripheral Interrupt Status Registers */
        uint32_t RESERVED12[112];
  __OM  uint32_t D_SGIR;                 /*!< Offset: 0x1F00 ( /W) Software Generated Interrupt Register */
        uint32_t RESERVED13[3];
  __IOM uint8_t  D_CPENDSGIR[16];        /*!< Offset: 0x1F10 - 0xF1C (R/W) SGI Clear-Pending Registers */
  __IOM uint8_t  D_SPENDSGIR[16];        /*!< Offset: 0x1F20 - 0xF2C (R/W) SGI Set-Pending Registers */
        uint32_t RESERVED14[40];
  __IM  uint32_t D_PIDR4;                /*!< Offset: 0x1FD0 (R/ ) Peripheral ID4 Register */
  __IM  uint32_t D_PIDR5;                /*!< Offset: 0x1FD4 (R/ ) Peripheral ID5 Register */
  __IM  uint32_t D_PIDR6;                /*!< Offset: 0x1FD8 (R/ ) Peripheral ID6 Register */
  __IM  uint32_t D_PIDR7;                /*!< Offset: 0x1FDC (R/ ) Peripheral ID7 Register */
  __IM  uint32_t D_PIDR0;                /*!< Offset: 0x1FE0 (R/ ) Peripheral ID0 Register */
  __IM  uint32_t D_PIDR1;                /*!< Offset: 0x1FE4 (R/ ) Peripheral ID1 Register */
  __IM  uint32_t D_PIDR2;                /*!< Offset: 0x1FE8 (R/ ) Peripheral ID2 Register */
  __IM  uint32_t D_PIDR3;                /*!< Offset: 0x1FEC (R/ ) Peripheral ID3 Register */
  __IM  uint32_t D_CIDR0;                /*!< Offset: 0x1FF0 (R/ ) Component ID0 Register */
  __IM  uint32_t D_CIDR1;                /*!< Offset: 0x1FF4 (R/ ) Component ID1 Register */
  __IM  uint32_t D_CIDR2;                /*!< Offset: 0x1FF8 (R/ ) Component ID2 Register */
  __IM  uint32_t D_CIDR3;                /*!< Offset: 0x1FFC (R/ ) Component ID3 Register */

  __IOM uint32_t C_CTLR;                 /*!< Offset: 0x2000 (R/W) CPU Interface Control Register */
  __IOM uint32_t C_PMR;                  /*!< Offset: 0x2004 (R/W) Interrupt Priority Mask Register */
  __IOM uint32_t C_BPR;                  /*!< Offset: 0x2008 (R/W) Binary Point Register */
  __IM  uint32_t C_IAR;                  /*!< Offset: 0x200C (R/ ) Interrupt Acknowledge Register */
  __OM  uint32_t C_EOIR;                 /*!< Offset: 0x2010 ( /W) End Of Interrupt Register */
  __IM  uint32_t C_RPR;                  /*!< Offset: 0x2014 (R/ ) Running Priority Register */
  __IM  uint32_t C_HPPIR;                /*!< Offset: 0x2018 (R/ ) Highest Priority Pending Interrupt Register */
  __IOM uint32_t C_ABPR;                 /*!< Offset: 0x201C (R/W) Aliased Binary Point Register */
  __IM  uint32_t C_AIAR;                 /*!< Offset: 0x2020 (R/ ) Aliased Interrupt Acknowledge Register */
  __OM  uint32_t C_AEOIR;                /*!< Offset: 0x2024 ( /W) Aliased End Of Interrupt Register */
  __IM  uint32_t C_AHPPIR;               /*!< Offset: 0x2028 (R/ ) Aliased Highest Priority Pending Interrupt Register */
        uint32_t RESERVED15[41];
  __IOM uint32_t C_APR0;                 /*!< Offset: 0x20D0 (R/W) Active Priority Register */
        uint32_t RESERVED16[3];
  __IOM uint32_t C_NSAPR0;               /*!< Offset: 0x20E0 (R/W) Non-secure Active Priority Register */
        uint32_t RESERVED17[6];
  __IM  uint32_t C_IIDR;                 /*!< Offset: 0x20FC (R/ ) CPU Interface Identification Register */
        uint32_t RESERVED18[960];
  __OM  uint32_t C_DIR;                  /*!< Offset: 0x3000 ( /W) Deactivate Interrupt Register */
} GIC_Type;


/* 
 * GIC初始化
 * 为了简单使用GIC的group0
 */
FORCEDINLINE __STATIC_INLINE void GIC_Init(void)
{
  uint32_t i;
  uint32_t irqRegs;
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);

  irqRegs = (gic->D_TYPER & 0x1FUL) + 1;

  /* On POR, all SPI is in group 0, level-sensitive and using 1-N model */

  /* Disable all PPI, SGI and SPI */
  for (i = 0; i < irqRegs; i++)
    gic->D_ICENABLER[i] = 0xFFFFFFFFUL;

  /* Make all interrupts have higher priority */
  gic->C_PMR = (0xFFUL << (8 - __GIC_PRIO_BITS)) & 0xFFUL;

  /* No subpriority, all priority level allows preemption */
  gic->C_BPR = 7 - __GIC_PRIO_BITS;

  /* Enable group0 distribution */
  gic->D_CTLR = 1UL;

  /* Enable group0 signaling */
  gic->C_CTLR = 1UL;
}

/*  
 * 使能指定的中断
 */
FORCEDINLINE __STATIC_INLINE void GIC_EnableIRQ(IRQn_Type IRQn)
{
  	GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);
  	gic->D_ISENABLER[((uint32_t)(int32_t)IRQn) >> 5] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}

/*  
 * 关闭指定的中断
 */

FORCEDINLINE __STATIC_INLINE void GIC_DisableIRQ(IRQn_Type IRQn)
{
  	GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);
  	gic->D_ICENABLER[((uint32_t)(int32_t)IRQn) >> 5] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL));
}

/* 
 * 返回中断号 
 */
FORCEDINLINE __STATIC_INLINE uint32_t GIC_AcknowledgeIRQ(void)
{
  	GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);
  	return gic->C_IAR & 0x1FFFUL;
}

/* 
 * 向EOIR写入发送中断的中断号来释放中断
 */
FORCEDINLINE __STATIC_INLINE void GIC_DeactivateIRQ(uint32_t value)
{
  	GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);
  	gic->C_EOIR = value;
}

/*
 * 获取运行优先级
 */
FORCEDINLINE __STATIC_INLINE uint32_t GIC_GetRunningPriority(void)
{
  	GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);
  	return gic->C_RPR & 0xFFUL;
}

/*
 * 设置组优先级
 */
FORCEDINLINE __STATIC_INLINE void GIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
  	GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);
  	gic->C_BPR = PriorityGroup & 0x7UL;
}

/*
 * 获取组优先级
 */
FORCEDINLINE __STATIC_INLINE uint32_t GIC_GetPriorityGrouping(void)
{
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);

  return gic->C_BPR & 0x7UL;
}

/*
 * 设置优先级
 */
FORCEDINLINE __STATIC_INLINE void GIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
  	GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);
  	gic->D_IPRIORITYR[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority << (8UL - __GIC_PRIO_BITS)) & (uint32_t)0xFFUL);
}

/*
 * 获取优先级
 */
FORCEDINLINE __STATIC_INLINE uint32_t GIC_GetPriority(IRQn_Type IRQn)
{
  GIC_Type *gic = (GIC_Type *)(__get_CBAR() & 0xFFFF0000UL);
  return(((uint32_t)gic->D_IPRIORITYR[((uint32_t)(int32_t)IRQn)] >> (8UL - __GIC_PRIO_BITS)));
}


#endif
posted on 2023-09-16 14:20  fuzidage  阅读(191)  评论(0编辑  收藏  举报