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: Andrew Scull <ascull@google.com> Signed-off-by: Marc Zyngier <maz@kernel.org> Link: https://lore.kernel.org/r/20200915104643.2543892-19-ascull@google.com
This commit is contained in:
committed by
Marc Zyngier
parent
054698316d
commit
04e4caa8d3
@@ -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_halt_guest(struct kvm *kvm);
|
||||||
void kvm_arm_resume_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, ...) \
|
#define kvm_call_hyp_nvhe(f, ...) \
|
||||||
({ \
|
({ \
|
||||||
struct arm_smccc_res res; \
|
struct arm_smccc_res res; \
|
||||||
|
@@ -13,7 +13,7 @@ obj-$(CONFIG_KVM) += hyp/
|
|||||||
kvm-y := $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o \
|
kvm-y := $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o \
|
||||||
$(KVM)/vfio.o $(KVM)/irqchip.o \
|
$(KVM)/vfio.o $(KVM)/irqchip.o \
|
||||||
arm.o mmu.o mmio.o psci.o perf.o hypercalls.o pvtime.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 \
|
guest.o debug.o reset.o sys_regs.o \
|
||||||
vgic-sys-reg-v3.o fpsimd.o pmu.o \
|
vgic-sys-reg-v3.o fpsimd.o pmu.o \
|
||||||
aarch32.o arch_timer.o \
|
aarch32.o arch_timer.o \
|
||||||
|
@@ -1264,6 +1264,7 @@ static void cpu_init_hyp_mode(void)
|
|||||||
unsigned long hyp_stack_ptr;
|
unsigned long hyp_stack_ptr;
|
||||||
unsigned long vector_ptr;
|
unsigned long vector_ptr;
|
||||||
unsigned long tpidr_el2;
|
unsigned long tpidr_el2;
|
||||||
|
struct arm_smccc_res res;
|
||||||
|
|
||||||
/* Switch from the HYP stub to our own HYP init vector */
|
/* Switch from the HYP stub to our own HYP init vector */
|
||||||
__hyp_set_vectors(kvm_get_idmap_vector());
|
__hyp_set_vectors(kvm_get_idmap_vector());
|
||||||
@@ -1288,7 +1289,9 @@ static void cpu_init_hyp_mode(void)
|
|||||||
* cpus_have_const_cap() wrapper.
|
* cpus_have_const_cap() wrapper.
|
||||||
*/
|
*/
|
||||||
BUG_ON(!system_capabilities_finalized());
|
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
|
* Disabling SSBD on a non-VHE system requires us to enable SSBS
|
||||||
|
@@ -1,22 +0,0 @@
|
|||||||
/* 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)
|
|
@@ -4,11 +4,13 @@
|
|||||||
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
* Author: Marc Zyngier <marc.zyngier@arm.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/arm-smccc.h>
|
||||||
#include <linux/linkage.h>
|
#include <linux/linkage.h>
|
||||||
|
|
||||||
#include <asm/alternative.h>
|
#include <asm/alternative.h>
|
||||||
#include <asm/assembler.h>
|
#include <asm/assembler.h>
|
||||||
#include <asm/kvm_arm.h>
|
#include <asm/kvm_arm.h>
|
||||||
|
#include <asm/kvm_asm.h>
|
||||||
#include <asm/kvm_mmu.h>
|
#include <asm/kvm_mmu.h>
|
||||||
#include <asm/pgtable-hwdef.h>
|
#include <asm/pgtable-hwdef.h>
|
||||||
#include <asm/sysreg.h>
|
#include <asm/sysreg.h>
|
||||||
@@ -44,27 +46,37 @@ __invalid:
|
|||||||
b .
|
b .
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* x0: HYP pgd
|
* x0: SMCCC function ID
|
||||||
* x1: HYP stack
|
* x1: HYP pgd
|
||||||
* x2: HYP vectors
|
* x2: per-CPU offset
|
||||||
* x3: per-CPU offset
|
* x3: HYP stack
|
||||||
|
* x4: HYP vectors
|
||||||
*/
|
*/
|
||||||
__do_hyp_init:
|
__do_hyp_init:
|
||||||
/* Check for a stub HVC call */
|
/* Check for a stub HVC call */
|
||||||
cmp x0, #HVC_STUB_HCALL_NR
|
cmp x0, #HVC_STUB_HCALL_NR
|
||||||
b.lo __kvm_handle_stub_hvc
|
b.lo __kvm_handle_stub_hvc
|
||||||
|
|
||||||
phys_to_ttbr x4, x0
|
/* Set tpidr_el2 for use by HYP to free a register */
|
||||||
alternative_if ARM64_HAS_CNP
|
msr tpidr_el2, x2
|
||||||
orr x4, x4, #TTBR_CNP_BIT
|
|
||||||
alternative_else_nop_endif
|
|
||||||
msr ttbr0_el2, x4
|
|
||||||
|
|
||||||
mrs x4, tcr_el1
|
mov x2, #KVM_HOST_SMCCC_FUNC(__kvm_hyp_init)
|
||||||
mov_q x5, TCR_EL2_MASK
|
cmp x0, x2
|
||||||
and x4, x4, x5
|
b.eq 1f
|
||||||
mov x5, #TCR_EL2_RES1
|
mov x0, #SMCCC_RET_NOT_SUPPORTED
|
||||||
orr x4, x4, x5
|
eret
|
||||||
|
|
||||||
|
1: phys_to_ttbr x0, x1
|
||||||
|
alternative_if ARM64_HAS_CNP
|
||||||
|
orr x0, x0, #TTBR_CNP_BIT
|
||||||
|
alternative_else_nop_endif
|
||||||
|
msr ttbr0_el2, x0
|
||||||
|
|
||||||
|
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
|
* 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.
|
* So use the same T0SZ value we use for the ID map.
|
||||||
*/
|
*/
|
||||||
ldr_l x5, idmap_t0sz
|
ldr_l x1, idmap_t0sz
|
||||||
bfi x4, x5, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH
|
bfi x0, x1, TCR_T0SZ_OFFSET, TCR_TxSZ_WIDTH
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the PS bits in TCR_EL2.
|
* 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
|
mrs x0, mair_el1
|
||||||
msr mair_el2, x4
|
msr mair_el2, x0
|
||||||
isb
|
isb
|
||||||
|
|
||||||
/* Invalidate the stale TLBs from Bootloader */
|
/* 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
|
* as well as the EE bit on BE. Drop the A flag since the compiler
|
||||||
* is allowed to generate unaligned accesses.
|
* is allowed to generate unaligned accesses.
|
||||||
*/
|
*/
|
||||||
mov_q x4, (SCTLR_EL2_RES1 | (SCTLR_ELx_FLAGS & ~SCTLR_ELx_A))
|
mov_q x0, (SCTLR_EL2_RES1 | (SCTLR_ELx_FLAGS & ~SCTLR_ELx_A))
|
||||||
CPU_BE( orr x4, x4, #SCTLR_ELx_EE)
|
CPU_BE( orr x0, x0, #SCTLR_ELx_EE)
|
||||||
alternative_if ARM64_HAS_ADDRESS_AUTH
|
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)
|
SCTLR_ELx_ENDA | SCTLR_ELx_ENDB)
|
||||||
orr x4, x4, x5
|
orr x0, x0, x1
|
||||||
alternative_else_nop_endif
|
alternative_else_nop_endif
|
||||||
msr sctlr_el2, x4
|
msr sctlr_el2, x0
|
||||||
isb
|
isb
|
||||||
|
|
||||||
/* Set the stack and new vectors */
|
/* Set the stack and new vectors */
|
||||||
mov sp, x1
|
mov sp, x3
|
||||||
msr vbar_el2, x2
|
msr vbar_el2, x4
|
||||||
|
|
||||||
/* Set tpidr_el2 for use by HYP */
|
|
||||||
msr tpidr_el2, x3
|
|
||||||
|
|
||||||
/* Hello, World! */
|
/* Hello, World! */
|
||||||
|
mov x0, #SMCCC_RET_SUCCESS
|
||||||
eret
|
eret
|
||||||
SYM_CODE_END(__kvm_hyp_init)
|
SYM_CODE_END(__kvm_hyp_init)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user