/* * Copyright (c) 2026, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl wa_cve_2025_0647_instruction_patch .globl wa_cve_2025_0647_do_cpp_wa .globl wa_cve_2025_0647_execute_cpp_el3 /* * wa_cve_2025_0647_instruction_patch * * Function to enable EL3 traps for all CPP RCTX instruction calls from lower * ELs to address CVE-2025-0647. * * Argument * x0 - bit[3] flag to use T32 opcode format * bit[2:0] patch slot to use * * Clobbers * x0 - x3 */ func wa_cve_2025_0647_instruction_patch /* Check bit 3 to see if we need T32 opcode format. */ tbnz x0, #WA_USE_T32_OPCODE_SHIFT, use_t32_opcode ldr x2, =0x00D50B73E0 ldr x3, =0x00FFFFFFE0 b apply_patch use_t32_opcode: ldr x2, =0x00EE670DF3 ldr x3, =0x00FFFF0FFF apply_patch: and x1, x0, #WA_PATCH_SLOT_MASK msr WA_CPUPSELR_EL3, x1 msr WA_CPUPOR_EL3, x2 msr WA_CPUPMR_EL3, x3 ldr x1, =0x800002001FF msr WA_CPUPCR_EL3, x1 isb ret endfunc wa_cve_2025_0647_instruction_patch /* * wa_cve_2025_0647_do_cpp_wa * * This function is also called by the trap handler when CPP RCTX is trapped * from lower ELs and also used by the EL3 API when the workaround is enabled. * It performs the core workaround procedure for the CPP RCTX bug. The CPP RCTX * instruction usually takes an argument in the form of a register but that is * ignored for this workaround. * * Arguments * x0 - Config flags for the workaround * bit[0] - indicates context is a trap handler and should ERET when done * bit[1] - perform ls rcg alwayson workaround * * Clobbers * x0 - x5 * * Register Purposes * x0 - Config flags * x1 - Backup SCR_EL3 * x2 - Backup CPUACTLR2 * x3 - Backup CPUACTLR * x4 - Backup CPUECTLR * x5 - Scratch register */ func wa_cve_2025_0647_do_cpp_wa psb csync tsb csync dsb osh /* Stash SCR_EL3 so we can restore it later. */ mrs x1, SCR_EL3 /* * There is an issue on some cores where disabling hardware prefetch can * result in a deadlock, setting this bit enables LS RCG AlwaysOn which * will prevent this issue, at the expense of increased power consumption * for the duration of this handler. */ tbz x0, #WA_LS_RCG_EN_BIT, skip_ls_rcg_alwayson_enable mrs x2, WA_CPUACTLR2_EL1 orr x5, x2, #BIT(29) msr WA_CPUACTLR2_EL1, x5 isb skip_ls_rcg_alwayson_enable: /* Disable branch prediction and stash CPUACTLR_EL1 in x3. */ mrs x3, WA_CPUACTLR_EL1 orr x5, x3, #BIT(0) msr WA_CPUACTLR_EL1, x5 /* Disable hardware prefetch and stash CPUECTLR_EL1 in x4. */ mrs x4, WA_CPUECTLR_EL1 orr x5, x4, #BIT(15) msr WA_CPUECTLR_EL1, x5 isb /* * Execute CPP instruction for EL3 / root state * EL3_rt: 0x000100000b010000 {GVMID,NSE,NS,EL,GASID} = {1,1,0,11,1} */ movz x5, #0x0001, LSL #48 movk x5, #0x0B01, LSL #16 cpp rctx, x5 #if ENABLE_RME /* * Execute CPP instructions for realm state * RL-EL2: 0x000100000e010000 {GVMID,NSE,NS,EL,GASID} = {1,1,1,10,1} */ movk x5, #0x0E01, LSL #16 cpp rctx, x5 /* RL-EL1: 0x000100000d010000 {GVMID,NSE,NS,EL,GASID} = {1,1,1,01,1} */ movk x5, #0x0D01, LSL #16 cpp rctx, x5 /* RL-EL0: 0x000100000c010000 {GVMID,NSE,NS,EL,GASID} = {1,1,1,00,1} */ movk x5, #0x0C01, LSL #16 cpp rctx, x5 #endif /* ENABLE_RME */ /* * Execute CPP instructions for non-secure state * EL2_ns: 0x0001000006010000 {GVMID,NSE,NS,EL,GASID} = {1,0,1,10,1} */ movk x5, #0x0601, LSL #16 cpp rctx, x5 /* NS-EL1: 0x0001000005010000 {GVMID,NSE,NS,EL,GASID} = {1,0,1,01,1} */ movk x5, #0x0501, LSL #16 cpp rctx, x5 /* NS-EL0: 0x0001000004010000 {GVMID,NSE,NS,EL,GASID} = {1,0,1,00,1} */ movk x5, #0x0401, LSL #16 cpp rctx, x5 /* * Execute CPP instructions for secure state * EL1_s: 0x0001000001010000 {GVMID,NSE,NS,EL,GASID} = {1,0,0,01,1} */ movk x5, #0x0101, LSL #16 cpp rctx, x5 /* S-EL0: 0x0001000000010000 {GVMID,NSE,NS,EL,GASID} = {1,0,0,00,1} */ movk x5, #0x0001, LSL #16 cpp rctx, x5 /* Check secure EL2 presence */ tbz x1, #SCR_EEL2_SHIFT, el3_handler_skip_sel2_cpp /* S-EL2: 0x0001000002010000 {GVMID,NSE,NS,EL,GASID} = {1,0,0,10,1} */ movk x5, #0x0201, LSL #16 cpp rctx, x5 el3_handler_skip_sel2_cpp: dsb sy /* EL3 / root state TLBI */ tlbi alle3 #if ENABLE_RME /* Realm state TLBI {NSE,NS} = {1,1} */ orr x5, x1, #SCR_NS_BIT orr x5, x5, #SCR_NSE_BIT msr SCR_EL3, x5 isb tlbi alle1 tlbi alle2 #endif /* ENABLE_RME */ /* Non-secure state TLBI {NSE,NS} = {0,1} */ orr x5, x1, #SCR_NS_BIT bic x5, x5, #SCR_NSE_BIT msr SCR_EL3, x5 isb tlbi alle1 tlbi alle2 /* Secure state TLBI {NSE,NS} = {0,0} */ bic x5, x5, #SCR_NS_BIT msr SCR_EL3, x5 isb tlbi alle1 /* Check if we need to invalidate for S-EL2. */ tbz x1, #SCR_EEL2_SHIFT, el3_handler_skip_sel2_tlbi tlbi alle2 el3_handler_skip_sel2_tlbi: /* Clean up and restore register values. */ dsb sy msr SCR_EL3, x1 /* Restore ECTLR and ACTLR values. */ msr WA_CPUACTLR_EL1, x3 msr WA_CPUECTLR_EL1, x4 isb /* Restore ACTLR2 if needed. */ tbz x0, #WA_LS_RCG_EN_BIT, skip_ls_rcg_alwayson_disable msr WA_CPUACTLR2_EL1, x2 isb skip_ls_rcg_alwayson_disable: /* Skip ERET if this is not an exception handler call. */ tbz x0, #WA_IS_TRAP_HANDLER_BIT, skip_eret /* * Update ELR_EL3 to skip the triggering instruction */ mrs x5, ELR_EL3 add x5, x5, #4 msr ELR_EL3, x5 /* Restore context and ERET */ ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] ldp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] exception_return skip_eret: ret endfunc wa_cve_2025_0647_do_cpp_wa /* * wa_cve_2025_0647_execute_cpp_el3 * * If a CPP RCTX instruction is needed in EL3 firmware this API can be used. It * performs the workaround steps without requiring a trap or exception handling * overhead and simplifies the code since we do not generally support nested * exceptions in EL3 outside of specific circumstances. * * Arguments * x0 - CPP RCTX argument to use when the workaround is not needed, this * argument is ignored on systems with the workaround enabled since * the workaround procedure does not use the argument and does CPP RCTX * for all contexts. This is here for compatibility in multi-core * systems where some cores might need this workaround and others do not. * * Clobbers * x0 - x7 */ func wa_cve_2025_0647_execute_cpp_el3 mov x7, x0 mov x6, lr /* Get the CPU ops so we can access the trap handler. */ bl get_cpu_ops_ptr mov lr, x6 ldr x0, [x0, #CPU_E_HANDLER_FUNC] /* If no handler exists, skip the workaround as its not enabled. */ cbz x0, skip_wa /* * The EL3 handler expects x1 to contain EC=0x1F when handling a trap, * so clear x1 so it knows it came from this API instead. */ mov x1, #0 br x0 skip_wa: cpp rctx, x7 ret endfunc wa_cve_2025_0647_execute_cpp_el3