Skip to content

Commit

Permalink
arm64: Call ARCH_WORKAROUND_2 on transitions between EL0 and EL1
Browse files Browse the repository at this point in the history
In order for the kernel to protect itself, let's call the SSBD mitigation
implemented by the higher exception level (either hypervisor or firmware)
on each transition between userspace and kernel.

We must take the PSCI conduit into account in order to target the
right exception level, hence the introduction of a runtime patching
callback.

Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Julien Grall <julien.grall@arm.com>
Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
  • Loading branch information
Marc Zyngier authored and Catalin Marinas committed May 31, 2018
1 parent eff0e9e commit 8e29062
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
24 changes: 24 additions & 0 deletions arch/arm64/kernel/cpu_errata.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,30 @@ enable_smccc_arch_workaround_1(const struct arm64_cpu_capabilities *entry)
}
#endif /* CONFIG_HARDEN_BRANCH_PREDICTOR */

#ifdef CONFIG_ARM64_SSBD
void __init arm64_update_smccc_conduit(struct alt_instr *alt,
__le32 *origptr, __le32 *updptr,
int nr_inst)
{
u32 insn;

BUG_ON(nr_inst != 1);

switch (psci_ops.conduit) {
case PSCI_CONDUIT_HVC:
insn = aarch64_insn_get_hvc_value();
break;
case PSCI_CONDUIT_SMC:
insn = aarch64_insn_get_smc_value();
break;
default:
return;
}

*updptr = cpu_to_le32(insn);
}
#endif /* CONFIG_ARM64_SSBD */

#define CAP_MIDR_RANGE(model, v_min, r_min, v_max, r_max) \
.matches = is_affected_midr_range, \
.midr_range = MIDR_RANGE(model, v_min, r_min, v_max, r_max)
Expand Down
22 changes: 22 additions & 0 deletions arch/arm64/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <linux/arm-smccc.h>
#include <linux/init.h>
#include <linux/linkage.h>

Expand Down Expand Up @@ -137,6 +138,18 @@ alternative_else_nop_endif
add \dst, \dst, #(\sym - .entry.tramp.text)
.endm

// This macro corrupts x0-x3. It is the caller's duty
// to save/restore them if required.
.macro apply_ssbd, state
#ifdef CONFIG_ARM64_SSBD
mov w0, #ARM_SMCCC_ARCH_WORKAROUND_2
mov w1, #\state
alternative_cb arm64_update_smccc_conduit
nop // Patched to SMC/HVC #0
alternative_cb_end
#endif
.endm

.macro kernel_entry, el, regsize = 64
.if \regsize == 32
mov w0, w0 // zero upper 32 bits of x0
Expand All @@ -163,6 +176,13 @@ alternative_else_nop_endif
ldr x19, [tsk, #TSK_TI_FLAGS] // since we can unmask debug
disable_step_tsk x19, x20 // exceptions when scheduling.

apply_ssbd 1

#ifdef CONFIG_ARM64_SSBD
ldp x0, x1, [sp, #16 * 0]
ldp x2, x3, [sp, #16 * 1]
#endif

mov x29, xzr // fp pointed to user-space
.else
add x21, sp, #S_FRAME_SIZE
Expand Down Expand Up @@ -303,6 +323,8 @@ alternative_if ARM64_WORKAROUND_845719
alternative_else_nop_endif
#endif
3:
apply_ssbd 0

.endif

msr elr_el1, x21 // set up the return data
Expand Down
5 changes: 5 additions & 0 deletions include/linux/arm-smccc.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@
ARM_SMCCC_SMC_32, \
0, 0x8000)

#define ARM_SMCCC_ARCH_WORKAROUND_2 \
ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, \
ARM_SMCCC_SMC_32, \
0, 0x7fff)

#ifndef __ASSEMBLY__

#include <linux/linkage.h>
Expand Down

0 comments on commit 8e29062

Please sign in to comment.