1*91f16700Schasinglulu/* 2*91f16700Schasinglulu * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu#ifndef ASM_MACROS_S 7*91f16700Schasinglulu#define ASM_MACROS_S 8*91f16700Schasinglulu 9*91f16700Schasinglulu#include <arch.h> 10*91f16700Schasinglulu#include <common/asm_macros_common.S> 11*91f16700Schasinglulu#include <lib/spinlock.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu/* 14*91f16700Schasinglulu * TLBI instruction with type specifier that implements the workaround for 15*91f16700Schasinglulu * errata 813419 of Cortex-A57 or errata 1286807 of Cortex-A76. 16*91f16700Schasinglulu */ 17*91f16700Schasinglulu#if ERRATA_A57_813419 || ERRATA_A76_1286807 18*91f16700Schasinglulu#define TLB_INVALIDATE(_type) \ 19*91f16700Schasinglulu tlbi _type; \ 20*91f16700Schasinglulu dsb ish; \ 21*91f16700Schasinglulu tlbi _type 22*91f16700Schasinglulu#else 23*91f16700Schasinglulu#define TLB_INVALIDATE(_type) \ 24*91f16700Schasinglulu tlbi _type 25*91f16700Schasinglulu#endif 26*91f16700Schasinglulu 27*91f16700Schasinglulu 28*91f16700Schasinglulu /* 29*91f16700Schasinglulu * Create a stack frame at the start of an assembly function. Will also 30*91f16700Schasinglulu * add all necessary call frame information (cfi) directives for a 31*91f16700Schasinglulu * pretty stack trace. This is necessary as there is quite a bit of 32*91f16700Schasinglulu * flexibility within a stack frame and the stack pointer can move 33*91f16700Schasinglulu * around throughout the function. If the debugger isn't told where to 34*91f16700Schasinglulu * find things, it gets lost, gives up and displays nothing. So inform 35*91f16700Schasinglulu * the debugger of what's where. Anchor the Canonical Frame Address 36*91f16700Schasinglulu * (CFA; the thing used to track what's where) to the frame pointer as 37*91f16700Schasinglulu * that's not expected to change in the function body and no extra 38*91f16700Schasinglulu * bookkeeping will be necessary, allowing free movement of the sp 39*91f16700Schasinglulu * 40*91f16700Schasinglulu * _frame_size: requested space for caller to use. Must be a mutliple 41*91f16700Schasinglulu * of 16 for stack pointer alignment 42*91f16700Schasinglulu */ 43*91f16700Schasinglulu .macro func_prologue _frame_size=0 44*91f16700Schasinglulu .if \_frame_size & 0xf 45*91f16700Schasinglulu .error "frame_size must have stack pointer alignment (multiple of 16)" 46*91f16700Schasinglulu .endif 47*91f16700Schasinglulu 48*91f16700Schasinglulu /* put frame record at top of frame */ 49*91f16700Schasinglulu stp x29, x30, [sp, #-0x10]! 50*91f16700Schasinglulu mov x29,sp 51*91f16700Schasinglulu .if \_frame_size 52*91f16700Schasinglulu sub sp, sp, #\_frame_size 53*91f16700Schasinglulu .endif 54*91f16700Schasinglulu 55*91f16700Schasinglulu /* point CFA to start of frame record, i.e. x29 + 0x10 */ 56*91f16700Schasinglulu .cfi_def_cfa x29, 0x10 57*91f16700Schasinglulu /* inform it about x29, x30 locations */ 58*91f16700Schasinglulu .cfi_offset x30, -0x8 59*91f16700Schasinglulu .cfi_offset x29, -0x10 60*91f16700Schasinglulu .endm 61*91f16700Schasinglulu 62*91f16700Schasinglulu /* 63*91f16700Schasinglulu * Clear stack frame at the end of an assembly function. 64*91f16700Schasinglulu * 65*91f16700Schasinglulu * _frame_size: the value passed to func_prologue 66*91f16700Schasinglulu */ 67*91f16700Schasinglulu .macro func_epilogue _frame_size=0 68*91f16700Schasinglulu /* remove requested space */ 69*91f16700Schasinglulu .if \_frame_size 70*91f16700Schasinglulu add sp, sp, #\_frame_size 71*91f16700Schasinglulu .endif 72*91f16700Schasinglulu ldp x29, x30, [sp], #0x10 73*91f16700Schasinglulu .endm 74*91f16700Schasinglulu 75*91f16700Schasinglulu 76*91f16700Schasinglulu .macro dcache_line_size reg, tmp 77*91f16700Schasinglulu mrs \tmp, ctr_el0 78*91f16700Schasinglulu ubfx \tmp, \tmp, #16, #4 79*91f16700Schasinglulu mov \reg, #4 80*91f16700Schasinglulu lsl \reg, \reg, \tmp 81*91f16700Schasinglulu .endm 82*91f16700Schasinglulu 83*91f16700Schasinglulu 84*91f16700Schasinglulu .macro icache_line_size reg, tmp 85*91f16700Schasinglulu mrs \tmp, ctr_el0 86*91f16700Schasinglulu and \tmp, \tmp, #0xf 87*91f16700Schasinglulu mov \reg, #4 88*91f16700Schasinglulu lsl \reg, \reg, \tmp 89*91f16700Schasinglulu .endm 90*91f16700Schasinglulu 91*91f16700Schasinglulu 92*91f16700Schasinglulu .macro smc_check label 93*91f16700Schasinglulu mrs x0, esr_el3 94*91f16700Schasinglulu ubfx x0, x0, #ESR_EC_SHIFT, #ESR_EC_LENGTH 95*91f16700Schasinglulu cmp x0, #EC_AARCH64_SMC 96*91f16700Schasinglulu b.ne $label 97*91f16700Schasinglulu .endm 98*91f16700Schasinglulu 99*91f16700Schasinglulu /* 100*91f16700Schasinglulu * Declare the exception vector table, enforcing it is aligned on a 101*91f16700Schasinglulu * 2KB boundary, as required by the ARMv8 architecture. 102*91f16700Schasinglulu * Use zero bytes as the fill value to be stored in the padding bytes 103*91f16700Schasinglulu * so that it inserts illegal AArch64 instructions. This increases 104*91f16700Schasinglulu * security, robustness and potentially facilitates debugging. 105*91f16700Schasinglulu */ 106*91f16700Schasinglulu .macro vector_base label, section_name=.vectors 107*91f16700Schasinglulu .section \section_name, "ax" 108*91f16700Schasinglulu .align 11, 0 109*91f16700Schasinglulu \label: 110*91f16700Schasinglulu .endm 111*91f16700Schasinglulu 112*91f16700Schasinglulu /* 113*91f16700Schasinglulu * Create an entry in the exception vector table, enforcing it is 114*91f16700Schasinglulu * aligned on a 128-byte boundary, as required by the ARMv8 architecture. 115*91f16700Schasinglulu * Use zero bytes as the fill value to be stored in the padding bytes 116*91f16700Schasinglulu * so that it inserts illegal AArch64 instructions. This increases 117*91f16700Schasinglulu * security, robustness and potentially facilitates debugging. 118*91f16700Schasinglulu */ 119*91f16700Schasinglulu .macro vector_entry label, section_name=.vectors 120*91f16700Schasinglulu .cfi_sections .debug_frame 121*91f16700Schasinglulu .section \section_name, "ax" 122*91f16700Schasinglulu .align 7, 0 123*91f16700Schasinglulu .type \label, %function 124*91f16700Schasinglulu .cfi_startproc 125*91f16700Schasinglulu \label: 126*91f16700Schasinglulu .endm 127*91f16700Schasinglulu 128*91f16700Schasinglulu /* 129*91f16700Schasinglulu * Add the bytes until fill the full exception vector, whose size is always 130*91f16700Schasinglulu * 32 instructions. If there are more than 32 instructions in the 131*91f16700Schasinglulu * exception vector then an error is emitted. 132*91f16700Schasinglulu */ 133*91f16700Schasinglulu .macro end_vector_entry label 134*91f16700Schasinglulu .cfi_endproc 135*91f16700Schasinglulu .fill \label + (32 * 4) - . 136*91f16700Schasinglulu .endm 137*91f16700Schasinglulu 138*91f16700Schasinglulu /* 139*91f16700Schasinglulu * This macro calculates the base address of the current CPU's MP stack 140*91f16700Schasinglulu * using the plat_my_core_pos() index, the name of the stack storage 141*91f16700Schasinglulu * and the size of each stack 142*91f16700Schasinglulu * Out: X0 = physical address of stack base 143*91f16700Schasinglulu * Clobber: X30, X1, X2 144*91f16700Schasinglulu */ 145*91f16700Schasinglulu .macro get_my_mp_stack _name, _size 146*91f16700Schasinglulu bl plat_my_core_pos 147*91f16700Schasinglulu adrp x2, (\_name + \_size) 148*91f16700Schasinglulu add x2, x2, :lo12:(\_name + \_size) 149*91f16700Schasinglulu mov x1, #\_size 150*91f16700Schasinglulu madd x0, x0, x1, x2 151*91f16700Schasinglulu .endm 152*91f16700Schasinglulu 153*91f16700Schasinglulu /* 154*91f16700Schasinglulu * This macro calculates the base address of a UP stack using the 155*91f16700Schasinglulu * name of the stack storage and the size of the stack 156*91f16700Schasinglulu * Out: X0 = physical address of stack base 157*91f16700Schasinglulu */ 158*91f16700Schasinglulu .macro get_up_stack _name, _size 159*91f16700Schasinglulu adrp x0, (\_name + \_size) 160*91f16700Schasinglulu add x0, x0, :lo12:(\_name + \_size) 161*91f16700Schasinglulu .endm 162*91f16700Schasinglulu 163*91f16700Schasinglulu /* 164*91f16700Schasinglulu * Helper macro to generate the best mov/movk combinations according 165*91f16700Schasinglulu * the value to be moved. The 16 bits from '_shift' are tested and 166*91f16700Schasinglulu * if not zero, they are moved into '_reg' without affecting 167*91f16700Schasinglulu * other bits. 168*91f16700Schasinglulu */ 169*91f16700Schasinglulu .macro _mov_imm16 _reg, _val, _shift 170*91f16700Schasinglulu .if (\_val >> \_shift) & 0xffff 171*91f16700Schasinglulu .if (\_val & (1 << \_shift - 1)) 172*91f16700Schasinglulu movk \_reg, (\_val >> \_shift) & 0xffff, LSL \_shift 173*91f16700Schasinglulu .else 174*91f16700Schasinglulu mov \_reg, \_val & (0xffff << \_shift) 175*91f16700Schasinglulu .endif 176*91f16700Schasinglulu .endif 177*91f16700Schasinglulu .endm 178*91f16700Schasinglulu 179*91f16700Schasinglulu /* 180*91f16700Schasinglulu * Helper macro to load arbitrary values into 32 or 64-bit registers 181*91f16700Schasinglulu * which generates the best mov/movk combinations. Many base addresses 182*91f16700Schasinglulu * are 64KB aligned the macro will eliminate updating bits 15:0 in 183*91f16700Schasinglulu * that case 184*91f16700Schasinglulu */ 185*91f16700Schasinglulu .macro mov_imm _reg, _val 186*91f16700Schasinglulu .if (\_val) == 0 187*91f16700Schasinglulu mov \_reg, #0 188*91f16700Schasinglulu .else 189*91f16700Schasinglulu _mov_imm16 \_reg, (\_val), 0 190*91f16700Schasinglulu _mov_imm16 \_reg, (\_val), 16 191*91f16700Schasinglulu _mov_imm16 \_reg, (\_val), 32 192*91f16700Schasinglulu _mov_imm16 \_reg, (\_val), 48 193*91f16700Schasinglulu .endif 194*91f16700Schasinglulu .endm 195*91f16700Schasinglulu 196*91f16700Schasinglulu /* 197*91f16700Schasinglulu * Macro to mark instances where we're jumping to a function and don't 198*91f16700Schasinglulu * expect a return. To provide the function being jumped to with 199*91f16700Schasinglulu * additional information, we use 'bl' instruction to jump rather than 200*91f16700Schasinglulu * 'b'. 201*91f16700Schasinglulu * 202*91f16700Schasinglulu * Debuggers infer the location of a call from where LR points to, which 203*91f16700Schasinglulu * is usually the instruction after 'bl'. If this macro expansion 204*91f16700Schasinglulu * happens to be the last location in a function, that'll cause the LR 205*91f16700Schasinglulu * to point a location beyond the function, thereby misleading debugger 206*91f16700Schasinglulu * back trace. We therefore insert a 'nop' after the function call for 207*91f16700Schasinglulu * debug builds, unless 'skip_nop' parameter is non-zero. 208*91f16700Schasinglulu */ 209*91f16700Schasinglulu .macro no_ret _func:req, skip_nop=0 210*91f16700Schasinglulu bl \_func 211*91f16700Schasinglulu#if DEBUG 212*91f16700Schasinglulu .ifeq \skip_nop 213*91f16700Schasinglulu nop 214*91f16700Schasinglulu .endif 215*91f16700Schasinglulu#endif 216*91f16700Schasinglulu .endm 217*91f16700Schasinglulu 218*91f16700Schasinglulu /* 219*91f16700Schasinglulu * Reserve space for a spin lock in assembly file. 220*91f16700Schasinglulu */ 221*91f16700Schasinglulu .macro define_asm_spinlock _name:req 222*91f16700Schasinglulu .align SPINLOCK_ASM_ALIGN 223*91f16700Schasinglulu \_name: 224*91f16700Schasinglulu .space SPINLOCK_ASM_SIZE 225*91f16700Schasinglulu .endm 226*91f16700Schasinglulu 227*91f16700Schasinglulu /* 228*91f16700Schasinglulu * With RAS extension executes esb instruction, else NOP 229*91f16700Schasinglulu */ 230*91f16700Schasinglulu .macro esb 231*91f16700Schasinglulu .inst 0xd503221f 232*91f16700Schasinglulu .endm 233*91f16700Schasinglulu 234*91f16700Schasinglulu /* 235*91f16700Schasinglulu * Helper macro to read system register value into x0 236*91f16700Schasinglulu */ 237*91f16700Schasinglulu .macro read reg:req 238*91f16700Schasinglulu#if ENABLE_BTI 239*91f16700Schasinglulu bti j 240*91f16700Schasinglulu#endif 241*91f16700Schasinglulu mrs x0, \reg 242*91f16700Schasinglulu ret 243*91f16700Schasinglulu .endm 244*91f16700Schasinglulu 245*91f16700Schasinglulu /* 246*91f16700Schasinglulu * Helper macro to write value from x1 to system register 247*91f16700Schasinglulu */ 248*91f16700Schasinglulu .macro write reg:req 249*91f16700Schasinglulu#if ENABLE_BTI 250*91f16700Schasinglulu bti j 251*91f16700Schasinglulu#endif 252*91f16700Schasinglulu msr \reg, x1 253*91f16700Schasinglulu ret 254*91f16700Schasinglulu .endm 255*91f16700Schasinglulu 256*91f16700Schasinglulu /* 257*91f16700Schasinglulu * The "sb" instruction was introduced later into the architecture, 258*91f16700Schasinglulu * so not all toolchains understand it. Some deny its usage unless 259*91f16700Schasinglulu * a supported processor is specified on the build command line. 260*91f16700Schasinglulu * Use sb's system register encoding to work around this, we already 261*91f16700Schasinglulu * guard the sb execution with a feature flag. 262*91f16700Schasinglulu */ 263*91f16700Schasinglulu 264*91f16700Schasinglulu .macro sb_barrier_insn 265*91f16700Schasinglulu msr SYSREG_SB, xzr 266*91f16700Schasinglulu .endm 267*91f16700Schasinglulu 268*91f16700Schasinglulu /* 269*91f16700Schasinglulu * Macro for using speculation barrier instruction introduced by 270*91f16700Schasinglulu * FEAT_SB, if it's enabled. 271*91f16700Schasinglulu */ 272*91f16700Schasinglulu .macro speculation_barrier 273*91f16700Schasinglulu#if ENABLE_FEAT_SB 274*91f16700Schasinglulu sb_barrier_insn 275*91f16700Schasinglulu#else 276*91f16700Schasinglulu dsb sy 277*91f16700Schasinglulu isb 278*91f16700Schasinglulu#endif 279*91f16700Schasinglulu .endm 280*91f16700Schasinglulu 281*91f16700Schasinglulu /* 282*91f16700Schasinglulu * Macro for mitigating against speculative execution beyond ERET. Uses the 283*91f16700Schasinglulu * speculation barrier instruction introduced by FEAT_SB, if it's enabled. 284*91f16700Schasinglulu */ 285*91f16700Schasinglulu .macro exception_return 286*91f16700Schasinglulu eret 287*91f16700Schasinglulu#if ENABLE_FEAT_SB 288*91f16700Schasinglulu sb_barrier_insn 289*91f16700Schasinglulu#else 290*91f16700Schasinglulu dsb nsh 291*91f16700Schasinglulu isb 292*91f16700Schasinglulu#endif 293*91f16700Schasinglulu .endm 294*91f16700Schasinglulu 295*91f16700Schasinglulu /* 296*91f16700Schasinglulu * Macro to unmask External Aborts by changing PSTATE.A bit. 297*91f16700Schasinglulu * Put explicit synchronization event to ensure newly unmasked interrupt 298*91f16700Schasinglulu * is taken immediately. 299*91f16700Schasinglulu */ 300*91f16700Schasinglulu .macro unmask_async_ea 301*91f16700Schasinglulu msr daifclr, #DAIF_ABT_BIT 302*91f16700Schasinglulu isb 303*91f16700Schasinglulu .endm 304*91f16700Schasinglulu 305*91f16700Schasinglulu /* Macro for error synchronization on exception boundries. 306*91f16700Schasinglulu * With FEAT_RAS enabled, it is assumed that FEAT_IESB is also present 307*91f16700Schasinglulu * and enabled. 308*91f16700Schasinglulu * FEAT_IESB provides an implicit error synchronization event at exception 309*91f16700Schasinglulu * entry and exception return, so there is no need for any explicit instruction. 310*91f16700Schasinglulu */ 311*91f16700Schasinglulu .macro synchronize_errors 312*91f16700Schasinglulu#if !ENABLE_FEAT_RAS 313*91f16700Schasinglulu /* Complete any stores that may return an abort */ 314*91f16700Schasinglulu dsb sy 315*91f16700Schasinglulu /* Synchronise the CPU context with the completion of the dsb */ 316*91f16700Schasinglulu isb 317*91f16700Schasinglulu#endif 318*91f16700Schasinglulu .endm 319*91f16700Schasinglulu 320*91f16700Schasinglulu#endif /* ASM_MACROS_S */ 321