Commit 0d3b2b4d authored by Oliver Upton's avatar Oliver Upton
Browse files

Merge branch kvm-arm64/nv-prefix into kvmarm/next



* kvm-arm64/nv-prefix:
  : Preamble to NV support, courtesy of Marc Zyngier.
  :
  : This brings in a set of prerequisite patches for supporting nested
  : virtualization in KVM/arm64. Of course, there is a long way to go until
  : NV is actually enabled in KVM.
  :
  :  - Introduce cpucap / vCPU feature flag to pivot the NV code on
  :
  :  - Add support for EL2 vCPU register state
  :
  :  - Basic nested exception handling
  :
  :  - Hide unsupported features from the ID registers for NV-capable VMs
  KVM: arm64: nv: Use reg_to_encoding() to get sysreg ID
  KVM: arm64: nv: Only toggle cache for virtual EL2 when SCTLR_EL2 changes
  KVM: arm64: nv: Filter out unsupported features from ID regs
  KVM: arm64: nv: Emulate EL12 register accesses from the virtual EL2
  KVM: arm64: nv: Allow a sysreg to be hidden from userspace only
  KVM: arm64: nv: Emulate PSTATE.M for a guest hypervisor
  KVM: arm64: nv: Add accessors for SPSR_EL1, ELR_EL1 and VBAR_EL1 from virtual EL2
  KVM: arm64: nv: Handle SMCs taken from virtual EL2
  KVM: arm64: nv: Handle trapped ERET from virtual EL2
  KVM: arm64: nv: Inject HVC exceptions to the virtual EL2
  KVM: arm64: nv: Support virtual EL2 exceptions
  KVM: arm64: nv: Handle HCR_EL2.NV system register traps
  KVM: arm64: nv: Add nested virt VCPU primitives for vEL2 VCPU state
  KVM: arm64: nv: Add EL2 system registers to vcpu context
  KVM: arm64: nv: Allow userspace to set PSR_MODE_EL2x
  KVM: arm64: nv: Reset VCPU to EL2 registers if VCPU nested virt is set
  KVM: arm64: nv: Introduce nested virtualization VCPU feature
  KVM: arm64: Use the S2 MMU context to iterate over S2 table
  arm64: Add ARM64_HAS_NESTED_VIRT cpufeature

Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parents 022d3f08 3fb901cd
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -2553,9 +2553,14 @@
			protected: nVHE-based mode with support for guests whose
				   state is kept private from the host.

			nested: VHE-based mode with support for nested
				virtualization. Requires at least ARMv8.3
				hardware.

			Defaults to VHE/nVHE based on hardware support. Setting
			mode to "protected" will disable kexec and hibernation
			for the host.
			for the host. "nested" is experimental and should be
			used with extreme caution.

	kvm-arm.vgic_v3_group0_trap=
			[KVM,ARM] Trap guest accesses to GICv3 group-0
+4 −0
Original line number Diff line number Diff line
@@ -272,6 +272,10 @@
		(((e) & ESR_ELx_SYS64_ISS_OP2_MASK) >>		\
		 ESR_ELx_SYS64_ISS_OP2_SHIFT))

/* ISS field definitions for ERET/ERETAA/ERETAB trapping */
#define ESR_ELx_ERET_ISS_ERET		0x2
#define ESR_ELx_ERET_ISS_ERETA		0x1

/*
 * ISS field definitions for floating-point exception traps
 * (FP_EXC_32/FP_EXC_64).
+18 −1
Original line number Diff line number Diff line
@@ -345,9 +345,26 @@
	ECN(SP_ALIGN), ECN(FP_EXC32), ECN(FP_EXC64), ECN(SERROR), \
	ECN(BREAKPT_LOW), ECN(BREAKPT_CUR), ECN(SOFTSTP_LOW), \
	ECN(SOFTSTP_CUR), ECN(WATCHPT_LOW), ECN(WATCHPT_CUR), \
	ECN(BKPT32), ECN(VECTOR32), ECN(BRK64)
	ECN(BKPT32), ECN(VECTOR32), ECN(BRK64), ECN(ERET)

#define CPACR_EL1_DEFAULT	(CPACR_EL1_FPEN_EL0EN | CPACR_EL1_FPEN_EL1EN |\
				 CPACR_EL1_ZEN_EL1EN)

#define kvm_mode_names				\
	{ PSR_MODE_EL0t,	"EL0t" },	\
	{ PSR_MODE_EL1t,	"EL1t" },	\
	{ PSR_MODE_EL1h,	"EL1h" },	\
	{ PSR_MODE_EL2t,	"EL2t" },	\
	{ PSR_MODE_EL2h,	"EL2h" },	\
	{ PSR_MODE_EL3t,	"EL3t" },	\
	{ PSR_MODE_EL3h,	"EL3h" },	\
	{ PSR_AA32_MODE_USR,	"32-bit USR" },	\
	{ PSR_AA32_MODE_FIQ,	"32-bit FIQ" },	\
	{ PSR_AA32_MODE_IRQ,	"32-bit IRQ" },	\
	{ PSR_AA32_MODE_SVC,	"32-bit SVC" },	\
	{ PSR_AA32_MODE_ABT,	"32-bit ABT" },	\
	{ PSR_AA32_MODE_HYP,	"32-bit HYP" },	\
	{ PSR_AA32_MODE_UND,	"32-bit UND" },	\
	{ PSR_AA32_MODE_SYS,	"32-bit SYS" }

#endif /* __ARM64_KVM_ARM_H__ */
+66 −0
Original line number Diff line number Diff line
@@ -33,6 +33,12 @@ enum exception_type {
	except_type_serror	= 0x180,
};

#define kvm_exception_type_names		\
	{ except_type_sync,	"SYNC"   },	\
	{ except_type_irq,	"IRQ"    },	\
	{ except_type_fiq,	"FIQ"    },	\
	{ except_type_serror,	"SERROR" }

bool kvm_condition_valid32(const struct kvm_vcpu *vcpu);
void kvm_skip_instr32(struct kvm_vcpu *vcpu);

@@ -44,6 +50,10 @@ void kvm_inject_size_fault(struct kvm_vcpu *vcpu);

void kvm_vcpu_wfi(struct kvm_vcpu *vcpu);

void kvm_emulate_nested_eret(struct kvm_vcpu *vcpu);
int kvm_inject_nested_sync(struct kvm_vcpu *vcpu, u64 esr_el2);
int kvm_inject_nested_irq(struct kvm_vcpu *vcpu);

#if defined(__KVM_VHE_HYPERVISOR__) || defined(__KVM_NVHE_HYPERVISOR__)
static __always_inline bool vcpu_el1_is_32bit(struct kvm_vcpu *vcpu)
{
@@ -179,6 +189,62 @@ static __always_inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
		vcpu_gp_regs(vcpu)->regs[reg_num] = val;
}

static inline bool vcpu_is_el2_ctxt(const struct kvm_cpu_context *ctxt)
{
	switch (ctxt->regs.pstate & (PSR_MODE32_BIT | PSR_MODE_MASK)) {
	case PSR_MODE_EL2h:
	case PSR_MODE_EL2t:
		return true;
	default:
		return false;
	}
}

static inline bool vcpu_is_el2(const struct kvm_vcpu *vcpu)
{
	return vcpu_is_el2_ctxt(&vcpu->arch.ctxt);
}

static inline bool __vcpu_el2_e2h_is_set(const struct kvm_cpu_context *ctxt)
{
	return ctxt_sys_reg(ctxt, HCR_EL2) & HCR_E2H;
}

static inline bool vcpu_el2_e2h_is_set(const struct kvm_vcpu *vcpu)
{
	return __vcpu_el2_e2h_is_set(&vcpu->arch.ctxt);
}

static inline bool __vcpu_el2_tge_is_set(const struct kvm_cpu_context *ctxt)
{
	return ctxt_sys_reg(ctxt, HCR_EL2) & HCR_TGE;
}

static inline bool vcpu_el2_tge_is_set(const struct kvm_vcpu *vcpu)
{
	return __vcpu_el2_tge_is_set(&vcpu->arch.ctxt);
}

static inline bool __is_hyp_ctxt(const struct kvm_cpu_context *ctxt)
{
	/*
	 * We are in a hypervisor context if the vcpu mode is EL2 or
	 * E2H and TGE bits are set. The latter means we are in the user space
	 * of the VHE kernel. ARMv8.1 ARM describes this as 'InHost'
	 *
	 * Note that the HCR_EL2.{E2H,TGE}={0,1} isn't really handled in the
	 * rest of the KVM code, and will result in a misbehaving guest.
	 */
	return vcpu_is_el2_ctxt(ctxt) ||
		(__vcpu_el2_e2h_is_set(ctxt) && __vcpu_el2_tge_is_set(ctxt)) ||
		__vcpu_el2_tge_is_set(ctxt);
}

static inline bool is_hyp_ctxt(const struct kvm_vcpu *vcpu)
{
	return __is_hyp_ctxt(&vcpu->arch.ctxt);
}

/*
 * The layout of SPSR for an AArch32 state is different when observed from an
 * AArch64 SPSR_ELx or an AArch32 SPSR_*. This function generates the AArch32
+40 −2
Original line number Diff line number Diff line
@@ -60,9 +60,14 @@
enum kvm_mode {
	KVM_MODE_DEFAULT,
	KVM_MODE_PROTECTED,
	KVM_MODE_NV,
	KVM_MODE_NONE,
};
#ifdef CONFIG_KVM
enum kvm_mode kvm_get_mode(void);
#else
static inline enum kvm_mode kvm_get_mode(void) { return KVM_MODE_NONE; };
#endif

DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);

@@ -321,12 +326,43 @@ enum vcpu_sysreg {
	TFSR_EL1,	/* Tag Fault Status Register (EL1) */
	TFSRE0_EL1,	/* Tag Fault Status Register (EL0) */

	/* 32bit specific registers. Keep them at the end of the range */
	/* 32bit specific registers. */
	DACR32_EL2,	/* Domain Access Control Register */
	IFSR32_EL2,	/* Instruction Fault Status Register */
	FPEXC32_EL2,	/* Floating-Point Exception Control Register */
	DBGVCR32_EL2,	/* Debug Vector Catch Register */

	/* EL2 registers */
	VPIDR_EL2,	/* Virtualization Processor ID Register */
	VMPIDR_EL2,	/* Virtualization Multiprocessor ID Register */
	SCTLR_EL2,	/* System Control Register (EL2) */
	ACTLR_EL2,	/* Auxiliary Control Register (EL2) */
	HCR_EL2,	/* Hypervisor Configuration Register */
	MDCR_EL2,	/* Monitor Debug Configuration Register (EL2) */
	CPTR_EL2,	/* Architectural Feature Trap Register (EL2) */
	HSTR_EL2,	/* Hypervisor System Trap Register */
	HACR_EL2,	/* Hypervisor Auxiliary Control Register */
	TTBR0_EL2,	/* Translation Table Base Register 0 (EL2) */
	TTBR1_EL2,	/* Translation Table Base Register 1 (EL2) */
	TCR_EL2,	/* Translation Control Register (EL2) */
	VTTBR_EL2,	/* Virtualization Translation Table Base Register */
	VTCR_EL2,	/* Virtualization Translation Control Register */
	SPSR_EL2,	/* EL2 saved program status register */
	ELR_EL2,	/* EL2 exception link register */
	AFSR0_EL2,	/* Auxiliary Fault Status Register 0 (EL2) */
	AFSR1_EL2,	/* Auxiliary Fault Status Register 1 (EL2) */
	ESR_EL2,	/* Exception Syndrome Register (EL2) */
	FAR_EL2,	/* Fault Address Register (EL2) */
	HPFAR_EL2,	/* Hypervisor IPA Fault Address Register */
	MAIR_EL2,	/* Memory Attribute Indirection Register (EL2) */
	AMAIR_EL2,	/* Auxiliary Memory Attribute Indirection Register (EL2) */
	VBAR_EL2,	/* Vector Base Address Register (EL2) */
	RVBAR_EL2,	/* Reset Vector Base Address Register */
	CONTEXTIDR_EL2,	/* Context ID Register (EL2) */
	TPIDR_EL2,	/* EL2 Software Thread ID Register */
	CNTHCTL_EL2,	/* Counter-timer Hypervisor Control register */
	SP_EL2,		/* EL2 Stack Pointer */

	NR_SYS_REGS	/* Nothing after this line! */
};

@@ -602,7 +638,7 @@ struct kvm_vcpu_arch {
#define EXCEPT_AA64_EL1_IRQ	__vcpu_except_flags(1)
#define EXCEPT_AA64_EL1_FIQ	__vcpu_except_flags(2)
#define EXCEPT_AA64_EL1_SERR	__vcpu_except_flags(3)
/* For AArch64 with NV (one day): */
/* For AArch64 with NV: */
#define EXCEPT_AA64_EL2_SYNC	__vcpu_except_flags(4)
#define EXCEPT_AA64_EL2_IRQ	__vcpu_except_flags(5)
#define EXCEPT_AA64_EL2_FIQ	__vcpu_except_flags(6)
@@ -613,6 +649,8 @@ struct kvm_vcpu_arch {
#define DEBUG_STATE_SAVE_SPE	__vcpu_single_flag(iflags, BIT(5))
/* Save TRBE context if active  */
#define DEBUG_STATE_SAVE_TRBE	__vcpu_single_flag(iflags, BIT(6))
/* vcpu running in HYP context */
#define VCPU_HYP_CONTEXT	__vcpu_single_flag(iflags, BIT(7))

/* SVE enabled for host EL0 */
#define HOST_SVE_ENABLED	__vcpu_single_flag(sflags, BIT(0))
Loading