Commit ff2bb93f authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

Merge tag 'kvmarm-fixes-5.10-2' of...

Merge tag 'kvmarm-fixes-5.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into HEAD

KVM/arm64 fixes for v5.10, take #2

- Fix compilation error when PMD and PUD are folded
- Fix regresssion of the RAZ behaviour of ID_AA64ZFR0_EL1
parents 9478dec3 c512298e
Loading
Loading
Loading
Loading
+2 −0
Original line number Original line Diff line number Diff line
@@ -788,10 +788,12 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
	}
	}


	switch (vma_shift) {
	switch (vma_shift) {
#ifndef __PAGETABLE_PMD_FOLDED
	case PUD_SHIFT:
	case PUD_SHIFT:
		if (fault_supports_stage2_huge_mapping(memslot, hva, PUD_SIZE))
		if (fault_supports_stage2_huge_mapping(memslot, hva, PUD_SIZE))
			break;
			break;
		fallthrough;
		fallthrough;
#endif
	case CONT_PMD_SHIFT:
	case CONT_PMD_SHIFT:
		vma_shift = PMD_SHIFT;
		vma_shift = PMD_SHIFT;
		fallthrough;
		fallthrough;
+33 −75
Original line number Original line Diff line number Diff line
@@ -1069,7 +1069,7 @@ static bool trap_ptrauth(struct kvm_vcpu *vcpu,
static unsigned int ptrauth_visibility(const struct kvm_vcpu *vcpu,
static unsigned int ptrauth_visibility(const struct kvm_vcpu *vcpu,
			const struct sys_reg_desc *rd)
			const struct sys_reg_desc *rd)
{
{
	return vcpu_has_ptrauth(vcpu) ? 0 : REG_HIDDEN_USER | REG_HIDDEN_GUEST;
	return vcpu_has_ptrauth(vcpu) ? 0 : REG_HIDDEN;
}
}


#define __PTRAUTH_KEY(k)						\
#define __PTRAUTH_KEY(k)						\
@@ -1153,6 +1153,22 @@ static u64 read_id_reg(const struct kvm_vcpu *vcpu,
	return val;
	return val;
}
}


static unsigned int id_visibility(const struct kvm_vcpu *vcpu,
				  const struct sys_reg_desc *r)
{
	u32 id = sys_reg((u32)r->Op0, (u32)r->Op1,
			 (u32)r->CRn, (u32)r->CRm, (u32)r->Op2);

	switch (id) {
	case SYS_ID_AA64ZFR0_EL1:
		if (!vcpu_has_sve(vcpu))
			return REG_RAZ;
		break;
	}

	return 0;
}

/* cpufeature ID register access trap handlers */
/* cpufeature ID register access trap handlers */


static bool __access_id_reg(struct kvm_vcpu *vcpu,
static bool __access_id_reg(struct kvm_vcpu *vcpu,
@@ -1171,7 +1187,9 @@ static bool access_id_reg(struct kvm_vcpu *vcpu,
			  struct sys_reg_params *p,
			  struct sys_reg_params *p,
			  const struct sys_reg_desc *r)
			  const struct sys_reg_desc *r)
{
{
	return __access_id_reg(vcpu, p, r, false);
	bool raz = sysreg_visible_as_raz(vcpu, r);

	return __access_id_reg(vcpu, p, r, raz);
}
}


static bool access_raz_id_reg(struct kvm_vcpu *vcpu,
static bool access_raz_id_reg(struct kvm_vcpu *vcpu,
@@ -1192,72 +1210,7 @@ static unsigned int sve_visibility(const struct kvm_vcpu *vcpu,
	if (vcpu_has_sve(vcpu))
	if (vcpu_has_sve(vcpu))
		return 0;
		return 0;


	return REG_HIDDEN_USER | REG_HIDDEN_GUEST;
	return REG_HIDDEN;
}

/* Visibility overrides for SVE-specific ID registers */
static unsigned int sve_id_visibility(const struct kvm_vcpu *vcpu,
				      const struct sys_reg_desc *rd)
{
	if (vcpu_has_sve(vcpu))
		return 0;

	return REG_HIDDEN_USER;
}

/* Generate the emulated ID_AA64ZFR0_EL1 value exposed to the guest */
static u64 guest_id_aa64zfr0_el1(const struct kvm_vcpu *vcpu)
{
	if (!vcpu_has_sve(vcpu))
		return 0;

	return read_sanitised_ftr_reg(SYS_ID_AA64ZFR0_EL1);
}

static bool access_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
				   struct sys_reg_params *p,
				   const struct sys_reg_desc *rd)
{
	if (p->is_write)
		return write_to_read_only(vcpu, p, rd);

	p->regval = guest_id_aa64zfr0_el1(vcpu);
	return true;
}

static int get_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
		const struct sys_reg_desc *rd,
		const struct kvm_one_reg *reg, void __user *uaddr)
{
	u64 val;

	if (WARN_ON(!vcpu_has_sve(vcpu)))
		return -ENOENT;

	val = guest_id_aa64zfr0_el1(vcpu);
	return reg_to_user(uaddr, &val, reg->id);
}

static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu,
		const struct sys_reg_desc *rd,
		const struct kvm_one_reg *reg, void __user *uaddr)
{
	const u64 id = sys_reg_to_index(rd);
	int err;
	u64 val;

	if (WARN_ON(!vcpu_has_sve(vcpu)))
		return -ENOENT;

	err = reg_from_user(&val, uaddr, id);
	if (err)
		return err;

	/* This is what we mean by invariant: you can't change it. */
	if (val != guest_id_aa64zfr0_el1(vcpu))
		return -EINVAL;

	return 0;
}
}


/*
/*
@@ -1299,13 +1252,17 @@ static int __set_id_reg(const struct kvm_vcpu *vcpu,
static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
static int get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
		      const struct kvm_one_reg *reg, void __user *uaddr)
		      const struct kvm_one_reg *reg, void __user *uaddr)
{
{
	return __get_id_reg(vcpu, rd, uaddr, false);
	bool raz = sysreg_visible_as_raz(vcpu, rd);

	return __get_id_reg(vcpu, rd, uaddr, raz);
}
}


static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
static int set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
		      const struct kvm_one_reg *reg, void __user *uaddr)
		      const struct kvm_one_reg *reg, void __user *uaddr)
{
{
	return __set_id_reg(vcpu, rd, uaddr, false);
	bool raz = sysreg_visible_as_raz(vcpu, rd);

	return __set_id_reg(vcpu, rd, uaddr, raz);
}
}


static int get_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
static int get_raz_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
@@ -1397,6 +1354,7 @@ static bool access_mte_regs(struct kvm_vcpu *vcpu, struct sys_reg_params *p,
	.access	= access_id_reg,		\
	.access	= access_id_reg,		\
	.get_user = get_id_reg,			\
	.get_user = get_id_reg,			\
	.set_user = set_id_reg,			\
	.set_user = set_id_reg,			\
	.visibility = id_visibility,		\
}
}


/*
/*
@@ -1518,7 +1476,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
	ID_SANITISED(ID_AA64PFR1_EL1),
	ID_SANITISED(ID_AA64PFR1_EL1),
	ID_UNALLOCATED(4,2),
	ID_UNALLOCATED(4,2),
	ID_UNALLOCATED(4,3),
	ID_UNALLOCATED(4,3),
	{ SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility },
	ID_SANITISED(ID_AA64ZFR0_EL1),
	ID_UNALLOCATED(4,5),
	ID_UNALLOCATED(4,5),
	ID_UNALLOCATED(4,6),
	ID_UNALLOCATED(4,6),
	ID_UNALLOCATED(4,7),
	ID_UNALLOCATED(4,7),
@@ -2185,7 +2143,7 @@ static void perform_access(struct kvm_vcpu *vcpu,
	trace_kvm_sys_access(*vcpu_pc(vcpu), params, r);
	trace_kvm_sys_access(*vcpu_pc(vcpu), params, r);


	/* Check for regs disabled by runtime config */
	/* Check for regs disabled by runtime config */
	if (sysreg_hidden_from_guest(vcpu, r)) {
	if (sysreg_hidden(vcpu, r)) {
		kvm_inject_undefined(vcpu);
		kvm_inject_undefined(vcpu);
		return;
		return;
	}
	}
@@ -2684,7 +2642,7 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
		return get_invariant_sys_reg(reg->id, uaddr);
		return get_invariant_sys_reg(reg->id, uaddr);


	/* Check for regs disabled by runtime config */
	/* Check for regs disabled by runtime config */
	if (sysreg_hidden_from_user(vcpu, r))
	if (sysreg_hidden(vcpu, r))
		return -ENOENT;
		return -ENOENT;


	if (r->get_user)
	if (r->get_user)
@@ -2709,7 +2667,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg
		return set_invariant_sys_reg(reg->id, uaddr);
		return set_invariant_sys_reg(reg->id, uaddr);


	/* Check for regs disabled by runtime config */
	/* Check for regs disabled by runtime config */
	if (sysreg_hidden_from_user(vcpu, r))
	if (sysreg_hidden(vcpu, r))
		return -ENOENT;
		return -ENOENT;


	if (r->set_user)
	if (r->set_user)
@@ -2780,7 +2738,7 @@ static int walk_one_sys_reg(const struct kvm_vcpu *vcpu,
	if (!(rd->reg || rd->get_user))
	if (!(rd->reg || rd->get_user))
		return 0;
		return 0;


	if (sysreg_hidden_from_user(vcpu, rd))
	if (sysreg_hidden(vcpu, rd))
		return 0;
		return 0;


	if (!copy_reg_to_user(rd, uind))
	if (!copy_reg_to_user(rd, uind))
+8 −8
Original line number Original line Diff line number Diff line
@@ -59,8 +59,8 @@ struct sys_reg_desc {
				   const struct sys_reg_desc *rd);
				   const struct sys_reg_desc *rd);
};
};


#define REG_HIDDEN_USER		(1 << 0) /* hidden from userspace ioctls */
#define REG_HIDDEN		(1 << 0) /* hidden from userspace and guest */
#define REG_HIDDEN_GUEST	(1 << 1) /* hidden from guest */
#define REG_RAZ			(1 << 1) /* RAZ from userspace and guest */


static __printf(2, 3)
static __printf(2, 3)
inline void print_sys_reg_msg(const struct sys_reg_params *p,
inline void print_sys_reg_msg(const struct sys_reg_params *p,
@@ -111,22 +111,22 @@ static inline void reset_val(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r
	__vcpu_sys_reg(vcpu, r->reg) = r->val;
	__vcpu_sys_reg(vcpu, r->reg) = r->val;
}
}


static inline bool sysreg_hidden_from_guest(const struct kvm_vcpu *vcpu,
static inline bool sysreg_hidden(const struct kvm_vcpu *vcpu,
				 const struct sys_reg_desc *r)
				 const struct sys_reg_desc *r)
{
{
	if (likely(!r->visibility))
	if (likely(!r->visibility))
		return false;
		return false;


	return r->visibility(vcpu, r) & REG_HIDDEN_GUEST;
	return r->visibility(vcpu, r) & REG_HIDDEN;
}
}


static inline bool sysreg_hidden_from_user(const struct kvm_vcpu *vcpu,
static inline bool sysreg_visible_as_raz(const struct kvm_vcpu *vcpu,
					 const struct sys_reg_desc *r)
					 const struct sys_reg_desc *r)
{
{
	if (likely(!r->visibility))
	if (likely(!r->visibility))
		return false;
		return false;


	return r->visibility(vcpu, r) & REG_HIDDEN_USER;
	return r->visibility(vcpu, r) & REG_RAZ;
}
}


static inline int cmp_sys_reg(const struct sys_reg_desc *i1,
static inline int cmp_sys_reg(const struct sys_reg_desc *i1,