xref: /arm-trusted-firmware/include/arch/aarch32/asm_macros.S (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu/*
2*91f16700Schasinglulu * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved.
3*91f16700Schasinglulu *
4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu */
6*91f16700Schasinglulu#ifndef ASM_MACROS_S
7*91f16700Schasinglulu#define ASM_MACROS_S
8*91f16700Schasinglulu
9*91f16700Schasinglulu#include <arch.h>
10*91f16700Schasinglulu#include <common/asm_macros_common.S>
11*91f16700Schasinglulu#include <lib/cpus/cpu_ops.h>
12*91f16700Schasinglulu#include <lib/spinlock.h>
13*91f16700Schasinglulu
14*91f16700Schasinglulu/*
15*91f16700Schasinglulu * TLBI instruction with type specifier that implements the workaround for
16*91f16700Schasinglulu * errata 813419 of Cortex-A57.
17*91f16700Schasinglulu */
18*91f16700Schasinglulu#if ERRATA_A57_813419
19*91f16700Schasinglulu#define TLB_INVALIDATE(_reg, _coproc) \
20*91f16700Schasinglulu	stcopr	_reg, _coproc; \
21*91f16700Schasinglulu	dsb	ish; \
22*91f16700Schasinglulu	stcopr	_reg, _coproc
23*91f16700Schasinglulu#else
24*91f16700Schasinglulu#define TLB_INVALIDATE(_reg, _coproc) \
25*91f16700Schasinglulu	stcopr	_reg, _coproc
26*91f16700Schasinglulu#endif
27*91f16700Schasinglulu
28*91f16700Schasinglulu	/*
29*91f16700Schasinglulu	 * Co processor register accessors
30*91f16700Schasinglulu	 */
31*91f16700Schasinglulu	.macro ldcopr reg, coproc, opc1, CRn, CRm, opc2
32*91f16700Schasinglulu	mrc	\coproc, \opc1, \reg, \CRn, \CRm, \opc2
33*91f16700Schasinglulu	.endm
34*91f16700Schasinglulu
35*91f16700Schasinglulu	.macro ldcopr16 reg1, reg2, coproc, opc1, CRm
36*91f16700Schasinglulu	mrrc	\coproc, \opc1, \reg1, \reg2, \CRm
37*91f16700Schasinglulu	.endm
38*91f16700Schasinglulu
39*91f16700Schasinglulu	.macro stcopr reg, coproc, opc1, CRn, CRm, opc2
40*91f16700Schasinglulu	mcr	\coproc, \opc1, \reg, \CRn, \CRm, \opc2
41*91f16700Schasinglulu	.endm
42*91f16700Schasinglulu
43*91f16700Schasinglulu	.macro stcopr16 reg1, reg2, coproc, opc1, CRm
44*91f16700Schasinglulu	mcrr	\coproc, \opc1, \reg1, \reg2, \CRm
45*91f16700Schasinglulu	.endm
46*91f16700Schasinglulu
47*91f16700Schasinglulu	/* Cache line size helpers */
48*91f16700Schasinglulu	.macro	dcache_line_size  reg, tmp
49*91f16700Schasinglulu	ldcopr	\tmp, CTR
50*91f16700Schasinglulu	ubfx	\tmp, \tmp, #CTR_DMINLINE_SHIFT, #CTR_DMINLINE_WIDTH
51*91f16700Schasinglulu	mov	\reg, #CPU_WORD_SIZE
52*91f16700Schasinglulu	lsl	\reg, \reg, \tmp
53*91f16700Schasinglulu	.endm
54*91f16700Schasinglulu
55*91f16700Schasinglulu	.macro	icache_line_size  reg, tmp
56*91f16700Schasinglulu	ldcopr	\tmp, CTR
57*91f16700Schasinglulu	and	\tmp, \tmp, #CTR_IMINLINE_MASK
58*91f16700Schasinglulu	mov	\reg, #CPU_WORD_SIZE
59*91f16700Schasinglulu	lsl	\reg, \reg, \tmp
60*91f16700Schasinglulu	.endm
61*91f16700Schasinglulu
62*91f16700Schasinglulu	/*
63*91f16700Schasinglulu	 * Declare the exception vector table, enforcing it is aligned on a
64*91f16700Schasinglulu	 * 32 byte boundary.
65*91f16700Schasinglulu	 */
66*91f16700Schasinglulu	.macro vector_base  label
67*91f16700Schasinglulu	.section .vectors, "ax"
68*91f16700Schasinglulu	.align 5
69*91f16700Schasinglulu	\label:
70*91f16700Schasinglulu	.endm
71*91f16700Schasinglulu
72*91f16700Schasinglulu	/*
73*91f16700Schasinglulu	 * This macro calculates the base address of the current CPU's multi
74*91f16700Schasinglulu	 * processor(MP) stack using the plat_my_core_pos() index, the name of
75*91f16700Schasinglulu	 * the stack storage and the size of each stack.
76*91f16700Schasinglulu	 * Out: r0 = physical address of stack base
77*91f16700Schasinglulu	 * Clobber: r14, r1, r2
78*91f16700Schasinglulu	 */
79*91f16700Schasinglulu	.macro get_my_mp_stack _name, _size
80*91f16700Schasinglulu	bl	plat_my_core_pos
81*91f16700Schasinglulu	ldr r2, =(\_name + \_size)
82*91f16700Schasinglulu	mov r1, #\_size
83*91f16700Schasinglulu	mla r0, r0, r1, r2
84*91f16700Schasinglulu	.endm
85*91f16700Schasinglulu
86*91f16700Schasinglulu	/*
87*91f16700Schasinglulu	 * This macro calculates the base address of a uniprocessor(UP) stack
88*91f16700Schasinglulu	 * using the name of the stack storage and the size of the stack
89*91f16700Schasinglulu	 * Out: r0 = physical address of stack base
90*91f16700Schasinglulu	 */
91*91f16700Schasinglulu	.macro get_up_stack _name, _size
92*91f16700Schasinglulu	ldr r0, =(\_name + \_size)
93*91f16700Schasinglulu	.endm
94*91f16700Schasinglulu
95*91f16700Schasinglulu#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION)
96*91f16700Schasinglulu	/*
97*91f16700Schasinglulu	 * Macro for mitigating against speculative execution.
98*91f16700Schasinglulu	 * ARMv7 cores without Virtualization extension do not support the
99*91f16700Schasinglulu	 * eret instruction.
100*91f16700Schasinglulu	 */
101*91f16700Schasinglulu	.macro exception_return
102*91f16700Schasinglulu	movs	pc, lr
103*91f16700Schasinglulu	dsb	nsh
104*91f16700Schasinglulu	isb
105*91f16700Schasinglulu	.endm
106*91f16700Schasinglulu
107*91f16700Schasinglulu#else
108*91f16700Schasinglulu	/*
109*91f16700Schasinglulu	 * Macro for mitigating against speculative execution beyond ERET. Uses the
110*91f16700Schasinglulu	 * speculation barrier instruction introduced by FEAT_SB, if it's enabled.
111*91f16700Schasinglulu	 */
112*91f16700Schasinglulu	.macro exception_return
113*91f16700Schasinglulu	eret
114*91f16700Schasinglulu#if ENABLE_FEAT_SB
115*91f16700Schasinglulu	sb
116*91f16700Schasinglulu#else
117*91f16700Schasinglulu	dsb	nsh
118*91f16700Schasinglulu	isb
119*91f16700Schasinglulu#endif
120*91f16700Schasinglulu	.endm
121*91f16700Schasinglulu#endif
122*91f16700Schasinglulu
123*91f16700Schasinglulu	/* Macro for error synchronization */
124*91f16700Schasinglulu	.macro synchronize_errors
125*91f16700Schasinglulu	/* Complete any stores that may return an abort */
126*91f16700Schasinglulu	dsb	sy
127*91f16700Schasinglulu	/* Synchronise the CPU context with the completion of the dsb */
128*91f16700Schasinglulu	isb
129*91f16700Schasinglulu	.endm
130*91f16700Schasinglulu
131*91f16700Schasinglulu#if (ARM_ARCH_MAJOR == 7)
132*91f16700Schasinglulu	/* ARMv7 does not support stl instruction */
133*91f16700Schasinglulu	.macro stl _reg, _write_lock
134*91f16700Schasinglulu	dmb
135*91f16700Schasinglulu	str	\_reg, \_write_lock
136*91f16700Schasinglulu	dsb
137*91f16700Schasinglulu	.endm
138*91f16700Schasinglulu#endif
139*91f16700Schasinglulu
140*91f16700Schasinglulu	/*
141*91f16700Schasinglulu	 * Helper macro to generate the best mov/movw/movt combinations
142*91f16700Schasinglulu	 * according to the value to be moved.
143*91f16700Schasinglulu	 */
144*91f16700Schasinglulu	.macro mov_imm _reg, _val
145*91f16700Schasinglulu		.if ((\_val) & 0xffff0000) == 0
146*91f16700Schasinglulu			mov	\_reg, #(\_val)
147*91f16700Schasinglulu		.else
148*91f16700Schasinglulu			movw	\_reg, #((\_val) & 0xffff)
149*91f16700Schasinglulu			movt	\_reg, #((\_val) >> 16)
150*91f16700Schasinglulu		.endif
151*91f16700Schasinglulu	.endm
152*91f16700Schasinglulu
153*91f16700Schasinglulu	/*
154*91f16700Schasinglulu	 * Macro to mark instances where we're jumping to a function and don't
155*91f16700Schasinglulu	 * expect a return. To provide the function being jumped to with
156*91f16700Schasinglulu	 * additional information, we use 'bl' instruction to jump rather than
157*91f16700Schasinglulu	 * 'b'.
158*91f16700Schasinglulu         *
159*91f16700Schasinglulu	 * Debuggers infer the location of a call from where LR points to, which
160*91f16700Schasinglulu	 * is usually the instruction after 'bl'. If this macro expansion
161*91f16700Schasinglulu	 * happens to be the last location in a function, that'll cause the LR
162*91f16700Schasinglulu	 * to point a location beyond the function, thereby misleading debugger
163*91f16700Schasinglulu	 * back trace. We therefore insert a 'nop' after the function call for
164*91f16700Schasinglulu	 * debug builds, unless 'skip_nop' parameter is non-zero.
165*91f16700Schasinglulu	 */
166*91f16700Schasinglulu	.macro no_ret _func:req, skip_nop=0
167*91f16700Schasinglulu	bl	\_func
168*91f16700Schasinglulu#if DEBUG
169*91f16700Schasinglulu	.ifeq \skip_nop
170*91f16700Schasinglulu	nop
171*91f16700Schasinglulu	.endif
172*91f16700Schasinglulu#endif
173*91f16700Schasinglulu	.endm
174*91f16700Schasinglulu
175*91f16700Schasinglulu	/*
176*91f16700Schasinglulu	 * Reserve space for a spin lock in assembly file.
177*91f16700Schasinglulu	 */
178*91f16700Schasinglulu	.macro define_asm_spinlock _name:req
179*91f16700Schasinglulu	.align	SPINLOCK_ASM_ALIGN
180*91f16700Schasinglulu	\_name:
181*91f16700Schasinglulu	.space	SPINLOCK_ASM_SIZE
182*91f16700Schasinglulu	.endm
183*91f16700Schasinglulu
184*91f16700Schasinglulu	/*
185*91f16700Schasinglulu	 * Helper macro to OR the bottom 32 bits of `_val` into `_reg_l`
186*91f16700Schasinglulu	 * and the top 32 bits of `_val` into `_reg_h`.  If either the bottom
187*91f16700Schasinglulu	 * or top word of `_val` is zero, the corresponding OR operation
188*91f16700Schasinglulu	 * is skipped.
189*91f16700Schasinglulu	 */
190*91f16700Schasinglulu	.macro orr64_imm _reg_l, _reg_h, _val
191*91f16700Schasinglulu		.if (\_val >> 32)
192*91f16700Schasinglulu			orr \_reg_h, \_reg_h, #(\_val >> 32)
193*91f16700Schasinglulu		.endif
194*91f16700Schasinglulu		.if (\_val & 0xffffffff)
195*91f16700Schasinglulu			orr \_reg_l, \_reg_l, #(\_val & 0xffffffff)
196*91f16700Schasinglulu		.endif
197*91f16700Schasinglulu	.endm
198*91f16700Schasinglulu
199*91f16700Schasinglulu	/*
200*91f16700Schasinglulu	 * Helper macro to bitwise-clear bits in `_reg_l` and
201*91f16700Schasinglulu	 * `_reg_h` given a 64 bit immediate `_val`.  The set bits
202*91f16700Schasinglulu	 * in the bottom word of `_val` dictate which bits from
203*91f16700Schasinglulu	 * `_reg_l` should be cleared.  Similarly, the set bits in
204*91f16700Schasinglulu	 * the top word of `_val` dictate which bits from `_reg_h`
205*91f16700Schasinglulu	 * should be cleared.  If either the bottom or top word of
206*91f16700Schasinglulu	 * `_val` is zero, the corresponding BIC operation is skipped.
207*91f16700Schasinglulu	 */
208*91f16700Schasinglulu	.macro bic64_imm _reg_l, _reg_h, _val
209*91f16700Schasinglulu		.if (\_val >> 32)
210*91f16700Schasinglulu			bic \_reg_h, \_reg_h, #(\_val >> 32)
211*91f16700Schasinglulu		.endif
212*91f16700Schasinglulu		.if (\_val & 0xffffffff)
213*91f16700Schasinglulu			bic \_reg_l, \_reg_l, #(\_val & 0xffffffff)
214*91f16700Schasinglulu		.endif
215*91f16700Schasinglulu	.endm
216*91f16700Schasinglulu
217*91f16700Schasinglulu	/*
218*91f16700Schasinglulu	 * Helper macro for carrying out division in software when
219*91f16700Schasinglulu	 * hardware division is not suported. \top holds the dividend
220*91f16700Schasinglulu	 * in the function call and the remainder after
221*91f16700Schasinglulu	 * the function is executed. \bot holds the divisor. \div holds
222*91f16700Schasinglulu	 * the quotient and \temp is a temporary registed used in calcualtion.
223*91f16700Schasinglulu	 * The division algorithm has been obtained from:
224*91f16700Schasinglulu	 * http://www.keil.com/support/man/docs/armasm/armasm_dom1359731155623.htm
225*91f16700Schasinglulu	 */
226*91f16700Schasinglulu	.macro	softudiv	div:req,top:req,bot:req,temp:req
227*91f16700Schasinglulu
228*91f16700Schasinglulu	mov     \temp, \bot
229*91f16700Schasinglulu	cmp     \temp, \top, lsr #1
230*91f16700Schasingluludiv1:
231*91f16700Schasinglulu	movls   \temp, \temp, lsl #1
232*91f16700Schasinglulu	cmp     \temp, \top, lsr #1
233*91f16700Schasinglulu	bls     div1
234*91f16700Schasinglulu	mov     \div, #0
235*91f16700Schasinglulu
236*91f16700Schasingluludiv2:
237*91f16700Schasinglulu	cmp     \top, \temp
238*91f16700Schasinglulu	subcs   \top, \top,\temp
239*91f16700Schasinglulu	ADC     \div, \div, \div
240*91f16700Schasinglulu	mov     \temp, \temp, lsr #1
241*91f16700Schasinglulu	cmp     \temp, \bot
242*91f16700Schasinglulu	bhs     div2
243*91f16700Schasinglulu	.endm
244*91f16700Schasinglulu#endif /* ASM_MACROS_S */
245