Commit 961e2bfc authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files
KVM/arm64 updates for 6.9

 - Infrastructure for building KVM's trap configuration based on the
   architectural features (or lack thereof) advertised in the VM's ID
   registers

 - Support for mapping vfio-pci BARs as Normal-NC (vaguely similar to
   x86's WC) at stage-2, improving the performance of interacting with
   assigned devices that can tolerate it

 - Conversion of KVM's representation of LPIs to an xarray, utilized to
   address serialization some of the serialization on the LPI injection
   path

 - Support for _architectural_ VHE-only systems, advertised through the
   absence of FEAT_E2H0 in the CPU's ID register

 - Miscellaneous cleanups, fixes, and spelling corrections to KVM and
   selftests
parents 233d0bc4 4a09ddb8
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ struct cpuinfo_arm64 {
	u64		reg_id_aa64mmfr1;
	u64		reg_id_aa64mmfr2;
	u64		reg_id_aa64mmfr3;
	u64		reg_id_aa64mmfr4;
	u64		reg_id_aa64pfr0;
	u64		reg_id_aa64pfr1;
	u64		reg_id_aa64zfr0;
+1 −0
Original line number Diff line number Diff line
@@ -363,6 +363,7 @@ struct arm64_cpu_capabilities {
			u8 field_pos;
			u8 field_width;
			u8 min_field_value;
			u8 max_field_value;
			u8 hwcap_type;
			bool sign;
			unsigned long hwcap;
+1 −3
Original line number Diff line number Diff line
@@ -102,9 +102,7 @@
#define HCR_HOST_NVHE_PROTECTED_FLAGS (HCR_HOST_NVHE_FLAGS | HCR_TSC)
#define HCR_HOST_VHE_FLAGS (HCR_RW | HCR_TGE | HCR_E2H)

#define HCRX_GUEST_FLAGS \
	(HCRX_EL2_SMPME | HCRX_EL2_TCR2En | \
	 (cpus_have_final_cap(ARM64_HAS_MOPS) ? (HCRX_EL2_MSCEn | HCRX_EL2_MCE2) : 0))
#define HCRX_GUEST_FLAGS (HCRX_EL2_SMPME | HCRX_EL2_TCR2En)
#define HCRX_HOST_FLAGS (HCRX_EL2_MSCEn | HCRX_EL2_TCR2En)

/* TCR_EL2 Registers bits */
+2 −1
Original line number Diff line number Diff line
@@ -209,7 +209,8 @@ static inline bool vcpu_is_el2(const struct kvm_vcpu *vcpu)

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

static inline bool vcpu_el2_e2h_is_set(const struct kvm_vcpu *vcpu)
+98 −1
Original line number Diff line number Diff line
@@ -238,9 +238,32 @@ static inline u16 kvm_mpidr_index(struct kvm_mpidr_data *data, u64 mpidr)
	return index;
}

struct kvm_sysreg_masks;

enum fgt_group_id {
	__NO_FGT_GROUP__,
	HFGxTR_GROUP,
	HDFGRTR_GROUP,
	HDFGWTR_GROUP = HDFGRTR_GROUP,
	HFGITR_GROUP,
	HAFGRTR_GROUP,

	/* Must be last */
	__NR_FGT_GROUP_IDS__
};

struct kvm_arch {
	struct kvm_s2_mmu mmu;

	/*
	 * Fine-Grained UNDEF, mimicking the FGT layout defined by the
	 * architecture. We track them globally, as we present the
	 * same feature-set to all vcpus.
	 *
	 * Index 0 is currently spare.
	 */
	u64 fgu[__NR_FGT_GROUP_IDS__];

	/* Interrupt controller */
	struct vgic_dist	vgic;

@@ -274,6 +297,8 @@ struct kvm_arch {
#define KVM_ARCH_FLAG_TIMER_PPIS_IMMUTABLE		6
	/* Initial ID reg values loaded */
#define KVM_ARCH_FLAG_ID_REGS_INITIALIZED		7
	/* Fine-Grained UNDEF initialised */
#define KVM_ARCH_FLAG_FGU_INITIALIZED			8
	unsigned long flags;

	/* VM-wide vCPU feature set */
@@ -294,6 +319,9 @@ struct kvm_arch {
	/* PMCR_EL0.N value for the guest */
	u8 pmcr_n;

	/* Iterator for idreg debugfs */
	u8	idreg_debugfs_iter;

	/* Hypercall features firmware registers' descriptor */
	struct kvm_smccc_features smccc_feat;
	struct maple_tree smccc_filter;
@@ -312,6 +340,9 @@ struct kvm_arch {
#define KVM_ARM_ID_REG_NUM	(IDREG_IDX(sys_reg(3, 0, 0, 7, 7)) + 1)
	u64 id_regs[KVM_ARM_ID_REG_NUM];

	/* Masks for VNCR-baked sysregs */
	struct kvm_sysreg_masks	*sysreg_masks;

	/*
	 * For an untrusted host VM, 'pkvm.handle' is used to lookup
	 * the associated pKVM instance in the hypervisor.
@@ -474,6 +505,13 @@ enum vcpu_sysreg {
	NR_SYS_REGS	/* Nothing after this line! */
};

struct kvm_sysreg_masks {
	struct {
		u64	res0;
		u64	res1;
	} mask[NR_SYS_REGS - __VNCR_START__];
};

struct kvm_cpu_context {
	struct user_pt_regs regs;	/* sp = sp_el0 */

@@ -549,6 +587,7 @@ struct kvm_vcpu_arch {

	/* Values of trap registers for the guest. */
	u64 hcr_el2;
	u64 hcrx_el2;
	u64 mdcr_el2;
	u64 cptr_el2;

@@ -868,7 +907,15 @@ static inline u64 *__ctxt_sys_reg(const struct kvm_cpu_context *ctxt, int r)

#define ctxt_sys_reg(c,r)	(*__ctxt_sys_reg(c,r))

#define __vcpu_sys_reg(v,r)	(ctxt_sys_reg(&(v)->arch.ctxt, (r)))
u64 kvm_vcpu_sanitise_vncr_reg(const struct kvm_vcpu *, enum vcpu_sysreg);
#define __vcpu_sys_reg(v,r)						\
	(*({								\
		const struct kvm_cpu_context *ctxt = &(v)->arch.ctxt;	\
		u64 *__r = __ctxt_sys_reg(ctxt, (r));			\
		if (vcpu_has_nv((v)) && (r) >= __VNCR_START__)		\
			*__r = kvm_vcpu_sanitise_vncr_reg((v), (r));	\
		__r;							\
	}))

u64 vcpu_read_sys_reg(const struct kvm_vcpu *vcpu, int reg);
void vcpu_write_sys_reg(struct kvm_vcpu *vcpu, u64 val, int reg);
@@ -1055,14 +1102,20 @@ int kvm_handle_cp15_64(struct kvm_vcpu *vcpu);
int kvm_handle_sys_reg(struct kvm_vcpu *vcpu);
int kvm_handle_cp10_id(struct kvm_vcpu *vcpu);

void kvm_sys_regs_create_debugfs(struct kvm *kvm);
void kvm_reset_sys_regs(struct kvm_vcpu *vcpu);

int __init kvm_sys_reg_table_init(void);
struct sys_reg_desc;
int __init populate_sysreg_config(const struct sys_reg_desc *sr,
				  unsigned int idx);
int __init populate_nv_trap_config(void);

bool lock_all_vcpus(struct kvm *kvm);
void unlock_all_vcpus(struct kvm *kvm);

void kvm_init_sysreg(struct kvm_vcpu *);

/* MMIO helpers */
void kvm_mmio_write_buf(void *buf, unsigned int len, unsigned long data);
unsigned long kvm_mmio_read_buf(const void *buf, unsigned int len);
@@ -1233,4 +1286,48 @@ static inline void kvm_hyp_reserve(void) { }
void kvm_arm_vcpu_power_off(struct kvm_vcpu *vcpu);
bool kvm_arm_vcpu_stopped(struct kvm_vcpu *vcpu);

#define __expand_field_sign_unsigned(id, fld, val)			\
	((u64)SYS_FIELD_VALUE(id, fld, val))

#define __expand_field_sign_signed(id, fld, val)			\
	({								\
		u64 __val = SYS_FIELD_VALUE(id, fld, val);		\
		sign_extend64(__val, id##_##fld##_WIDTH - 1);		\
	})

#define expand_field_sign(id, fld, val)					\
	(id##_##fld##_SIGNED ?						\
	 __expand_field_sign_signed(id, fld, val) :			\
	 __expand_field_sign_unsigned(id, fld, val))

#define get_idreg_field_unsigned(kvm, id, fld)				\
	({								\
		u64 __val = IDREG((kvm), SYS_##id);			\
		FIELD_GET(id##_##fld##_MASK, __val);			\
	})

#define get_idreg_field_signed(kvm, id, fld)				\
	({								\
		u64 __val = get_idreg_field_unsigned(kvm, id, fld);	\
		sign_extend64(__val, id##_##fld##_WIDTH - 1);		\
	})

#define get_idreg_field_enum(kvm, id, fld)				\
	get_idreg_field_unsigned(kvm, id, fld)

#define get_idreg_field(kvm, id, fld)					\
	(id##_##fld##_SIGNED ?						\
	 get_idreg_field_signed(kvm, id, fld) :				\
	 get_idreg_field_unsigned(kvm, id, fld))

#define kvm_has_feat(kvm, id, fld, limit)				\
	(get_idreg_field((kvm), id, fld) >= expand_field_sign(id, fld, limit))

#define kvm_has_feat_enum(kvm, id, fld, val)				\
	(get_idreg_field_unsigned((kvm), id, fld) == __expand_field_sign_unsigned(id, fld, val))

#define kvm_has_feat_range(kvm, id, fld, min, max)			\
	(get_idreg_field((kvm), id, fld) >= expand_field_sign(id, fld, min) && \
	 get_idreg_field((kvm), id, fld) <= expand_field_sign(id, fld, max))

#endif /* __ARM64_KVM_HOST_H__ */
Loading