xref: /rk3399_ARM-atf/include/arch/aarch64/asm_macros.S (revision f610c8c38b523dd8f314dd5c849c92a0be2e7ded)
1/*
2 * Copyright (c) 2013-2025, 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	.fill	\label + (32 * 4) - .
137	.endm
138
139	/*
140	 * This macro calculates the base address of the current CPU's MP stack
141	 * using the plat_my_core_pos() index, the name of the stack storage
142	 * and the size of each stack
143	 * Out: X0 = physical address of stack base
144	 * Clobber: X30, X1, X2
145	 */
146	.macro get_my_mp_stack _name, _size
147	bl	plat_my_core_pos
148	adrp	x2, (\_name + \_size)
149	add	x2, x2, :lo12:(\_name + \_size)
150	mov x1, #\_size
151	madd x0, x0, x1, x2
152	.endm
153
154	/*
155	 * This macro calculates the base address of a UP stack using the
156	 * name of the stack storage and the size of the stack
157	 * Out: X0 = physical address of stack base
158	 */
159	.macro get_up_stack _name, _size
160	adrp	x0, (\_name + \_size)
161	add	x0, x0, :lo12:(\_name + \_size)
162	.endm
163
164	/*
165	 * Helper macro to generate the best mov/movk combinations according
166	 * the value to be moved. The 16 bits from '_shift' are tested and
167	 * if not zero, they are moved into '_reg' without affecting
168	 * other bits.
169	 */
170	.macro _mov_imm16 _reg, _val, _shift
171		.if (\_val >> \_shift) & 0xffff
172			.if (\_val & (1 << \_shift - 1))
173				movk	\_reg, (\_val >> \_shift) & 0xffff, LSL \_shift
174			.else
175				mov	\_reg, \_val & (0xffff << \_shift)
176			.endif
177		.endif
178	.endm
179
180	/*
181	 * Helper macro to load arbitrary values into 32 or 64-bit registers
182	 * which generates the best mov/movk combinations. Many base addresses
183	 * are 64KB aligned the macro will eliminate updating bits 15:0 in
184	 * that case
185	 */
186	.macro mov_imm _reg, _val
187		.if (\_val) == 0
188			mov	\_reg, #0
189		.else
190			_mov_imm16	\_reg, (\_val), 0
191			_mov_imm16	\_reg, (\_val), 16
192			_mov_imm16	\_reg, (\_val), 32
193			_mov_imm16	\_reg, (\_val), 48
194		.endif
195	.endm
196
197	/*
198	 * Macro to mark instances where we're jumping to a function and don't
199	 * expect a return. To provide the function being jumped to with
200	 * additional information, we use 'bl' instruction to jump rather than
201	 * 'b'.
202         *
203	 * Debuggers infer the location of a call from where LR points to, which
204	 * is usually the instruction after 'bl'. If this macro expansion
205	 * happens to be the last location in a function, that'll cause the LR
206	 * to point a location beyond the function, thereby misleading debugger
207	 * back trace. We therefore insert a 'nop' after the function call for
208	 * debug builds, unless 'skip_nop' parameter is non-zero.
209	 */
210	.macro no_ret _func:req, skip_nop=0
211	bl	\_func
212#if DEBUG
213	.ifeq \skip_nop
214	nop
215	.endif
216#endif
217	.endm
218
219	/*
220	 * Reserve space for a spin lock in assembly file.
221	 */
222	.macro define_asm_spinlock _name:req
223	.align	SPINLOCK_ASM_ALIGN
224	\_name:
225	.space	SPINLOCK_ASM_SIZE
226	.endm
227
228	/*
229	 * Helper macro to read system register value into x0
230	 */
231	.macro	read reg:req
232#if ENABLE_BTI
233	BTI	j
234#endif
235	mrs	x0, \reg
236	ret
237	.endm
238
239	/*
240	 * Helper macro to write value from x1 to system register
241	 */
242	.macro	write reg:req
243#if ENABLE_BTI
244	BTI	j
245#endif
246	msr	\reg, x1
247	ret
248	.endm
249
250	/*
251	 * The "sb" instruction was introduced later into the architecture,
252	 * so not all toolchains understand it. Some deny its usage unless
253	 * a supported processor is specified on the build command line.
254	 * Use sb's system register encoding to work around this, we already
255	 * guard the sb execution with a feature flag.
256	 */
257
258	.macro sb_barrier_insn
259	msr	SYSREG_SB, xzr
260	.endm
261
262	.macro psb_csync
263	hint #17 /* use the hint synonym for compatibility */
264	.endm
265
266	.macro tsb_csync
267	hint #18 /* use the hint synonym for compatibility */
268	.endm
269
270	/*
271	 * Macro for using speculation barrier instruction introduced by
272	 * FEAT_SB, if it's enabled.
273	 */
274	.macro speculation_barrier
275#if ENABLE_FEAT_SB
276	sb_barrier_insn
277#else
278	dsb	sy
279	isb
280#endif
281	.endm
282
283	/*
284	 * Clear Branch History instruction, translates to NOP on CPUs
285	 * that don't implement the clrbhb instruction.
286	 */
287	.macro clrbhb
288	hint	#22
289	.endm
290
291	/*
292	 * Macro for mitigating against speculative execution beyond ERET. Uses the
293	 * speculation barrier instruction introduced by FEAT_SB, if it's enabled.
294	 */
295	.macro exception_return
296	eret
297#if ENABLE_FEAT_SB
298	sb_barrier_insn
299#else
300	dsb	nsh
301	isb
302#endif
303	.endm
304
305	/*
306	 * Macro to unmask External Aborts by changing PSTATE.A bit.
307	 * Put explicit synchronization event to ensure newly unmasked interrupt
308	 * is taken immediately.
309	 */
310	.macro  unmask_async_ea
311	msr     daifclr, #DAIF_ABT_BIT
312	isb
313	.endm
314
315	/* Macro for error synchronization on exception boundries.
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 exception
319	 * entry and exception return, so there is no need for any explicit instruction.
320	 */
321	.macro synchronize_errors
322#if !ENABLE_FEAT_RAS
323	/* Complete any stores that may return an abort */
324	dsb	sy
325	/* Synchronise the CPU context with the completion of the dsb */
326	isb
327#endif
328	.endm
329
330	/*
331	 * Helper macro to instruction adr <reg>, <symbol> where <symbol> is
332	 * within the range +/- 4 GB.
333	 */
334	.macro adr_l, dst, sym
335	adrp	\dst, \sym
336	add	\dst, \dst, :lo12:\sym
337	.endm
338
339	/*
340	* is_feat_XYZ_present_asm - Set flags and reg if FEAT_XYZ
341	* is enabled at runtime.
342	*
343	* Arguments:
344	* reg: Register for temporary use.
345	*
346	* Clobbers: reg
347	*/
348	.macro is_feat_sysreg128_present_asm reg:req
349	mrs	\reg, ID_AA64ISAR2_EL1
350	ands	\reg, \reg, #(ID_AA64ISAR2_SYSREG128_MASK << ID_AA64ISAR2_SYSREG128_SHIFT)
351	.endm
352
353	.macro is_feat_pauth_present_asm reg:req, clobber:req
354	mrs	\reg, ID_AA64ISAR1_EL1
355	mov_imm	\clobber, ((ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) \
356			 | (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT) \
357			 | (ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) \
358			 | (ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT))
359	tst	\reg, \clobber
360	.endm
361
362	.macro is_feat_sctlr2_present_asm reg:req
363	mrs	\reg, ID_AA64MMFR3_EL1
364	ands	\reg, \reg, #(ID_AA64MMFR3_EL1_SCTLR2_MASK << ID_AA64MMFR3_EL1_SCTLR2_SHIFT)
365	.endm
366
367.macro call_reset_handler
368#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && RESET_TO_BL2)
369	/* ---------------------------------------------------------------------
370	 * It is a cold boot.
371	 * Perform any processor specific actions upon reset e.g. cache, TLB
372	 * invalidations etc.
373	 * ---------------------------------------------------------------------
374	 */
375	/* The plat_reset_handler can clobber x0 - x18, x30 */
376	bl	plat_reset_handler
377
378	/* Get the matching cpu_ops pointer */
379	bl	get_cpu_ops_ptr
380
381	/* Get the cpu_ops reset handler */
382	ldr	x2, [x0, #CPU_RESET_FUNC]
383
384	/* The cpu_ops reset handler can clobber x0 - x19, x30 */
385	blr	x2
386#endif
387.endm
388#endif /* ASM_MACROS_S */
389