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#if ENABLE_FEAT_SB 279 // todo feat state 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#if ENABLE_FEAT_SB 302 sb_barrier_insn 303#else 304 dsb nsh 305 isb 306#endif 307 .endm 308 309 /* 310 * Macro to unmask External Aborts by changing PSTATE.A bit. 311 * Put explicit synchronization event to ensure newly unmasked interrupt 312 * is taken immediately. 313 */ 314 .macro unmask_async_ea 315 msr daifclr, #DAIF_ABT_BIT 316 isb 317 .endm 318 319 /* 320 * Macro for error synchronization on exception boundaries. 321 * With FEAT_RAS enabled, it is assumed that FEAT_IESB is also present 322 * and enabled. 323 * FEAT_IESB provides an implicit error synchronization event at 324 * exception entry and exception return, so there is no need for any 325 * explicit instruction. In the FEAT_STATE_CHECKED case the explicit 326 * synchronisation will be done anyway because there isn't enough space 327 * in the exception vectors to do the check. Any platform looking for 328 * maximum performance should not use FEAT_STATE_CHECKED. 329 */ 330 .macro synchronize_errors 331#if ENABLE_FEAT_RAS == 0 || ENABLE_FEAT_RAS == 2 332 /* Complete any stores that may return an abort */ 333 dsb sy 334 /* Synchronise the CPU context with the completion of the dsb */ 335 isb 336#endif 337 .endm 338 339 /* 340 * Helper macro to instruction adr <reg>, <symbol> where <symbol> is 341 * within the range +/- 4 GB. 342 */ 343 .macro adr_l, dst, sym 344 adrp \dst, \sym 345 add \dst, \dst, :lo12:\sym 346 .endm 347 348 /* 349 * is_feat_XYZ_present_asm - Set flags and reg if FEAT_XYZ 350 * is enabled at runtime. 351 * 352 * Arguments: 353 * reg: Register for temporary use. 354 * 355 * Clobbers: reg 356 */ 357 .macro is_feat_sysreg128_present_asm reg:req 358 mrs \reg, ID_AA64ISAR2_EL1 359 ands \reg, \reg, #(ID_AA64ISAR2_SYSREG128_MASK << ID_AA64ISAR2_SYSREG128_SHIFT) 360 .endm 361 362 .macro is_feat_pauth_present_asm reg:req, clobber:req 363 mrs \reg, ID_AA64ISAR1_EL1 364 mov_imm \clobber, ((ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) \ 365 | (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT) \ 366 | (ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) \ 367 | (ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT)) 368 tst \reg, \clobber 369 .endm 370 371 .macro is_feat_sctlr2_present_asm reg:req 372 mrs \reg, ID_AA64MMFR3_EL1 373 ands \reg, \reg, #(ID_AA64MMFR3_EL1_SCTLR2_MASK << ID_AA64MMFR3_EL1_SCTLR2_SHIFT) 374 .endm 375 376 .macro is_feat_sme_present_asm reg:req 377 mrs \reg, id_aa64pfr1_el1 378 ands \reg, \reg, #(ID_AA64PFR1_EL1_SME_MASK << ID_AA64PFR1_EL1_SME_SHIFT) 379 .endm 380 381 .macro is_feat_amu_present_asm reg:req 382 mrs \reg, ID_AA64PFR0_EL1 383 ands \reg, \reg, #(ID_AA64PFR0_AMU_MASK << ID_AA64PFR0_AMU_SHIFT) 384 .endm 385 386 /* 387 * There are various places where Morello requires simple switchovers for 388 * system registers. For eg morello uses celr_el3 vs elr_el3, cvbar_el3 vs 389 * vbar_el3 etc., this macro simplifies that operation and makes the code 390 * more readable. 391 */ 392 .macro msr_wide_reg _sysreg:req, _gp_reg:req 393#if ENABLE_FEAT_MORELLO 394#if ENABLE_FEAT_MORELLO == 2 395 is_feat_morello_present_asm x10 396 beq 1f 397#endif /* ENABLE_FEAT_MORELLO == 2 */ 398 cvtp c\_gp_reg, x\_gp_reg 399 msr c\_sysreg, c\_gp_reg 400 b 2f 4011: 402#endif /* ENABLE_FEAT_MORELLO */ 403#if ENABLE_FEAT_MORELLO != 1 404 msr \_sysreg, x\_gp_reg 405#endif /* ENABLE_FEAT_MORELLO != 1 */ 4062: 407 .endm 408 409.macro call_reset_handler 410#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && RESET_TO_BL2) 411 /* --------------------------------------------------------------------- 412 * It is a cold boot. 413 * Perform any processor specific actions upon reset e.g. cache, TLB 414 * invalidations etc. 415 * --------------------------------------------------------------------- 416 */ 417 /* The plat_reset_handler can clobber x0 - x18, x30 */ 418 bl plat_reset_handler 419 420 /* Get the matching cpu_ops pointer */ 421 bl get_cpu_ops_ptr 422 423 /* Get the cpu_ops reset handler */ 424 ldr x2, [x0, #CPU_RESET_FUNC] 425 426 /* The cpu_ops reset handler can clobber x0 - x19, x30 */ 427 blr x2 428#endif 429.endm 430#endif /* ASM_MACROS_S */ 431