Commit 04e4caa8 authored by Andrew Scull's avatar Andrew Scull Committed by Marc Zyngier
Browse files

KVM: arm64: nVHE: Migrate hyp-init to SMCCC



To complete the transition to SMCCC, the hyp initialization is given a
function ID. This looks neater than comparing the hyp stub function IDs
to the page table physical address.

Some care is taken to only clobber x0-3 before the host context is saved
as only those registers can be clobbered accoring to SMCCC. Fortunately,
only a few acrobatics are needed. The possible new tpidr_el2 is moved to
the argument in x2 so that it can be stashed in tpidr_el2 early to free
up a scratch register. The page table configuration then makes use of
x0-2.

Signed-off-by: default avatarAndrew Scull <ascull@google.com>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20200915104643.2543892-19-ascull@google.com
parent 05469831
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -480,11 +480,6 @@ int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
void kvm_arm_halt_guest(struct kvm *kvm);
void kvm_arm_resume_guest(struct kvm *kvm);

u64 __kvm_call_hyp_init(phys_addr_t pgd_ptr,
			unsigned long hyp_stack_ptr,
			unsigned long vector_ptr,
			unsigned long tpidr_el2);

#define kvm_call_hyp_nvhe(f, ...)						\
	({								\
		struct arm_smccc_res res;				\
+1 −1
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@ obj-$(CONFIG_KVM) += hyp/
kvm-y := $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o \
	 $(KVM)/vfio.o $(KVM)/irqchip.o \
	 arm.o mmu.o mmio.o psci.o perf.o hypercalls.o pvtime.o \
	 inject_fault.o regmap.o va_layout.o hyp.o handle_exit.o \
	 inject_fault.o regmap.o va_layout.o handle_exit.o \
	 guest.o debug.o reset.o sys_regs.o \
	 vgic-sys-reg-v3.o fpsimd.o pmu.o \
	 aarch32.o arch_timer.o \
+4 −1
Original line number Diff line number Diff line
@@ -1264,6 +1264,7 @@ static void cpu_init_hyp_mode(void)
	unsigned long hyp_stack_ptr;
	unsigned long vector_ptr;
	unsigned long tpidr_el2;
	struct arm_smccc_res res;

	/* Switch from the HYP stub to our own HYP init vector */
	__hyp_set_vectors(kvm_get_idmap_vector());
@@ -1288,7 +1289,9 @@ static void cpu_init_hyp_mode(void)
	 * cpus_have_const_cap() wrapper.
	 */
	BUG_ON(!system_capabilities_finalized());
	__kvm_call_hyp_init(pgd_ptr, hyp_stack_ptr, vector_ptr, tpidr_el2);
	arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(__kvm_hyp_init),
			  pgd_ptr, tpidr_el2, hyp_stack_ptr, vector_ptr, &res);
	WARN_ON(res.a0 != SMCCC_RET_SUCCESS);

	/*
	 * Disabling SSBD on a non-VHE system requires us to enable SSBS

arch/arm64/kvm/hyp.S

deleted100644 → 0
+0 −22
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (C) 2012,2013 - ARM Ltd
 * Author: Marc Zyngier <marc.zyngier@arm.com>
 */

#include <linux/linkage.h>

#include <asm/alternative.h>
#include <asm/assembler.h>
#include <asm/cpufeature.h>

/*
 * u64 __kvm_call_hyp_init(phys_addr_t pgd_ptr,
 * 			   unsigned long hyp_stack_ptr,
 * 			   unsigned long vector_ptr,
 * 			   unsigned long tpidr_el2);
 */
SYM_FUNC_START(__kvm_call_hyp_init)
	hvc	#0
	ret
SYM_FUNC_END(__kvm_call_hyp_init)
+38 −28
Original line number Diff line number Diff line
@@ -4,11 +4,13 @@
 * Author: Marc Zyngier <marc.zyngier@arm.com>
 */

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

#include <asm/alternative.h>
#include <asm/assembler.h>
#include <asm/kvm_arm.h>
#include <asm/kvm_asm.h>
#include <asm/kvm_mmu.h>
#include <asm/pgtable-hwdef.h>
#include <asm/sysreg.h>
@@ -44,27 +46,37 @@ __invalid:
	b	.

	/*
	 * x0: HYP pgd
	 * x1: HYP stack
	 * x2: HYP vectors
	 * x3: per-CPU offset
	 * x0: SMCCC function ID
	 * x1: HYP pgd
	 * x2: per-CPU offset
	 * x3: HYP stack
	 * x4: HYP vectors
	 */
__do_hyp_init:
	/* Check for a stub HVC call */
	cmp	x0, #HVC_STUB_HCALL_NR
	b.lo	__kvm_handle_stub_hvc

	phys_to_ttbr x4, x0
	/* Set tpidr_el2 for use by HYP to free a register */
	msr	tpidr_el2, x2

	mov	x2, #KVM_HOST_SMCCC_FUNC(__kvm_hyp_init)
	cmp	x0, x2
	b.eq	1f
	mov	x0, #SMCCC_RET_NOT_SUPPORTED
	eret

1:	phys_to_ttbr x0, x1
alternative_if ARM64_HAS_CNP
	orr	x4, x4, #TTBR_CNP_BIT
	orr	x0, x0, #TTBR_CNP_BIT
alternative_else_nop_endif
	msr	ttbr0_el2, x4
	msr	ttbr0_el2, x0

	mrs	x4, tcr_el1
	mov_q	x5, TCR_EL2_MASK
	and	x4, x4, x5
	mov	x5, #TCR_EL2_RES1
	orr	x4, x4, x5
	mrs	x0, tcr_el1
	mov_q	x1, TCR_EL2_MASK
	and	x0, x0, x1
	mov	x1, #TCR_EL2_RES1
	orr	x0, x0, x1

	/*
	 * The ID map may be configured to use an extended virtual address
@@ -80,18 +92,18 @@ alternative_else_nop_endif
	 *
	 * So use the same T0SZ value we use for the ID map.
	 */
	ldr_l	x5, idmap_t0sz
	bfi	x4, x5, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH
	ldr_l	x1, idmap_t0sz
	bfi	x0, x1, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH

	/*
	 * Set the PS bits in TCR_EL2.
	 */
	tcr_compute_pa_size x4, #TCR_EL2_PS_SHIFT, x5, x6
	tcr_compute_pa_size x0, #TCR_EL2_PS_SHIFT, x1, x2

	msr	tcr_el2, x4
	msr	tcr_el2, x0

	mrs	x4, mair_el1
	msr	mair_el2, x4
	mrs	x0, mair_el1
	msr	mair_el2, x0
	isb

	/* Invalidate the stale TLBs from Bootloader */
@@ -103,24 +115,22 @@ alternative_else_nop_endif
	 * as well as the EE bit on BE. Drop the A flag since the compiler
	 * is allowed to generate unaligned accesses.
	 */
	mov_q	x4, (SCTLR_EL2_RES1 | (SCTLR_ELx_FLAGS & ~SCTLR_ELx_A))
CPU_BE(	orr	x4, x4, #SCTLR_ELx_EE)
	mov_q	x0, (SCTLR_EL2_RES1 | (SCTLR_ELx_FLAGS & ~SCTLR_ELx_A))
CPU_BE(	orr	x0, x0, #SCTLR_ELx_EE)
alternative_if ARM64_HAS_ADDRESS_AUTH
	mov_q	x5, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \
	mov_q	x1, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \
		     SCTLR_ELx_ENDA | SCTLR_ELx_ENDB)
	orr	x4, x4, x5
	orr	x0, x0, x1
alternative_else_nop_endif
	msr	sctlr_el2, x4
	msr	sctlr_el2, x0
	isb

	/* Set the stack and new vectors */
	mov	sp, x1
	msr	vbar_el2, x2

	/* Set tpidr_el2 for use by HYP */
	msr	tpidr_el2, x3
	mov	sp, x3
	msr	vbar_el2, x4

	/* Hello, World! */
	mov	x0, #SMCCC_RET_SUCCESS
	eret
SYM_CODE_END(__kvm_hyp_init)