Commit b86c9bea authored by Joey Gouly's avatar Joey Gouly Committed by Will Deacon
Browse files

KVM: arm64: Save/restore POE registers



Define the new system registers that POE introduces and context switch them.

Signed-off-by: default avatarJoey Gouly <joey.gouly@arm.com>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Oliver Upton <oliver.upton@linux.dev>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Reviewed-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20240822151113.1479789-8-joey.gouly@arm.com


Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 160a8e13
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -446,6 +446,8 @@ enum vcpu_sysreg {
	GCR_EL1,	/* Tag Control Register */
	TFSRE0_EL1,	/* Tag Fault Status Register (EL0) */

	POR_EL0,	/* Permission Overlay Register 0 (EL0) */

	/* 32bit specific registers. */
	DACR32_EL2,	/* Domain Access Control Register */
	IFSR32_EL2,	/* Instruction Fault Status Register */
@@ -517,6 +519,8 @@ enum vcpu_sysreg {
	VNCR(PIR_EL1),	 /* Permission Indirection Register 1 (EL1) */
	VNCR(PIRE0_EL1), /*  Permission Indirection Register 0 (EL1) */

	VNCR(POR_EL1),	/* Permission Overlay Register 1 (EL1) */

	VNCR(HFGRTR_EL2),
	VNCR(HFGWTR_EL2),
	VNCR(HFGITR_EL2),
+1 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@
#define VNCR_PIRE0_EL1		0x290
#define VNCR_PIRE0_EL2		0x298
#define VNCR_PIR_EL1		0x2A0
#define VNCR_POR_EL1		0x2A8
#define VNCR_ICH_LR0_EL2        0x400
#define VNCR_ICH_LR1_EL2        0x408
#define VNCR_ICH_LR2_EL2        0x410
+27 −0
Original line number Diff line number Diff line
@@ -16,9 +16,15 @@
#include <asm/kvm_hyp.h>
#include <asm/kvm_mmu.h>

static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt);

static inline void __sysreg_save_common_state(struct kvm_cpu_context *ctxt)
{
	ctxt_sys_reg(ctxt, MDSCR_EL1)	= read_sysreg(mdscr_el1);

	// POR_EL0 can affect uaccess, so must be saved/restored early.
	if (ctxt_has_s1poe(ctxt))
		ctxt_sys_reg(ctxt, POR_EL0)	= read_sysreg_s(SYS_POR_EL0);
}

static inline void __sysreg_save_user_state(struct kvm_cpu_context *ctxt)
@@ -66,6 +72,17 @@ static inline bool ctxt_has_tcrx(struct kvm_cpu_context *ctxt)
	return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64MMFR3_EL1, TCRX, IMP);
}

static inline bool ctxt_has_s1poe(struct kvm_cpu_context *ctxt)
{
	struct kvm_vcpu *vcpu;

	if (!system_supports_poe())
		return false;

	vcpu = ctxt_to_vcpu(ctxt);
	return kvm_has_feat(kern_hyp_va(vcpu->kvm), ID_AA64MMFR3_EL1, S1POE, IMP);
}

static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
{
	ctxt_sys_reg(ctxt, SCTLR_EL1)	= read_sysreg_el1(SYS_SCTLR);
@@ -80,6 +97,9 @@ static inline void __sysreg_save_el1_state(struct kvm_cpu_context *ctxt)
			ctxt_sys_reg(ctxt, PIR_EL1)	= read_sysreg_el1(SYS_PIR);
			ctxt_sys_reg(ctxt, PIRE0_EL1)	= read_sysreg_el1(SYS_PIRE0);
		}

		if (ctxt_has_s1poe(ctxt))
			ctxt_sys_reg(ctxt, POR_EL1)	= read_sysreg_el1(SYS_POR);
	}
	ctxt_sys_reg(ctxt, ESR_EL1)	= read_sysreg_el1(SYS_ESR);
	ctxt_sys_reg(ctxt, AFSR0_EL1)	= read_sysreg_el1(SYS_AFSR0);
@@ -120,6 +140,10 @@ static inline void __sysreg_save_el2_return_state(struct kvm_cpu_context *ctxt)
static inline void __sysreg_restore_common_state(struct kvm_cpu_context *ctxt)
{
	write_sysreg(ctxt_sys_reg(ctxt, MDSCR_EL1),  mdscr_el1);

	// POR_EL0 can affect uaccess, so must be saved/restored early.
	if (ctxt_has_s1poe(ctxt))
		write_sysreg_s(ctxt_sys_reg(ctxt, POR_EL0),	SYS_POR_EL0);
}

static inline void __sysreg_restore_user_state(struct kvm_cpu_context *ctxt)
@@ -158,6 +182,9 @@ static inline void __sysreg_restore_el1_state(struct kvm_cpu_context *ctxt)
			write_sysreg_el1(ctxt_sys_reg(ctxt, PIR_EL1),	SYS_PIR);
			write_sysreg_el1(ctxt_sys_reg(ctxt, PIRE0_EL1),	SYS_PIRE0);
		}

		if (ctxt_has_s1poe(ctxt))
			write_sysreg_el1(ctxt_sys_reg(ctxt, POR_EL1),	SYS_POR);
	}
	write_sysreg_el1(ctxt_sys_reg(ctxt, ESR_EL1),	SYS_ESR);
	write_sysreg_el1(ctxt_sys_reg(ctxt, AFSR0_EL1),	SYS_AFSR0);
+17 −2
Original line number Diff line number Diff line
@@ -2255,6 +2255,15 @@ static bool access_zcr_el2(struct kvm_vcpu *vcpu,
	return true;
}

static unsigned int s1poe_visibility(const struct kvm_vcpu *vcpu,
				     const struct sys_reg_desc *rd)
{
	if (kvm_has_feat(vcpu->kvm, ID_AA64MMFR3_EL1, S1POE, IMP))
		return 0;

	return REG_HIDDEN;
}

/*
 * Architected system registers.
 * Important: Must be sorted ascending by Op0, Op1, CRn, CRm, Op2
@@ -2492,6 +2501,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
	{ SYS_DESC(SYS_MAIR_EL1), access_vm_reg, reset_unknown, MAIR_EL1 },
	{ SYS_DESC(SYS_PIRE0_EL1), NULL, reset_unknown, PIRE0_EL1 },
	{ SYS_DESC(SYS_PIR_EL1), NULL, reset_unknown, PIR_EL1 },
	{ SYS_DESC(SYS_POR_EL1), NULL, reset_unknown, POR_EL1,
	  .visibility = s1poe_visibility },
	{ SYS_DESC(SYS_AMAIR_EL1), access_vm_reg, reset_amair_el1, AMAIR_EL1 },

	{ SYS_DESC(SYS_LORSA_EL1), trap_loregion },
@@ -2578,6 +2589,8 @@ static const struct sys_reg_desc sys_reg_descs[] = {
	  .access = access_pmovs, .reg = PMOVSSET_EL0,
	  .get_user = get_pmreg, .set_user = set_pmreg },

	{ SYS_DESC(SYS_POR_EL0), NULL, reset_unknown, POR_EL0,
	  .visibility = s1poe_visibility },
	{ SYS_DESC(SYS_TPIDR_EL0), NULL, reset_unknown, TPIDR_EL0 },
	{ SYS_DESC(SYS_TPIDRRO_EL0), NULL, reset_unknown, TPIDRRO_EL0 },
	{ SYS_DESC(SYS_TPIDR2_EL0), undef_access },
@@ -4568,8 +4581,6 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
	kvm->arch.fgu[HFGxTR_GROUP] = (HFGxTR_EL2_nAMAIR2_EL1		|
				       HFGxTR_EL2_nMAIR2_EL1		|
				       HFGxTR_EL2_nS2POR_EL1		|
				       HFGxTR_EL2_nPOR_EL1		|
				       HFGxTR_EL2_nPOR_EL0		|
				       HFGxTR_EL2_nACCDATA_EL1		|
				       HFGxTR_EL2_nSMPRI_EL1_MASK	|
				       HFGxTR_EL2_nTPIDR2_EL0_MASK);
@@ -4604,6 +4615,10 @@ void kvm_calculate_traps(struct kvm_vcpu *vcpu)
		kvm->arch.fgu[HFGxTR_GROUP] |= (HFGxTR_EL2_nPIRE0_EL1 |
						HFGxTR_EL2_nPIR_EL1);

	if (!kvm_has_feat(kvm, ID_AA64MMFR3_EL1, S1POE, IMP))
		kvm->arch.fgu[HFGxTR_GROUP] |= (HFGxTR_EL2_nPOR_EL1 |
						HFGxTR_EL2_nPOR_EL0);

	if (!kvm_has_feat(kvm, ID_AA64PFR0_EL1, AMU, IMP))
		kvm->arch.fgu[HAFGRTR_GROUP] |= ~(HAFGRTR_EL2_RES0 |
						  HAFGRTR_EL2_RES1);