Skip to content

Commit

Permalink
Merge tag 'kvmarm-fixes-6.10-2' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/kvmarm/kvmarm into HEAD

KVM/arm64 fixes for 6.10, take #2

- Fix dangling references to a redistributor region if
  the vgic was prematurely destroyed.

- Properly mark FFA buffers as released, ensuring that
  both parties can make forward progress.
  • Loading branch information
bonzini committed Jun 20, 2024
2 parents 676f819 + d66e50b commit fb443ce
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 4 deletions.
12 changes: 12 additions & 0 deletions arch/arm64/kvm/hyp/nvhe/ffa.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,14 @@ static void ffa_retrieve_req(struct arm_smccc_res *res, u32 len)
res);
}

static void ffa_rx_release(struct arm_smccc_res *res)
{
arm_smccc_1_1_smc(FFA_RX_RELEASE,
0, 0,
0, 0, 0, 0, 0,
res);
}

static void do_ffa_rxtx_map(struct arm_smccc_res *res,
struct kvm_cpu_context *ctxt)
{
Expand Down Expand Up @@ -543,16 +551,19 @@ static void do_ffa_mem_reclaim(struct arm_smccc_res *res,
if (WARN_ON(offset > len ||
fraglen > KVM_FFA_MBOX_NR_PAGES * PAGE_SIZE)) {
ret = FFA_RET_ABORTED;
ffa_rx_release(res);
goto out_unlock;
}

if (len > ffa_desc_buf.len) {
ret = FFA_RET_NO_MEMORY;
ffa_rx_release(res);
goto out_unlock;
}

buf = ffa_desc_buf.buf;
memcpy(buf, hyp_buffers.rx, fraglen);
ffa_rx_release(res);

for (fragoff = fraglen; fragoff < len; fragoff += fraglen) {
ffa_mem_frag_rx(res, handle_lo, handle_hi, fragoff);
Expand All @@ -563,6 +574,7 @@ static void do_ffa_mem_reclaim(struct arm_smccc_res *res,

fraglen = res->a3;
memcpy((void *)buf + fragoff, hyp_buffers.rx, fraglen);
ffa_rx_release(res);
}

ffa_mem_reclaim(res, handle_lo, handle_hi, flags);
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/kvm/vgic/vgic-init.c
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm)

if (dist->vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3) {
list_for_each_entry_safe(rdreg, next, &dist->rd_regions, list)
vgic_v3_free_redist_region(rdreg);
vgic_v3_free_redist_region(kvm, rdreg);
INIT_LIST_HEAD(&dist->rd_regions);
} else {
dist->vgic_cpu_base = VGIC_ADDR_UNDEF;
Expand Down
15 changes: 13 additions & 2 deletions arch/arm64/kvm/vgic/vgic-mmio-v3.c
Original file line number Diff line number Diff line change
Expand Up @@ -919,8 +919,19 @@ static int vgic_v3_alloc_redist_region(struct kvm *kvm, uint32_t index,
return ret;
}

void vgic_v3_free_redist_region(struct vgic_redist_region *rdreg)
void vgic_v3_free_redist_region(struct kvm *kvm, struct vgic_redist_region *rdreg)
{
struct kvm_vcpu *vcpu;
unsigned long c;

lockdep_assert_held(&kvm->arch.config_lock);

/* Garbage collect the region */
kvm_for_each_vcpu(c, vcpu, kvm) {
if (vcpu->arch.vgic_cpu.rdreg == rdreg)
vcpu->arch.vgic_cpu.rdreg = NULL;
}

list_del(&rdreg->list);
kfree(rdreg);
}
Expand All @@ -945,7 +956,7 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count)

mutex_lock(&kvm->arch.config_lock);
rdreg = vgic_v3_rdist_region_from_index(kvm, index);
vgic_v3_free_redist_region(rdreg);
vgic_v3_free_redist_region(kvm, rdreg);
mutex_unlock(&kvm->arch.config_lock);
return ret;
}
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/kvm/vgic/vgic.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ vgic_v3_rd_region_size(struct kvm *kvm, struct vgic_redist_region *rdreg)

struct vgic_redist_region *vgic_v3_rdist_region_from_index(struct kvm *kvm,
u32 index);
void vgic_v3_free_redist_region(struct vgic_redist_region *rdreg);
void vgic_v3_free_redist_region(struct kvm *kvm, struct vgic_redist_region *rdreg);

bool vgic_v3_rdist_overlap(struct kvm *kvm, gpa_t base, size_t size);

Expand Down

0 comments on commit fb443ce

Please sign in to comment.