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