Commit 26f31498 authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

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

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

KVM/arm64 fixes for 6.4, take #2

- Address some fallout of the locking rework, this time affecting
  the way the vgic is configured

- Fix an issue where the page table walker frees a subtree and
  then proceeds with walking what it has just freed...

- Check that a given PA donated to the gues is actually memory
  (only affecting pKVM)

- Correctly handle MTE CMOs by Set/Way
parents b9846a69 a9f0e3d5
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -632,9 +632,9 @@ int kvm_pgtable_stage2_flush(struct kvm_pgtable *pgt, u64 addr, u64 size);
 *
 * The walker will walk the page-table entries corresponding to the input
 * address range specified, visiting entries according to the walker flags.
 * Invalid entries are treated as leaf entries. Leaf entries are reloaded
 * after invoking the walker callback, allowing the walker to descend into
 * a newly installed table.
 * Invalid entries are treated as leaf entries. The visited page table entry is
 * reloaded after invoking the walker callback, allowing the walker to descend
 * into a newly installed table.
 *
 * Returning a negative error code from the walker callback function will
 * terminate the walk immediately with the same error code.
+6 −0
Original line number Diff line number Diff line
@@ -115,8 +115,14 @@
#define SB_BARRIER_INSN			__SYS_BARRIER_INSN(0, 7, 31)

#define SYS_DC_ISW			sys_insn(1, 0, 7, 6, 2)
#define SYS_DC_IGSW			sys_insn(1, 0, 7, 6, 4)
#define SYS_DC_IGDSW			sys_insn(1, 0, 7, 6, 6)
#define SYS_DC_CSW			sys_insn(1, 0, 7, 10, 2)
#define SYS_DC_CGSW			sys_insn(1, 0, 7, 10, 4)
#define SYS_DC_CGDSW			sys_insn(1, 0, 7, 10, 6)
#define SYS_DC_CISW			sys_insn(1, 0, 7, 14, 2)
#define SYS_DC_CIGSW			sys_insn(1, 0, 7, 14, 4)
#define SYS_DC_CIGDSW			sys_insn(1, 0, 7, 14, 6)

/*
 * Automatically generated definitions for system registers, the
+7 −7
Original line number Diff line number Diff line
@@ -575,7 +575,7 @@ struct pkvm_mem_donation {

struct check_walk_data {
	enum pkvm_page_state	desired;
	enum pkvm_page_state	(*get_page_state)(kvm_pte_t pte);
	enum pkvm_page_state	(*get_page_state)(kvm_pte_t pte, u64 addr);
};

static int __check_page_state_visitor(const struct kvm_pgtable_visit_ctx *ctx,
@@ -583,10 +583,7 @@ static int __check_page_state_visitor(const struct kvm_pgtable_visit_ctx *ctx,
{
	struct check_walk_data *d = ctx->arg;

	if (kvm_pte_valid(ctx->old) && !addr_is_allowed_memory(kvm_pte_to_phys(ctx->old)))
		return -EINVAL;

	return d->get_page_state(ctx->old) == d->desired ? 0 : -EPERM;
	return d->get_page_state(ctx->old, ctx->addr) == d->desired ? 0 : -EPERM;
}

static int check_page_state_range(struct kvm_pgtable *pgt, u64 addr, u64 size,
@@ -601,8 +598,11 @@ static int check_page_state_range(struct kvm_pgtable *pgt, u64 addr, u64 size,
	return kvm_pgtable_walk(pgt, addr, size, &walker);
}

static enum pkvm_page_state host_get_page_state(kvm_pte_t pte)
static enum pkvm_page_state host_get_page_state(kvm_pte_t pte, u64 addr)
{
	if (!addr_is_allowed_memory(addr))
		return PKVM_NOPAGE;

	if (!kvm_pte_valid(pte) && pte)
		return PKVM_NOPAGE;

@@ -709,7 +709,7 @@ static int host_complete_donation(u64 addr, const struct pkvm_mem_transition *tx
	return host_stage2_set_owner_locked(addr, size, host_id);
}

static enum pkvm_page_state hyp_get_page_state(kvm_pte_t pte)
static enum pkvm_page_state hyp_get_page_state(kvm_pte_t pte, u64 addr)
{
	if (!kvm_pte_valid(pte))
		return PKVM_NOPAGE;
+13 −1
Original line number Diff line number Diff line
@@ -209,14 +209,26 @@ static inline int __kvm_pgtable_visit(struct kvm_pgtable_walk_data *data,
		.flags	= flags,
	};
	int ret = 0;
	bool reload = false;
	kvm_pteref_t childp;
	bool table = kvm_pte_table(ctx.old, level);

	if (table && (ctx.flags & KVM_PGTABLE_WALK_TABLE_PRE))
	if (table && (ctx.flags & KVM_PGTABLE_WALK_TABLE_PRE)) {
		ret = kvm_pgtable_visitor_cb(data, &ctx, KVM_PGTABLE_WALK_TABLE_PRE);
		reload = true;
	}

	if (!table && (ctx.flags & KVM_PGTABLE_WALK_LEAF)) {
		ret = kvm_pgtable_visitor_cb(data, &ctx, KVM_PGTABLE_WALK_LEAF);
		reload = true;
	}

	/*
	 * Reload the page table after invoking the walker callback for leaf
	 * entries or after pre-order traversal, to allow the walker to descend
	 * into a newly installed or replaced table.
	 */
	if (reload) {
		ctx.old = READ_ONCE(*ptep);
		table = kvm_pte_table(ctx.old, level);
	}
+19 −0
Original line number Diff line number Diff line
@@ -211,6 +211,19 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
	return true;
}

static bool access_dcgsw(struct kvm_vcpu *vcpu,
			 struct sys_reg_params *p,
			 const struct sys_reg_desc *r)
{
	if (!kvm_has_mte(vcpu->kvm)) {
		kvm_inject_undefined(vcpu);
		return false;
	}

	/* Treat MTE S/W ops as we treat the classic ones: with contempt */
	return access_dcsw(vcpu, p, r);
}

static void get_access_mask(const struct sys_reg_desc *r, u64 *mask, u64 *shift)
{
	switch (r->aarch32_map) {
@@ -1756,8 +1769,14 @@ static bool access_spsr(struct kvm_vcpu *vcpu,
 */
static const struct sys_reg_desc sys_reg_descs[] = {
	{ SYS_DESC(SYS_DC_ISW), access_dcsw },
	{ SYS_DESC(SYS_DC_IGSW), access_dcgsw },
	{ SYS_DESC(SYS_DC_IGDSW), access_dcgsw },
	{ SYS_DESC(SYS_DC_CSW), access_dcsw },
	{ SYS_DESC(SYS_DC_CGSW), access_dcgsw },
	{ SYS_DESC(SYS_DC_CGDSW), access_dcgsw },
	{ SYS_DESC(SYS_DC_CISW), access_dcsw },
	{ SYS_DESC(SYS_DC_CIGSW), access_dcgsw },
	{ SYS_DESC(SYS_DC_CIGDSW), access_dcgsw },

	DBG_BCR_BVR_WCR_WVR_EL1(0),
	DBG_BCR_BVR_WCR_WVR_EL1(1),
Loading