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