xref: /arm-trusted-firmware/include/arch/aarch64/asm_macros.S (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu/*
2*91f16700Schasinglulu * Copyright (c) 2013-2020, 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/spinlock.h>
12*91f16700Schasinglulu
13*91f16700Schasinglulu/*
14*91f16700Schasinglulu * TLBI instruction with type specifier that implements the workaround for
15*91f16700Schasinglulu * errata 813419 of Cortex-A57 or errata 1286807 of Cortex-A76.
16*91f16700Schasinglulu */
17*91f16700Schasinglulu#if ERRATA_A57_813419 || ERRATA_A76_1286807
18*91f16700Schasinglulu#define TLB_INVALIDATE(_type) \
19*91f16700Schasinglulu	tlbi	_type; \
20*91f16700Schasinglulu	dsb	ish; \
21*91f16700Schasinglulu	tlbi	_type
22*91f16700Schasinglulu#else
23*91f16700Schasinglulu#define TLB_INVALIDATE(_type) \
24*91f16700Schasinglulu	tlbi	_type
25*91f16700Schasinglulu#endif
26*91f16700Schasinglulu
27*91f16700Schasinglulu
28*91f16700Schasinglulu	/*
29*91f16700Schasinglulu	 * Create a stack frame at the start of an assembly function. Will also
30*91f16700Schasinglulu	 * add all necessary call frame information (cfi) directives for a
31*91f16700Schasinglulu	 * pretty stack trace. This is necessary as there is quite a bit of
32*91f16700Schasinglulu	 * flexibility within a stack frame and the stack pointer can move
33*91f16700Schasinglulu	 * around throughout the function. If the debugger isn't told where to
34*91f16700Schasinglulu	 * find things, it gets lost, gives up and displays nothing. So inform
35*91f16700Schasinglulu	 * the debugger of what's where. Anchor the Canonical Frame Address
36*91f16700Schasinglulu	 * (CFA; the thing used to track what's where) to the frame pointer as
37*91f16700Schasinglulu	 * that's not expected to change in the function body and no extra
38*91f16700Schasinglulu	 * bookkeeping will be necessary, allowing free movement of the sp
39*91f16700Schasinglulu	 *
40*91f16700Schasinglulu	 *   _frame_size: requested space for caller to use. Must be a mutliple
41*91f16700Schasinglulu	 *     of 16 for stack pointer alignment
42*91f16700Schasinglulu	 */
43*91f16700Schasinglulu	.macro	func_prologue _frame_size=0
44*91f16700Schasinglulu	.if \_frame_size & 0xf
45*91f16700Schasinglulu	.error "frame_size must have stack pointer alignment (multiple of 16)"
46*91f16700Schasinglulu	.endif
47*91f16700Schasinglulu
48*91f16700Schasinglulu	/* put frame record at top of frame */
49*91f16700Schasinglulu	stp	x29, x30, [sp, #-0x10]!
50*91f16700Schasinglulu	mov	x29,sp
51*91f16700Schasinglulu	.if \_frame_size
52*91f16700Schasinglulu	sub	sp, sp, #\_frame_size
53*91f16700Schasinglulu	.endif
54*91f16700Schasinglulu
55*91f16700Schasinglulu	/* point CFA to start of frame record, i.e. x29 + 0x10 */
56*91f16700Schasinglulu	.cfi_def_cfa	x29,  0x10
57*91f16700Schasinglulu	/* inform it about x29, x30 locations */
58*91f16700Schasinglulu	.cfi_offset	x30, -0x8
59*91f16700Schasinglulu	.cfi_offset	x29, -0x10
60*91f16700Schasinglulu	.endm
61*91f16700Schasinglulu
62*91f16700Schasinglulu	/*
63*91f16700Schasinglulu	 * Clear stack frame at the end of an assembly function.
64*91f16700Schasinglulu	 *
65*91f16700Schasinglulu	 *   _frame_size: the value passed to func_prologue
66*91f16700Schasinglulu	 */
67*91f16700Schasinglulu	.macro	func_epilogue _frame_size=0
68*91f16700Schasinglulu	/* remove requested space */
69*91f16700Schasinglulu	.if \_frame_size
70*91f16700Schasinglulu	add	sp, sp, #\_frame_size
71*91f16700Schasinglulu	.endif
72*91f16700Schasinglulu	ldp	x29, x30, [sp], #0x10
73*91f16700Schasinglulu	.endm
74*91f16700Schasinglulu
75*91f16700Schasinglulu
76*91f16700Schasinglulu	.macro	dcache_line_size  reg, tmp
77*91f16700Schasinglulu	mrs	\tmp, ctr_el0
78*91f16700Schasinglulu	ubfx	\tmp, \tmp, #16, #4
79*91f16700Schasinglulu	mov	\reg, #4
80*91f16700Schasinglulu	lsl	\reg, \reg, \tmp
81*91f16700Schasinglulu	.endm
82*91f16700Schasinglulu
83*91f16700Schasinglulu
84*91f16700Schasinglulu	.macro	icache_line_size  reg, tmp
85*91f16700Schasinglulu	mrs	\tmp, ctr_el0
86*91f16700Schasinglulu	and	\tmp, \tmp, #0xf
87*91f16700Schasinglulu	mov	\reg, #4
88*91f16700Schasinglulu	lsl	\reg, \reg, \tmp
89*91f16700Schasinglulu	.endm
90*91f16700Schasinglulu
91*91f16700Schasinglulu
92*91f16700Schasinglulu	.macro	smc_check  label
93*91f16700Schasinglulu	mrs	x0, esr_el3
94*91f16700Schasinglulu	ubfx	x0, x0, #ESR_EC_SHIFT, #ESR_EC_LENGTH
95*91f16700Schasinglulu	cmp	x0, #EC_AARCH64_SMC
96*91f16700Schasinglulu	b.ne	$label
97*91f16700Schasinglulu	.endm
98*91f16700Schasinglulu
99*91f16700Schasinglulu	/*
100*91f16700Schasinglulu	 * Declare the exception vector table, enforcing it is aligned on a
101*91f16700Schasinglulu	 * 2KB boundary, as required by the ARMv8 architecture.
102*91f16700Schasinglulu	 * Use zero bytes as the fill value to be stored in the padding bytes
103*91f16700Schasinglulu	 * so that it inserts illegal AArch64 instructions. This increases
104*91f16700Schasinglulu	 * security, robustness and potentially facilitates debugging.
105*91f16700Schasinglulu	 */
106*91f16700Schasinglulu	.macro vector_base  label, section_name=.vectors
107*91f16700Schasinglulu	.section \section_name, "ax"
108*91f16700Schasinglulu	.align 11, 0
109*91f16700Schasinglulu	\label:
110*91f16700Schasinglulu	.endm
111*91f16700Schasinglulu
112*91f16700Schasinglulu	/*
113*91f16700Schasinglulu	 * Create an entry in the exception vector table, enforcing it is
114*91f16700Schasinglulu	 * aligned on a 128-byte boundary, as required by the ARMv8 architecture.
115*91f16700Schasinglulu	 * Use zero bytes as the fill value to be stored in the padding bytes
116*91f16700Schasinglulu	 * so that it inserts illegal AArch64 instructions. This increases
117*91f16700Schasinglulu	 * security, robustness and potentially facilitates debugging.
118*91f16700Schasinglulu	 */
119*91f16700Schasinglulu	.macro vector_entry  label, section_name=.vectors
120*91f16700Schasinglulu	.cfi_sections .debug_frame
121*91f16700Schasinglulu	.section \section_name, "ax"
122*91f16700Schasinglulu	.align 7, 0
123*91f16700Schasinglulu	.type \label, %function
124*91f16700Schasinglulu	.cfi_startproc
125*91f16700Schasinglulu	\label:
126*91f16700Schasinglulu	.endm
127*91f16700Schasinglulu
128*91f16700Schasinglulu	/*
129*91f16700Schasinglulu	 * Add the bytes until fill the full exception vector, whose size is always
130*91f16700Schasinglulu	 * 32 instructions. If there are more than 32 instructions in the
131*91f16700Schasinglulu	 * exception vector then an error is emitted.
132*91f16700Schasinglulu	 */
133*91f16700Schasinglulu	.macro end_vector_entry label
134*91f16700Schasinglulu	.cfi_endproc
135*91f16700Schasinglulu	.fill	\label + (32 * 4) - .
136*91f16700Schasinglulu	.endm
137*91f16700Schasinglulu
138*91f16700Schasinglulu	/*
139*91f16700Schasinglulu	 * This macro calculates the base address of the current CPU's MP stack
140*91f16700Schasinglulu	 * using the plat_my_core_pos() index, the name of the stack storage
141*91f16700Schasinglulu	 * and the size of each stack
142*91f16700Schasinglulu	 * Out: X0 = physical address of stack base
143*91f16700Schasinglulu	 * Clobber: X30, X1, X2
144*91f16700Schasinglulu	 */
145*91f16700Schasinglulu	.macro get_my_mp_stack _name, _size
146*91f16700Schasinglulu	bl	plat_my_core_pos
147*91f16700Schasinglulu	adrp	x2, (\_name + \_size)
148*91f16700Schasinglulu	add	x2, x2, :lo12:(\_name + \_size)
149*91f16700Schasinglulu	mov x1, #\_size
150*91f16700Schasinglulu	madd x0, x0, x1, x2
151*91f16700Schasinglulu	.endm
152*91f16700Schasinglulu
153*91f16700Schasinglulu	/*
154*91f16700Schasinglulu	 * This macro calculates the base address of a UP stack using the
155*91f16700Schasinglulu	 * name of the stack storage and the size of the stack
156*91f16700Schasinglulu	 * Out: X0 = physical address of stack base
157*91f16700Schasinglulu	 */
158*91f16700Schasinglulu	.macro get_up_stack _name, _size
159*91f16700Schasinglulu	adrp	x0, (\_name + \_size)
160*91f16700Schasinglulu	add	x0, x0, :lo12:(\_name + \_size)
161*91f16700Schasinglulu	.endm
162*91f16700Schasinglulu
163*91f16700Schasinglulu	/*
164*91f16700Schasinglulu	 * Helper macro to generate the best mov/movk combinations according
165*91f16700Schasinglulu	 * the value to be moved. The 16 bits from '_shift' are tested and
166*91f16700Schasinglulu	 * if not zero, they are moved into '_reg' without affecting
167*91f16700Schasinglulu	 * other bits.
168*91f16700Schasinglulu	 */
169*91f16700Schasinglulu	.macro _mov_imm16 _reg, _val, _shift
170*91f16700Schasinglulu		.if (\_val >> \_shift) & 0xffff
171*91f16700Schasinglulu			.if (\_val & (1 << \_shift - 1))
172*91f16700Schasinglulu				movk	\_reg, (\_val >> \_shift) & 0xffff, LSL \_shift
173*91f16700Schasinglulu			.else
174*91f16700Schasinglulu				mov	\_reg, \_val & (0xffff << \_shift)
175*91f16700Schasinglulu			.endif
176*91f16700Schasinglulu		.endif
177*91f16700Schasinglulu	.endm
178*91f16700Schasinglulu
179*91f16700Schasinglulu	/*
180*91f16700Schasinglulu	 * Helper macro to load arbitrary values into 32 or 64-bit registers
181*91f16700Schasinglulu	 * which generates the best mov/movk combinations. Many base addresses
182*91f16700Schasinglulu	 * are 64KB aligned the macro will eliminate updating bits 15:0 in
183*91f16700Schasinglulu	 * that case
184*91f16700Schasinglulu	 */
185*91f16700Schasinglulu	.macro mov_imm _reg, _val
186*91f16700Schasinglulu		.if (\_val) == 0
187*91f16700Schasinglulu			mov	\_reg, #0
188*91f16700Schasinglulu		.else
189*91f16700Schasinglulu			_mov_imm16	\_reg, (\_val), 0
190*91f16700Schasinglulu			_mov_imm16	\_reg, (\_val), 16
191*91f16700Schasinglulu			_mov_imm16	\_reg, (\_val), 32
192*91f16700Schasinglulu			_mov_imm16	\_reg, (\_val), 48
193*91f16700Schasinglulu		.endif
194*91f16700Schasinglulu	.endm
195*91f16700Schasinglulu
196*91f16700Schasinglulu	/*
197*91f16700Schasinglulu	 * Macro to mark instances where we're jumping to a function and don't
198*91f16700Schasinglulu	 * expect a return. To provide the function being jumped to with
199*91f16700Schasinglulu	 * additional information, we use 'bl' instruction to jump rather than
200*91f16700Schasinglulu	 * 'b'.
201*91f16700Schasinglulu         *
202*91f16700Schasinglulu	 * Debuggers infer the location of a call from where LR points to, which
203*91f16700Schasinglulu	 * is usually the instruction after 'bl'. If this macro expansion
204*91f16700Schasinglulu	 * happens to be the last location in a function, that'll cause the LR
205*91f16700Schasinglulu	 * to point a location beyond the function, thereby misleading debugger
206*91f16700Schasinglulu	 * back trace. We therefore insert a 'nop' after the function call for
207*91f16700Schasinglulu	 * debug builds, unless 'skip_nop' parameter is non-zero.
208*91f16700Schasinglulu	 */
209*91f16700Schasinglulu	.macro no_ret _func:req, skip_nop=0
210*91f16700Schasinglulu	bl	\_func
211*91f16700Schasinglulu#if DEBUG
212*91f16700Schasinglulu	.ifeq \skip_nop
213*91f16700Schasinglulu	nop
214*91f16700Schasinglulu	.endif
215*91f16700Schasinglulu#endif
216*91f16700Schasinglulu	.endm
217*91f16700Schasinglulu
218*91f16700Schasinglulu	/*
219*91f16700Schasinglulu	 * Reserve space for a spin lock in assembly file.
220*91f16700Schasinglulu	 */
221*91f16700Schasinglulu	.macro define_asm_spinlock _name:req
222*91f16700Schasinglulu	.align	SPINLOCK_ASM_ALIGN
223*91f16700Schasinglulu	\_name:
224*91f16700Schasinglulu	.space	SPINLOCK_ASM_SIZE
225*91f16700Schasinglulu	.endm
226*91f16700Schasinglulu
227*91f16700Schasinglulu	/*
228*91f16700Schasinglulu	 * With RAS extension executes esb instruction, else NOP
229*91f16700Schasinglulu	 */
230*91f16700Schasinglulu	.macro esb
231*91f16700Schasinglulu	.inst	0xd503221f
232*91f16700Schasinglulu	.endm
233*91f16700Schasinglulu
234*91f16700Schasinglulu	/*
235*91f16700Schasinglulu	 * Helper macro to read system register value into x0
236*91f16700Schasinglulu	 */
237*91f16700Schasinglulu	.macro	read reg:req
238*91f16700Schasinglulu#if ENABLE_BTI
239*91f16700Schasinglulu	bti	j
240*91f16700Schasinglulu#endif
241*91f16700Schasinglulu	mrs	x0, \reg
242*91f16700Schasinglulu	ret
243*91f16700Schasinglulu	.endm
244*91f16700Schasinglulu
245*91f16700Schasinglulu	/*
246*91f16700Schasinglulu	 * Helper macro to write value from x1 to system register
247*91f16700Schasinglulu	 */
248*91f16700Schasinglulu	.macro	write reg:req
249*91f16700Schasinglulu#if ENABLE_BTI
250*91f16700Schasinglulu	bti	j
251*91f16700Schasinglulu#endif
252*91f16700Schasinglulu	msr	\reg, x1
253*91f16700Schasinglulu	ret
254*91f16700Schasinglulu	.endm
255*91f16700Schasinglulu
256*91f16700Schasinglulu	/*
257*91f16700Schasinglulu	 * The "sb" instruction was introduced later into the architecture,
258*91f16700Schasinglulu	 * so not all toolchains understand it. Some deny its usage unless
259*91f16700Schasinglulu	 * a supported processor is specified on the build command line.
260*91f16700Schasinglulu	 * Use sb's system register encoding to work around this, we already
261*91f16700Schasinglulu	 * guard the sb execution with a feature flag.
262*91f16700Schasinglulu	 */
263*91f16700Schasinglulu
264*91f16700Schasinglulu	.macro sb_barrier_insn
265*91f16700Schasinglulu	msr	SYSREG_SB, xzr
266*91f16700Schasinglulu	.endm
267*91f16700Schasinglulu
268*91f16700Schasinglulu	/*
269*91f16700Schasinglulu	 * Macro for using speculation barrier instruction introduced by
270*91f16700Schasinglulu	 * FEAT_SB, if it's enabled.
271*91f16700Schasinglulu	 */
272*91f16700Schasinglulu	.macro speculation_barrier
273*91f16700Schasinglulu#if ENABLE_FEAT_SB
274*91f16700Schasinglulu	sb_barrier_insn
275*91f16700Schasinglulu#else
276*91f16700Schasinglulu	dsb	sy
277*91f16700Schasinglulu	isb
278*91f16700Schasinglulu#endif
279*91f16700Schasinglulu	.endm
280*91f16700Schasinglulu
281*91f16700Schasinglulu	/*
282*91f16700Schasinglulu	 * Macro for mitigating against speculative execution beyond ERET. Uses the
283*91f16700Schasinglulu	 * speculation barrier instruction introduced by FEAT_SB, if it's enabled.
284*91f16700Schasinglulu	 */
285*91f16700Schasinglulu	.macro exception_return
286*91f16700Schasinglulu	eret
287*91f16700Schasinglulu#if ENABLE_FEAT_SB
288*91f16700Schasinglulu	sb_barrier_insn
289*91f16700Schasinglulu#else
290*91f16700Schasinglulu	dsb	nsh
291*91f16700Schasinglulu	isb
292*91f16700Schasinglulu#endif
293*91f16700Schasinglulu	.endm
294*91f16700Schasinglulu
295*91f16700Schasinglulu	/*
296*91f16700Schasinglulu	 * Macro to unmask External Aborts by changing PSTATE.A bit.
297*91f16700Schasinglulu	 * Put explicit synchronization event to ensure newly unmasked interrupt
298*91f16700Schasinglulu	 * is taken immediately.
299*91f16700Schasinglulu	 */
300*91f16700Schasinglulu	.macro  unmask_async_ea
301*91f16700Schasinglulu	msr     daifclr, #DAIF_ABT_BIT
302*91f16700Schasinglulu	isb
303*91f16700Schasinglulu	.endm
304*91f16700Schasinglulu
305*91f16700Schasinglulu	/* Macro for error synchronization on exception boundries.
306*91f16700Schasinglulu	 * With FEAT_RAS enabled, it is assumed that FEAT_IESB is also present
307*91f16700Schasinglulu	 * and enabled.
308*91f16700Schasinglulu	 * FEAT_IESB provides an implicit error synchronization event at exception
309*91f16700Schasinglulu	 * entry and exception return, so there is no need for any explicit instruction.
310*91f16700Schasinglulu	 */
311*91f16700Schasinglulu	.macro synchronize_errors
312*91f16700Schasinglulu#if !ENABLE_FEAT_RAS
313*91f16700Schasinglulu	/* Complete any stores that may return an abort */
314*91f16700Schasinglulu	dsb	sy
315*91f16700Schasinglulu	/* Synchronise the CPU context with the completion of the dsb */
316*91f16700Schasinglulu	isb
317*91f16700Schasinglulu#endif
318*91f16700Schasinglulu	.endm
319*91f16700Schasinglulu
320*91f16700Schasinglulu#endif /* ASM_MACROS_S */
321