1*91f16700Schasinglulu/* 2*91f16700Schasinglulu * Copyright (c) 2016-2023, 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/cpus/cpu_ops.h> 12*91f16700Schasinglulu#include <lib/spinlock.h> 13*91f16700Schasinglulu 14*91f16700Schasinglulu/* 15*91f16700Schasinglulu * TLBI instruction with type specifier that implements the workaround for 16*91f16700Schasinglulu * errata 813419 of Cortex-A57. 17*91f16700Schasinglulu */ 18*91f16700Schasinglulu#if ERRATA_A57_813419 19*91f16700Schasinglulu#define TLB_INVALIDATE(_reg, _coproc) \ 20*91f16700Schasinglulu stcopr _reg, _coproc; \ 21*91f16700Schasinglulu dsb ish; \ 22*91f16700Schasinglulu stcopr _reg, _coproc 23*91f16700Schasinglulu#else 24*91f16700Schasinglulu#define TLB_INVALIDATE(_reg, _coproc) \ 25*91f16700Schasinglulu stcopr _reg, _coproc 26*91f16700Schasinglulu#endif 27*91f16700Schasinglulu 28*91f16700Schasinglulu /* 29*91f16700Schasinglulu * Co processor register accessors 30*91f16700Schasinglulu */ 31*91f16700Schasinglulu .macro ldcopr reg, coproc, opc1, CRn, CRm, opc2 32*91f16700Schasinglulu mrc \coproc, \opc1, \reg, \CRn, \CRm, \opc2 33*91f16700Schasinglulu .endm 34*91f16700Schasinglulu 35*91f16700Schasinglulu .macro ldcopr16 reg1, reg2, coproc, opc1, CRm 36*91f16700Schasinglulu mrrc \coproc, \opc1, \reg1, \reg2, \CRm 37*91f16700Schasinglulu .endm 38*91f16700Schasinglulu 39*91f16700Schasinglulu .macro stcopr reg, coproc, opc1, CRn, CRm, opc2 40*91f16700Schasinglulu mcr \coproc, \opc1, \reg, \CRn, \CRm, \opc2 41*91f16700Schasinglulu .endm 42*91f16700Schasinglulu 43*91f16700Schasinglulu .macro stcopr16 reg1, reg2, coproc, opc1, CRm 44*91f16700Schasinglulu mcrr \coproc, \opc1, \reg1, \reg2, \CRm 45*91f16700Schasinglulu .endm 46*91f16700Schasinglulu 47*91f16700Schasinglulu /* Cache line size helpers */ 48*91f16700Schasinglulu .macro dcache_line_size reg, tmp 49*91f16700Schasinglulu ldcopr \tmp, CTR 50*91f16700Schasinglulu ubfx \tmp, \tmp, #CTR_DMINLINE_SHIFT, #CTR_DMINLINE_WIDTH 51*91f16700Schasinglulu mov \reg, #CPU_WORD_SIZE 52*91f16700Schasinglulu lsl \reg, \reg, \tmp 53*91f16700Schasinglulu .endm 54*91f16700Schasinglulu 55*91f16700Schasinglulu .macro icache_line_size reg, tmp 56*91f16700Schasinglulu ldcopr \tmp, CTR 57*91f16700Schasinglulu and \tmp, \tmp, #CTR_IMINLINE_MASK 58*91f16700Schasinglulu mov \reg, #CPU_WORD_SIZE 59*91f16700Schasinglulu lsl \reg, \reg, \tmp 60*91f16700Schasinglulu .endm 61*91f16700Schasinglulu 62*91f16700Schasinglulu /* 63*91f16700Schasinglulu * Declare the exception vector table, enforcing it is aligned on a 64*91f16700Schasinglulu * 32 byte boundary. 65*91f16700Schasinglulu */ 66*91f16700Schasinglulu .macro vector_base label 67*91f16700Schasinglulu .section .vectors, "ax" 68*91f16700Schasinglulu .align 5 69*91f16700Schasinglulu \label: 70*91f16700Schasinglulu .endm 71*91f16700Schasinglulu 72*91f16700Schasinglulu /* 73*91f16700Schasinglulu * This macro calculates the base address of the current CPU's multi 74*91f16700Schasinglulu * processor(MP) stack using the plat_my_core_pos() index, the name of 75*91f16700Schasinglulu * the stack storage and the size of each stack. 76*91f16700Schasinglulu * Out: r0 = physical address of stack base 77*91f16700Schasinglulu * Clobber: r14, r1, r2 78*91f16700Schasinglulu */ 79*91f16700Schasinglulu .macro get_my_mp_stack _name, _size 80*91f16700Schasinglulu bl plat_my_core_pos 81*91f16700Schasinglulu ldr r2, =(\_name + \_size) 82*91f16700Schasinglulu mov r1, #\_size 83*91f16700Schasinglulu mla r0, r0, r1, r2 84*91f16700Schasinglulu .endm 85*91f16700Schasinglulu 86*91f16700Schasinglulu /* 87*91f16700Schasinglulu * This macro calculates the base address of a uniprocessor(UP) stack 88*91f16700Schasinglulu * using the name of the stack storage and the size of the stack 89*91f16700Schasinglulu * Out: r0 = physical address of stack base 90*91f16700Schasinglulu */ 91*91f16700Schasinglulu .macro get_up_stack _name, _size 92*91f16700Schasinglulu ldr r0, =(\_name + \_size) 93*91f16700Schasinglulu .endm 94*91f16700Schasinglulu 95*91f16700Schasinglulu#if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION) 96*91f16700Schasinglulu /* 97*91f16700Schasinglulu * Macro for mitigating against speculative execution. 98*91f16700Schasinglulu * ARMv7 cores without Virtualization extension do not support the 99*91f16700Schasinglulu * eret instruction. 100*91f16700Schasinglulu */ 101*91f16700Schasinglulu .macro exception_return 102*91f16700Schasinglulu movs pc, lr 103*91f16700Schasinglulu dsb nsh 104*91f16700Schasinglulu isb 105*91f16700Schasinglulu .endm 106*91f16700Schasinglulu 107*91f16700Schasinglulu#else 108*91f16700Schasinglulu /* 109*91f16700Schasinglulu * Macro for mitigating against speculative execution beyond ERET. Uses the 110*91f16700Schasinglulu * speculation barrier instruction introduced by FEAT_SB, if it's enabled. 111*91f16700Schasinglulu */ 112*91f16700Schasinglulu .macro exception_return 113*91f16700Schasinglulu eret 114*91f16700Schasinglulu#if ENABLE_FEAT_SB 115*91f16700Schasinglulu sb 116*91f16700Schasinglulu#else 117*91f16700Schasinglulu dsb nsh 118*91f16700Schasinglulu isb 119*91f16700Schasinglulu#endif 120*91f16700Schasinglulu .endm 121*91f16700Schasinglulu#endif 122*91f16700Schasinglulu 123*91f16700Schasinglulu /* Macro for error synchronization */ 124*91f16700Schasinglulu .macro synchronize_errors 125*91f16700Schasinglulu /* Complete any stores that may return an abort */ 126*91f16700Schasinglulu dsb sy 127*91f16700Schasinglulu /* Synchronise the CPU context with the completion of the dsb */ 128*91f16700Schasinglulu isb 129*91f16700Schasinglulu .endm 130*91f16700Schasinglulu 131*91f16700Schasinglulu#if (ARM_ARCH_MAJOR == 7) 132*91f16700Schasinglulu /* ARMv7 does not support stl instruction */ 133*91f16700Schasinglulu .macro stl _reg, _write_lock 134*91f16700Schasinglulu dmb 135*91f16700Schasinglulu str \_reg, \_write_lock 136*91f16700Schasinglulu dsb 137*91f16700Schasinglulu .endm 138*91f16700Schasinglulu#endif 139*91f16700Schasinglulu 140*91f16700Schasinglulu /* 141*91f16700Schasinglulu * Helper macro to generate the best mov/movw/movt combinations 142*91f16700Schasinglulu * according to the value to be moved. 143*91f16700Schasinglulu */ 144*91f16700Schasinglulu .macro mov_imm _reg, _val 145*91f16700Schasinglulu .if ((\_val) & 0xffff0000) == 0 146*91f16700Schasinglulu mov \_reg, #(\_val) 147*91f16700Schasinglulu .else 148*91f16700Schasinglulu movw \_reg, #((\_val) & 0xffff) 149*91f16700Schasinglulu movt \_reg, #((\_val) >> 16) 150*91f16700Schasinglulu .endif 151*91f16700Schasinglulu .endm 152*91f16700Schasinglulu 153*91f16700Schasinglulu /* 154*91f16700Schasinglulu * Macro to mark instances where we're jumping to a function and don't 155*91f16700Schasinglulu * expect a return. To provide the function being jumped to with 156*91f16700Schasinglulu * additional information, we use 'bl' instruction to jump rather than 157*91f16700Schasinglulu * 'b'. 158*91f16700Schasinglulu * 159*91f16700Schasinglulu * Debuggers infer the location of a call from where LR points to, which 160*91f16700Schasinglulu * is usually the instruction after 'bl'. If this macro expansion 161*91f16700Schasinglulu * happens to be the last location in a function, that'll cause the LR 162*91f16700Schasinglulu * to point a location beyond the function, thereby misleading debugger 163*91f16700Schasinglulu * back trace. We therefore insert a 'nop' after the function call for 164*91f16700Schasinglulu * debug builds, unless 'skip_nop' parameter is non-zero. 165*91f16700Schasinglulu */ 166*91f16700Schasinglulu .macro no_ret _func:req, skip_nop=0 167*91f16700Schasinglulu bl \_func 168*91f16700Schasinglulu#if DEBUG 169*91f16700Schasinglulu .ifeq \skip_nop 170*91f16700Schasinglulu nop 171*91f16700Schasinglulu .endif 172*91f16700Schasinglulu#endif 173*91f16700Schasinglulu .endm 174*91f16700Schasinglulu 175*91f16700Schasinglulu /* 176*91f16700Schasinglulu * Reserve space for a spin lock in assembly file. 177*91f16700Schasinglulu */ 178*91f16700Schasinglulu .macro define_asm_spinlock _name:req 179*91f16700Schasinglulu .align SPINLOCK_ASM_ALIGN 180*91f16700Schasinglulu \_name: 181*91f16700Schasinglulu .space SPINLOCK_ASM_SIZE 182*91f16700Schasinglulu .endm 183*91f16700Schasinglulu 184*91f16700Schasinglulu /* 185*91f16700Schasinglulu * Helper macro to OR the bottom 32 bits of `_val` into `_reg_l` 186*91f16700Schasinglulu * and the top 32 bits of `_val` into `_reg_h`. If either the bottom 187*91f16700Schasinglulu * or top word of `_val` is zero, the corresponding OR operation 188*91f16700Schasinglulu * is skipped. 189*91f16700Schasinglulu */ 190*91f16700Schasinglulu .macro orr64_imm _reg_l, _reg_h, _val 191*91f16700Schasinglulu .if (\_val >> 32) 192*91f16700Schasinglulu orr \_reg_h, \_reg_h, #(\_val >> 32) 193*91f16700Schasinglulu .endif 194*91f16700Schasinglulu .if (\_val & 0xffffffff) 195*91f16700Schasinglulu orr \_reg_l, \_reg_l, #(\_val & 0xffffffff) 196*91f16700Schasinglulu .endif 197*91f16700Schasinglulu .endm 198*91f16700Schasinglulu 199*91f16700Schasinglulu /* 200*91f16700Schasinglulu * Helper macro to bitwise-clear bits in `_reg_l` and 201*91f16700Schasinglulu * `_reg_h` given a 64 bit immediate `_val`. The set bits 202*91f16700Schasinglulu * in the bottom word of `_val` dictate which bits from 203*91f16700Schasinglulu * `_reg_l` should be cleared. Similarly, the set bits in 204*91f16700Schasinglulu * the top word of `_val` dictate which bits from `_reg_h` 205*91f16700Schasinglulu * should be cleared. If either the bottom or top word of 206*91f16700Schasinglulu * `_val` is zero, the corresponding BIC operation is skipped. 207*91f16700Schasinglulu */ 208*91f16700Schasinglulu .macro bic64_imm _reg_l, _reg_h, _val 209*91f16700Schasinglulu .if (\_val >> 32) 210*91f16700Schasinglulu bic \_reg_h, \_reg_h, #(\_val >> 32) 211*91f16700Schasinglulu .endif 212*91f16700Schasinglulu .if (\_val & 0xffffffff) 213*91f16700Schasinglulu bic \_reg_l, \_reg_l, #(\_val & 0xffffffff) 214*91f16700Schasinglulu .endif 215*91f16700Schasinglulu .endm 216*91f16700Schasinglulu 217*91f16700Schasinglulu /* 218*91f16700Schasinglulu * Helper macro for carrying out division in software when 219*91f16700Schasinglulu * hardware division is not suported. \top holds the dividend 220*91f16700Schasinglulu * in the function call and the remainder after 221*91f16700Schasinglulu * the function is executed. \bot holds the divisor. \div holds 222*91f16700Schasinglulu * the quotient and \temp is a temporary registed used in calcualtion. 223*91f16700Schasinglulu * The division algorithm has been obtained from: 224*91f16700Schasinglulu * http://www.keil.com/support/man/docs/armasm/armasm_dom1359731155623.htm 225*91f16700Schasinglulu */ 226*91f16700Schasinglulu .macro softudiv div:req,top:req,bot:req,temp:req 227*91f16700Schasinglulu 228*91f16700Schasinglulu mov \temp, \bot 229*91f16700Schasinglulu cmp \temp, \top, lsr #1 230*91f16700Schasingluludiv1: 231*91f16700Schasinglulu movls \temp, \temp, lsl #1 232*91f16700Schasinglulu cmp \temp, \top, lsr #1 233*91f16700Schasinglulu bls div1 234*91f16700Schasinglulu mov \div, #0 235*91f16700Schasinglulu 236*91f16700Schasingluludiv2: 237*91f16700Schasinglulu cmp \top, \temp 238*91f16700Schasinglulu subcs \top, \top,\temp 239*91f16700Schasinglulu ADC \div, \div, \div 240*91f16700Schasinglulu mov \temp, \temp, lsr #1 241*91f16700Schasinglulu cmp \temp, \bot 242*91f16700Schasinglulu bhs div2 243*91f16700Schasinglulu .endm 244*91f16700Schasinglulu#endif /* ASM_MACROS_S */ 245