快速链接:
1、一个简单的aarch64架构图
2、A64指令集的特点:
- x0-x30 : 31个通用寄存器(general-purpose register),且都扩展到了64位, 其中x30是sp(Stack Pointer)
- Zero Register: XZR/WZR,在大多数情况下,作为源寄存器使用时, 读出来的值 是0; 作为目标寄存器使用时, 丢弃结果。
- 不再有LDM、STM、PUSH、POP指令, 取而代之的是STP、LDP
- 条件指令大量的减少了
- 不能将CPSR作为单个寄存器访问,确认代之的是PSTATE
- 删除了"协处理器"概念,取而代之的是通过系统寄存器访问
o System register access
o Cache/TLB management
o VAPA translation
o Barriers and CLREX
o Architectural hints (WFI, etc)
o Debug
通用寄存器分类
PSTATE寄存器:
3、跳转指令
指令统计
- 条件跳转指令 : 5个
- 无条件跳转label指令 : 2个
- 无条件跳转register指令 : 3个
(1)、条件跳转指令
(偏移范围为±1MiB)
- b.cond label
- cbz Xn|Wn, label
- cbnz Xn|Wn, label
- tbz Xn|Wn, #uimm6, label //如果Xn的第uimm的bit位位0,则跳转到label
- tbnz Xn|Wn, #uimm6, label
(b.cond的condition条件)
(b.cond的应用)
.align 7, INV_INSN
el0_sync_a64:
restore_mapping
mrs x2, esr_el1
mrs x3, sp_el0
lsr x2, x2, #ESR_EC_SHIFT
cmp x2, #ESR_EC_AARCH64_SVC
b.eq el0_svc //-----------b.cond的应用
b el0_sync_abort
check_vector_size el0_sync_a64
(cbz、cbnz的应用)
当调用__cpu_spin_trylock(lock)时
FUNC __cpu_spin_trylock , :
mov x1, x0
mov w2, #SPINLOCK_LOCK
.loop: ldaxr w0, [x1]
cbnz w0, .cpu_spin_trylock_out //------相当于是在检查参数的合法性,lock==NULL时直接返回
stxr w0, w2, [x1]
cbnz w0, .loop
.cpu_spin_trylock_out:
ret
END_FUNC __cpu_spin_trylock
(tbz、tbnz的应用)
LOCAL_FUNC el1_sync_abort , :
mov x0, sp
msr spsel, #0
mov x3, sp /* Save original sp */
/*
* Update core local flags.
* flags = (flags << THREAD_CLF_SAVED_SHIFT) | THREAD_CLF_ABORT;
*/
ldr w1, [x0, #THREAD_CORE_LOCAL_FLAGS]
lsl w1, w1, #THREAD_CLF_SAVED_SHIFT
orr w1, w1, #THREAD_CLF_ABORT
tbnz w1, #(THREAD_CLF_SAVED_SHIFT + THREAD_CLF_ABORT_SHIFT), \ //--------------tbnz的使用
.Lsel_tmp_sp
/* Select abort stack */
ldr x2, [x0, #THREAD_CORE_LOCAL_ABT_STACK_VA_END]
b .Lset_sp
.Lsel_tmp_sp:
/* Select tmp stack */
ldr x2, [x0, #THREAD_CORE_LOCAL_TMP_STACK_VA_END]
orr w1, w1, #THREAD_CLF_TMP /* flags |= THREAD_CLF_TMP; */
(2)、无条件跳转label指令
(偏移范围为 : ±128MiB)
- b label
- bl label
(3)、无条件跳转register指令
(偏移范围为 : 无限制)
- br Xn
- blr Xn
- ret {Xn}
4、异常产生和返回
- 异常产生指令 : 5个
- 异常返回指令 : 1个
- debug的异常指令 : 4个
(1)、异常产生指令
- BRK Breakpoint Instruction BRK
- HLT Halt Instruction //停止指令
- HVC
- SMC
- SVC
(2)、异常返回指令
- ERET
(3)、debug的异常指令
DCPS1 Debug switch to Exception level 1
DCPS2 Debug switch to Exception level 2
DCPS3 Debug switch to Exception level 3
DRPS Debug restore PE state
5、系统访问指令
- 系统寄存器访问指令 : 1个
- 系统操作指令 : 6个
(1)、系统寄存器访问指令
- MRS
- MSR
(2)、系统操作指令
- SYS
- SYSL
- IC
- DC
- AT
- TLBI
6、提示指令Hint instructions
提示指令Hint instructions : 8个
- NOP
- YIELD
- WFE
- WFI
- SEV
- SEVL
- HINT
- DGH
7、Barriers指令
Barriers指令 : 4个
- CLREX // Clear Exclusives monitor
- DMB
- DSB
- ISB
还有一些特殊的barriers指令,如果未实现,则等效于 NOP
CSDB
ESB
PSB
PSSB
SB
SSBB
TSB
7、指针授权指令:Pointer authentication instructions
有很多寄存器,目前(2020)基本没有使用,暂不介绍
8、存取指令 : Loads and stores
(1)、存取指令的寻址模式
[Rn, offset]! 前变址寻址
最终访问内存的地址 = Rn+offset
操作后Rn的值 = Rn+offset
[Rn], offset 后变址寻址
最终访问内存的地址 = Rn
操作后Rn的值 = Rn+offset
[Rn, offset] 偏移寻址
最终访问内存的地址 = Rn+offset
操作后Rn的值不变
注意:对于偏移寻址,还可以使用寄存器偏移寻址、扩展寄存器偏移寻址
[base,Xm{,LSL #imm}]
[base,Wm,(S|U)XTW {#imm}]
示例:
(1)、在进程切换调用的cpu_switch_to函数中,使用到了后变址寻址
ENTRY(cpu_switch_to)
mov x10, #THREAD_CPU_CONTEXT
add x8, x0, x10
mov x9, sp
stp x19, x20, [x8], #16 // store callee-saved registers
stp x21, x22, [x8], #16
stp x23, x24, [x8], #16
stp x25, x26, [x8], #16
stp x27, x28, [x8], #16
stp x29, x9, [x8], #16
str lr, [x8]
add x8, x1, x10
ldp x19, x20, [x8], #16 // restore callee-saved registers
ldp x21, x22, [x8], #16
ldp x23, x24, [x8], #16
ldp x25, x26, [x8], #16
ldp x27, x28, [x8], #16
ldp x29, x9, [x8], #16
ldr lr, [x8]
mov sp, x9
#ifdef CONFIG_THREAD_INFO_IN_TASK
msr sp_el0, x1
#else
and x9, x9, #~(THREAD_SIZE - 1)
msr sp_el0, x9
#endif
ret
ENDPROC(cpu_switch_to)
(2)、load/store指令的介绍
术语:
sign-extends :符号扩展,前面补符合位和0
zero-extends :0扩展,即前面补0
S : sign-extends
B : byte
H : half-word
R :register
P : pair 双字操作
a、Load-Store Pair
LDP Wt1, Wt2, addr //从addr处读取两个word到Wt1和Wt2
LDP Xt1, Xt2, addr //从addr处读取两个double-word到Xt1和Xt2
LDPSW Xt1, Xt2, addr //从addr处读取两个word到Xt1和Xt2, sign-extends
STP Wt1, Wt2, addr //将Wt1和Wt2写入addr地址处
STP Xt1, Xt2, addr //将Xt1和Xt2写入addr地址处
b、LDNP and STNP 非暂存指令
非暂存指令(Non-temporal),不会加载到cache
LDNP Wt1, Wt2, [base,#imm]
LDNP Xt1, Xt2, [base,#imm]
STNP Wt1, Wt2, [base,#imm]
STNP Xt1, Xt2, [base,#imm]
c、Load-Store Unprivileged
在EL1中执行数据的加载和写入,权限等是按照EL0的配置来执行
LDTR Wt, [base,#simm9]
LDTR Xt, [base,#simm9]
LDTRB Wt, [base,#simm9] 加载一个字节并sign-extends扩展到Wt, 在EL1下执行的,但是按照EL0的权限来执行
LDTRSB Wt, [base,#simm9]
LDTRSB Xt, [base,#simm9]
LDTRH Wt, [base,#simm9]
LDTRSH Wt, [base,#simm9]
LDTRSH Xt, [base,#simm9]
LDTRSW Xt, [base,#simm9]
STTR Wt, [base,#simm9]
STTR Xt, [base,#simm9]
STTRB Wt, [base,#simm9]
STTRH Wt, [base,#simm9]
d、Load-Store Exclusive
【补充armv8的exclusive操作】
为了解决多核情况下的锁竞争问题,arm引入了exclusive操作,并添加了相应的指令。
exclusive的操作的核心,就是会将锁,用一个状态机进行维护,该状态机有2种状态,open状态和exclusive状态。要想成功的对锁进行上锁,状态必须要从exclusive状态切换到open状态,其他状态,都是失败的。
LDXR指令,将状态从open状态切换到exclusive状态,STXR指令,将状态从exclusive状态切换到open状态
术语 : (R-register, P-pair)
LDXR Wt, [base{,#0}]
LDXR Xt, [base{,#0}]
LDXRB Wt, [base{,#0}]
LDXRH Wt, [base{,#0}]
LDXP Wt, Wt2, [base{,#0}]
LDXP Xt, Xt2, [base{,#0}]
STXR Ws, Wt, [base{,#0}]
STXR Ws, Xt, [base{,#0}]
STXRB Ws, Wt, [base{,#0}]
STXRH Ws, Wt, [base{,#0}]
STXP Ws, Wt, Wt2, [base{,#0}]
STXP Ws, Xt, Xt2, [base{,#0}]
e、Load-Acquire / Store-Release
标记物理地址为非独占访问
(Non-exclusive)
LDAR Wt, [base{,#0}]
LDAR Xt, [base{,#0}]
LDARB Wt, [base{,#0}]
LDARH Wt, [base{,#0}]
STLR Wt, [base{,#0}]
STLR Xt, [base{,#0}]
STLRB Wt, [base{,#0}]
STLRH Wt, [base{,#0}]
(Exclusive)
LDAXR Wt, [base{,#0}]
LDAXR Xt, [base{,#0}]
LDAXRB Wt, [base{,#0}]
LDAXRH Wt, [base{,#0}]
LDAXP Wt, Wt2, [base{,#0}]
LDAXP Xt, Xt2, [base{,#0}]
STLXR Ws, Wt, [base{,#0}]
STLXR Ws, Xt, [base{,#0}]
STLXRB Ws, Wt, [base{,#0}]
STLXRH Ws, Xt|Wt, [base{,#0}]
STLXP Ws, Wt, Wt2, [base{,#0}]
STLXP Ws, Xt, Xt2, [base{,#0}]
关注"Arm精选"公众号,备注进ARM交流讨论区。