xref: /rk3399_ARM-atf/include/arch/aarch64/asm_macros.S (revision 0607fb7f6bd9480eea8e989700b0fd5bc7f79148)
1/*
2 * Copyright (c) 2013-2026, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6#ifndef ASM_MACROS_S
7#define ASM_MACROS_S
8
9#include <arch.h>
10#include <common/asm_macros_common.S>
11#include <lib/cpus/cpu_ops.h>
12#include <lib/spinlock.h>
13
14/*
15 * TLBI instruction with type specifier that implements the workaround for
16 * errata 813419 of Cortex-A57 or errata 1286807 of Cortex-A76.
17 */
18#if ERRATA_A57_813419 || ERRATA_A76_1286807
19#define TLB_INVALIDATE(_type) \
20	tlbi	_type; \
21	dsb	ish; \
22	tlbi	_type
23#else
24#define TLB_INVALIDATE(_type) \
25	tlbi	_type
26#endif
27
28
29	/*
30	 * Create a stack frame at the start of an assembly function. Will also
31	 * add all necessary call frame information (cfi) directives for a
32	 * pretty stack trace. This is necessary as there is quite a bit of
33	 * flexibility within a stack frame and the stack pointer can move
34	 * around throughout the function. If the debugger isn't told where to
35	 * find things, it gets lost, gives up and displays nothing. So inform
36	 * the debugger of what's where. Anchor the Canonical Frame Address
37	 * (CFA; the thing used to track what's where) to the frame pointer as
38	 * that's not expected to change in the function body and no extra
39	 * bookkeeping will be necessary, allowing free movement of the sp
40	 *
41	 *   _frame_size: requested space for caller to use. Must be a mutliple
42	 *     of 16 for stack pointer alignment
43	 */
44	.macro	func_prologue _frame_size=0
45	.if \_frame_size & 0xf
46	.error "frame_size must have stack pointer alignment (multiple of 16)"
47	.endif
48
49	/* put frame record at top of frame */
50	stp	x29, x30, [sp, #-0x10]!
51	mov	x29,sp
52	.if \_frame_size
53	sub	sp, sp, #\_frame_size
54	.endif
55
56	/* point CFA to start of frame record, i.e. x29 + 0x10 */
57	.cfi_def_cfa	x29,  0x10
58	/* inform it about x29, x30 locations */
59	.cfi_offset	x30, -0x8
60	.cfi_offset	x29, -0x10
61	.endm
62
63	/*
64	 * Clear stack frame at the end of an assembly function.
65	 *
66	 *   _frame_size: the value passed to func_prologue
67	 */
68	.macro	func_epilogue _frame_size=0
69	/* remove requested space */
70	.if \_frame_size
71	add	sp, sp, #\_frame_size
72	.endif
73	ldp	x29, x30, [sp], #0x10
74	.endm
75
76
77	.macro	dcache_line_size  reg, tmp
78	mrs	\tmp, ctr_el0
79	ubfx	\tmp, \tmp, #16, #4
80	mov	\reg, #4
81	lsl	\reg, \reg, \tmp
82	.endm
83
84
85	.macro	icache_line_size  reg, tmp
86	mrs	\tmp, ctr_el0
87	and	\tmp, \tmp, #0xf
88	mov	\reg, #4
89	lsl	\reg, \reg, \tmp
90	.endm
91
92
93	.macro	smc_check  label
94	mrs	x0, esr_el3
95	ubfx	x0, x0, #ESR_EC_SHIFT, #ESR_EC_LENGTH
96	cmp	x0, #EC_AARCH64_SMC
97	b.ne	$label
98	.endm
99
100	/*
101	 * Declare the exception vector table, enforcing it is aligned on a
102	 * 2KB boundary, as required by the ARMv8 architecture.
103	 * Use zero bytes as the fill value to be stored in the padding bytes
104	 * so that it inserts illegal AArch64 instructions. This increases
105	 * security, robustness and potentially facilitates debugging.
106	 */
107	.macro vector_base  label, section_name=.vectors
108	.section \section_name, "ax"
109	.align 11, 0
110	\label:
111	.endm
112
113	/*
114	 * Create an entry in the exception vector table, enforcing it is
115	 * aligned on a 128-byte boundary, as required by the ARMv8 architecture.
116	 * Use zero bytes as the fill value to be stored in the padding bytes
117	 * so that it inserts illegal AArch64 instructions. This increases
118	 * security, robustness and potentially facilitates debugging.
119	 */
120	.macro vector_entry  label, section_name=.vectors
121	.cfi_sections .debug_frame
122	.section \section_name, "ax"
123	.align 7, 0
124	.type \label, %function
125	.cfi_startproc
126	\label:
127	.endm
128
129	/*
130	 * Add the bytes until fill the full exception vector, whose size is always
131	 * 32 instructions. If there are more than 32 instructions in the
132	 * exception vector then an error is emitted.
133	 */
134	.macro end_vector_entry label
135	.cfi_endproc
136	.iflt \label + (32 * 4) - .
137		.error "\label won't fit in exception vector"
138	.endif
139	.fill	\label + (32 * 4) - .
140	.endm
141
142	/*
143	 * This macro calculates the base address of the current CPU's MP stack
144	 * using the plat_my_core_pos() index, the name of the stack storage
145	 * and the size of each stack
146	 * Out: X0 = physical address of stack base
147	 * Clobber: X30, X1, X2
148	 */
149	.macro get_my_mp_stack _name, _size
150	bl	plat_my_core_pos
151	adrp	x2, (\_name + \_size)
152	add	x2, x2, :lo12:(\_name + \_size)
153	mov x1, #\_size
154	madd x0, x0, x1, x2
155	.endm
156
157	/*
158	 * This macro calculates the base address of a UP stack using the
159	 * name of the stack storage and the size of the stack
160	 * Out: X0 = physical address of stack base
161	 */
162	.macro get_up_stack _name, _size
163	adrp	x0, (\_name + \_size)
164	add	x0, x0, :lo12:(\_name + \_size)
165	.endm
166
167	/*
168	 * Helper macro to generate the best mov/movk combinations according
169	 * the value to be moved. The 16 bits from '_shift' are tested and
170	 * if not zero, they are moved into '_reg' without affecting
171	 * other bits.
172	 */
173	.macro _mov_imm16 _reg, _val, _shift
174		.if (\_val >> \_shift) & 0xffff
175			.if (\_val & (1 << \_shift - 1))
176				movk	\_reg, (\_val >> \_shift) & 0xffff, LSL \_shift
177			.else
178				mov	\_reg, \_val & (0xffff << \_shift)
179			.endif
180		.endif
181	.endm
182
183	/*
184	 * Helper macro to load arbitrary values into 32 or 64-bit registers
185	 * which generates the best mov/movk combinations. Many base addresses
186	 * are 64KB aligned the macro will eliminate updating bits 15:0 in
187	 * that case
188	 */
189	.macro mov_imm _reg, _val
190		.if (\_val) == 0
191			mov	\_reg, #0
192		.else
193			_mov_imm16	\_reg, (\_val), 0
194			_mov_imm16	\_reg, (\_val), 16
195			_mov_imm16	\_reg, (\_val), 32
196			_mov_imm16	\_reg, (\_val), 48
197		.endif
198	.endm
199
200	/*
201	 * Macro to mark instances where we're jumping to a function and don't
202	 * expect a return. To provide the function being jumped to with
203	 * additional information, we use 'bl' instruction to jump rather than
204	 * 'b'.
205         *
206	 * Debuggers infer the location of a call from where LR points to, which
207	 * is usually the instruction after 'bl'. If this macro expansion
208	 * happens to be the last location in a function, that'll cause the LR
209	 * to point a location beyond the function, thereby misleading debugger
210	 * back trace. We therefore insert a 'nop' after the function call for
211	 * debug builds, unless 'skip_nop' parameter is non-zero.
212	 */
213	.macro no_ret _func:req, skip_nop=0
214	bl	\_func
215#if DEBUG
216	.ifeq \skip_nop
217	nop
218	.endif
219#endif
220	.endm
221
222	/*
223	 * Reserve space for a spin lock in assembly file.
224	 */
225	.macro define_asm_spinlock _name:req
226	.align	SPINLOCK_ASM_ALIGN
227	\_name:
228	.space	SPINLOCK_ASM_SIZE
229	.endm
230
231	/*
232	 * Helper macro to read system register value into x0
233	 */
234	.macro	read reg:req
235#if ENABLE_BTI
236	BTI	j
237#endif
238	mrs	x0, \reg
239	ret
240	.endm
241
242	/*
243	 * Helper macro to write value from x1 to system register
244	 */
245	.macro	write reg:req
246#if ENABLE_BTI
247	BTI	j
248#endif
249	msr	\reg, x1
250	ret
251	.endm
252
253	/*
254	 * The "sb" instruction was introduced later into the architecture,
255	 * so not all toolchains understand it. Some deny its usage unless
256	 * a supported processor is specified on the build command line.
257	 * Use sb's system register encoding to work around this, we already
258	 * guard the sb execution with a feature flag.
259	 */
260
261	.macro sb_barrier_insn
262	msr	SYSREG_SB, xzr
263	.endm
264
265	.macro psb_csync
266	hint #17 /* use the hint synonym for compatibility */
267	.endm
268
269	.macro tsb_csync
270	hint #18 /* use the hint synonym for compatibility */
271	.endm
272
273	/*
274	 * Macro for using speculation barrier instruction introduced by
275	 * FEAT_SB, if it's enabled.
276	 */
277	.macro speculation_barrier
278	/* fallback to the old slower variant for FEAT_STATE_CHECKED */
279#if ENABLE_FEAT_SB == 1
280	sb_barrier_insn
281#else
282	dsb	sy
283	isb
284#endif
285	.endm
286
287	/*
288	 * Clear Branch History instruction, translates to NOP on CPUs
289	 * that don't implement the clrbhb instruction.
290	 */
291	.macro clrbhb
292	hint	#22
293	.endm
294
295	/*
296	 * Macro for mitigating against speculative execution beyond ERET. Uses the
297	 * speculation barrier instruction introduced by FEAT_SB, if it's enabled.
298	 */
299	.macro exception_return
300	eret
301	speculation_barrier
302	.endm
303
304	/*
305	 * Macro to unmask External Aborts by changing PSTATE.A bit.
306	 * Put explicit synchronization event to ensure newly unmasked interrupt
307	 * is taken immediately.
308	 */
309	.macro  unmask_async_ea
310	msr     daifclr, #DAIF_ABT_BIT
311	isb
312	.endm
313
314	/*
315	 * Macro for error synchronization on exception boundaries.
316	 * With FEAT_RAS enabled, it is assumed that FEAT_IESB is also present
317	 * and enabled.
318	 * FEAT_IESB provides an implicit error synchronization event at
319	 * exception entry and exception return, so there is no need for any
320	 * explicit instruction. In the FEAT_STATE_CHECKED case the explicit
321	 * synchronisation will be done anyway because there isn't enough space
322	 * in the exception vectors to do the check. Any platform looking for
323	 * maximum performance should not use FEAT_STATE_CHECKED.
324	 */
325	.macro synchronize_errors
326#if ENABLE_FEAT_RAS == 0 || ENABLE_FEAT_RAS == 2
327	/* Complete any stores that may return an abort */
328	dsb	sy
329	/* Synchronise the CPU context with the completion of the dsb */
330	isb
331#endif
332	.endm
333
334	/*
335	 * Helper macro to instruction adr <reg>, <symbol> where <symbol> is
336	 * within the range +/- 4 GB.
337	 */
338	.macro adr_l, dst, sym
339	adrp	\dst, \sym
340	add	\dst, \dst, :lo12:\sym
341	.endm
342
343	/*
344	* is_feat_XYZ_present_asm - Set flags and reg if FEAT_XYZ
345	* is enabled at runtime.
346	*
347	* Arguments:
348	* reg: Register for temporary use.
349	*
350	* Clobbers: reg
351	*/
352	.macro is_feat_sysreg128_present_asm reg:req
353	mrs	\reg, ID_AA64ISAR2_EL1
354	ands	\reg, \reg, #(ID_AA64ISAR2_SYSREG128_MASK << ID_AA64ISAR2_SYSREG128_SHIFT)
355	.endm
356
357	.macro is_feat_pauth_present_asm reg:req, clobber:req
358	mrs	\reg, ID_AA64ISAR1_EL1
359	mov_imm	\clobber, ((ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) \
360			 | (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT) \
361			 | (ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) \
362			 | (ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT))
363	tst	\reg, \clobber
364	.endm
365
366	.macro is_feat_sctlr2_present_asm reg:req
367	mrs	\reg, ID_AA64MMFR3_EL1
368	ands	\reg, \reg, #(ID_AA64MMFR3_EL1_SCTLR2_MASK << ID_AA64MMFR3_EL1_SCTLR2_SHIFT)
369	.endm
370
371	.macro is_feat_sme_present_asm reg:req
372	mrs	\reg, id_aa64pfr1_el1
373	ands	\reg, \reg, #(ID_AA64PFR1_EL1_SME_MASK << ID_AA64PFR1_EL1_SME_SHIFT)
374	.endm
375
376	.macro is_feat_amu_present_asm reg:req
377	mrs	\reg, ID_AA64PFR0_EL1
378	ands	\reg, \reg, #(ID_AA64PFR0_AMU_MASK << ID_AA64PFR0_AMU_SHIFT)
379	.endm
380
381	/*
382	 * There are various places where Morello requires simple switchovers for
383	 * system registers. For eg morello uses celr_el3 vs elr_el3, cvbar_el3 vs
384	 * vbar_el3 etc., this macro simplifies that operation and makes the code
385	 * more readable.
386	 */
387	.macro	msr_wide_reg _sysreg:req, _gp_reg:req
388#if ENABLE_FEAT_MORELLO
389#if ENABLE_FEAT_MORELLO == 2
390	is_feat_morello_present_asm	x10
391	beq 1f
392#endif /* ENABLE_FEAT_MORELLO == 2 */
393	cvtp	c\_gp_reg, x\_gp_reg
394	msr	c\_sysreg, c\_gp_reg
395	b	2f
3961:
397#endif /* ENABLE_FEAT_MORELLO */
398#if ENABLE_FEAT_MORELLO != 1
399	msr	\_sysreg, x\_gp_reg
400#endif /* ENABLE_FEAT_MORELLO != 1 */
4012:
402	.endm
403
404.macro call_reset_handler
405#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && RESET_TO_BL2)
406	/* ---------------------------------------------------------------------
407	 * It is a cold boot.
408	 * Perform any processor specific actions upon reset e.g. cache, TLB
409	 * invalidations etc.
410	 * ---------------------------------------------------------------------
411	 */
412	/* The plat_reset_handler can clobber x0 - x18, x30 */
413	bl	plat_reset_handler
414
415	/* Get the matching cpu_ops pointer */
416	bl	get_cpu_ops_ptr
417
418	/* Get the cpu_ops reset handler */
419	ldr	x2, [x0, #CPU_RESET_FUNC]
420
421	/* The cpu_ops reset handler can clobber x0 - x19, x30 */
422	blr	x2
423#endif
424.endm
425#endif /* ASM_MACROS_S */
426