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

KVM/arm64 fixes for 7.2, take #3

- Fix a tiny buglet when propagating the deactivation of an interrupt
  from a nested guest, which happened to trigger a gold plated CPU bug
  on a particular implementation

- Fix a race between LPI unmapping and mapping, resulting in leaked
  LPIs

- Make LPI mapping more robust on memory allocation failure

- Fix the handling of the EL2 tracing clock being disabled

- A couple of Sashiko-driven fixes for corner cases in the EL2 tracing
  code

- Add missing sysreg tracepoint for the EL2 code

- Tidy-up the mutual exclusion of guest-memfd and MTE

- Update Fuad's email address to point to @linux.dev
This commit is contained in:
Paolo Bonzini
2026-07-28 17:43:23 +02:00
13 changed files with 93 additions and 41 deletions
+1
View File
@@ -296,6 +296,7 @@ Frank Rowand <frowand.list@gmail.com> <frank.rowand@sony.com>
Frank Rowand <frowand.list@gmail.com> <frank.rowand@sonymobile.com>
Frank Rowand <frowand.list@gmail.com> <frowand@mvista.com>
Frank Zago <fzago@systemfabricworks.com>
Fuad Tabba <fuad.tabba@linux.dev> <tabba@google.com>
Gao Xiang <xiang@kernel.org> <gaoxiang25@huawei.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@aol.com>
Gao Xiang <xiang@kernel.org> <hsiangkao@linux.alibaba.com>
@@ -55,10 +55,14 @@ stable kernels.
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | AmpereOne | AC03_CPU_38 | AMPERE_ERRATUM_AC03_CPU_38 |
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | AmpereOne | AC03_CPU_57 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | AmpereOne AC04 | AC04_CPU_10 | AMPERE_ERRATUM_AC03_CPU_38 |
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | AmpereOne AC04 | AC04_CPU_23 | AMPERE_ERRATUM_AC04_CPU_23 |
+----------------+-----------------+-----------------+-----------------------------+
| Ampere | AmpereOne AC04 | AC04_CPU_29 | N/A |
+----------------+-----------------+-----------------+-----------------------------+
+----------------+-----------------+-----------------+-----------------------------+
| ARM | Cortex-A510 | #2457168 | ARM64_ERRATUM_2457168 |
+----------------+-----------------+-----------------+-----------------------------+
+6
View File
@@ -8414,6 +8414,12 @@ When this capability is enabled all memory in memslots must be mapped as
attempts to create a memslot with an invalid mmap will result in an
-EINVAL return.
``guest_memfd``, even though it is an anonymous file, is not supported with MTE.
Attempting to create a memslot backed by ``guest_memfd`` when the MTE capability
is enabled, or attempting to enable the MTE capability after
``guest_memfd``-backed memslots have been created, will result in an -EINVAL
return.
When enabled the VMM may make use of the ``KVM_ARM_MTE_COPY_TAGS`` ioctl to
perform a bulk copy of tags to/from the guest.
+1 -1
View File
@@ -14193,7 +14193,7 @@ F: virt/kvm/*
KERNEL VIRTUAL MACHINE FOR ARM64 (KVM/arm64)
M: Marc Zyngier <maz@kernel.org>
M: Oliver Upton <oupton@kernel.org>
R: Fuad Tabba <tabba@google.com>
R: Fuad Tabba <fuad.tabba@linux.dev>
R: Joey Gouly <joey.gouly@arm.com>
R: Steffen Eiden <seiden@linux.ibm.com>
R: Suzuki K Poulose <suzuki.poulose@arm.com>
+1
View File
@@ -12,6 +12,7 @@
enum hyp_enter_exit_reason {
HYP_REASON_SMC,
HYP_REASON_HVC,
HYP_REASON_SYS,
HYP_REASON_PSCI,
HYP_REASON_HOST_ABORT,
HYP_REASON_GUEST_EXIT,
+19 -6
View File
@@ -149,14 +149,27 @@ int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
set_bit(KVM_ARCH_FLAG_RETURN_NISV_IO_ABORT_TO_USER,
&kvm->arch.flags);
break;
case KVM_CAP_ARM_MTE:
mutex_lock(&kvm->lock);
if (system_supports_mte() && !kvm->created_vcpus) {
r = 0;
set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
case KVM_CAP_ARM_MTE: {
struct kvm_memory_slot *memslot;
int bkt;
guard(mutex)(&kvm->lock);
if (!system_supports_mte() || kvm->created_vcpus)
break;
r = 0;
guard(mutex)(&kvm->slots_lock);
kvm_for_each_memslot(memslot, bkt, kvm_memslots(kvm)) {
if (kvm_slot_has_gmem(memslot)) {
r = -EINVAL;
break;
}
}
mutex_unlock(&kvm->lock);
if (r == 0)
set_bit(KVM_ARCH_FLAG_MTE_ENABLED, &kvm->arch.flags);
break;
}
case KVM_CAP_ARM_SYSTEM_SUSPEND:
r = 0;
set_bit(KVM_ARCH_FLAG_SYSTEM_SUSPEND_ENABLED, &kvm->arch.flags);
+1
View File
@@ -932,6 +932,7 @@ void handle_trap(struct kvm_cpu_context *host_ctxt)
handle_host_mem_abort(host_ctxt);
break;
case ESR_ELx_EC_SYS64:
trace_hyp_enter(host_ctxt, HYP_REASON_SYS);
if (handle_host_mte(esr))
break;
fallthrough;
+24 -12
View File
@@ -37,8 +37,6 @@ static struct hyp_trace_clock {
u32 shift;
struct delayed_work work;
struct completion ready;
struct mutex lock;
bool running;
} hyp_clock;
static void __hyp_clock_work(struct work_struct *work)
@@ -110,12 +108,9 @@ static void hyp_trace_clock_enable(struct hyp_trace_clock *hyp_clock, bool enabl
{
struct system_time_snapshot snap;
if (hyp_clock->running == enable)
return;
if (!enable) {
cancel_delayed_work_sync(&hyp_clock->work);
hyp_clock->running = false;
return;
}
ktime_get_snapshot_id(CLOCK_BOOTTIME, &snap);
@@ -128,7 +123,6 @@ static void hyp_trace_clock_enable(struct hyp_trace_clock *hyp_clock, bool enabl
INIT_DELAYED_WORK(&hyp_clock->work, __hyp_clock_work);
schedule_delayed_work(&hyp_clock->work, msecs_to_jiffies(CLOCK_INIT_MS));
wait_for_completion(&hyp_clock->ready);
hyp_clock->running = true;
}
/* Access to this struct within the trace_remote_callbacks are protected by the trace_remote lock */
@@ -160,6 +154,7 @@ static int hyp_trace_buffer_alloc_bpages_backing(struct hyp_trace_buffer *trace_
int nr_bpages = (PAGE_ALIGN(size) / PAGE_SIZE) + 1;
size_t backing_size;
void *start;
int ret;
backing_size = PAGE_ALIGN(sizeof(struct simple_buffer_page) * nr_bpages *
num_possible_cpus());
@@ -168,10 +163,16 @@ static int hyp_trace_buffer_alloc_bpages_backing(struct hyp_trace_buffer *trace_
if (!start)
return -ENOMEM;
ret = __map_hyp(start, backing_size);
if (ret) {
free_pages_exact(start, backing_size);
return ret;
}
trace_buffer->desc->bpages_backing_start = (unsigned long)start;
trace_buffer->desc->bpages_backing_size = backing_size;
return __map_hyp(start, backing_size);
return ret;
}
static void hyp_trace_buffer_free_bpages_backing(struct hyp_trace_buffer *trace_buffer)
@@ -228,18 +229,22 @@ static int hyp_trace_buffer_share_hyp(struct hyp_trace_buffer *trace_buffer)
static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
{
struct hyp_trace_buffer *trace_buffer = priv;
size_t desc_size, tb_desc_size;
struct hyp_trace_desc *desc;
size_t desc_size;
int ret;
if (WARN_ON(trace_buffer->desc))
return ERR_PTR(-EINVAL);
desc_size = trace_buffer_desc_size(size, num_possible_cpus());
tb_desc_size = trace_buffer_desc_size(size, num_possible_cpus());
desc_size = size_add(tb_desc_size, offsetof(struct hyp_trace_desc, trace_buffer_desc));
if (desc_size == SIZE_MAX)
return ERR_PTR(-E2BIG);
desc_size = PAGE_ALIGN(desc_size);
if (!desc_size)
return ERR_PTR(-E2BIG);
desc = (struct hyp_trace_desc *)alloc_pages_exact(desc_size, GFP_KERNEL);
if (!desc)
return ERR_PTR(-ENOMEM);
@@ -255,7 +260,7 @@ static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
if (ret)
goto err_free_desc;
ret = trace_remote_alloc_buffer(&desc->trace_buffer_desc, desc_size, size,
ret = trace_remote_alloc_buffer(&desc->trace_buffer_desc, tb_desc_size, size,
cpu_possible_mask);
if (ret)
goto err_free_backing;
@@ -304,9 +309,15 @@ static void hyp_trace_unload(struct trace_buffer_desc *desc, void *priv)
static int hyp_trace_enable_tracing(bool enable, void *priv)
{
int ret;
hyp_trace_clock_enable(&hyp_clock, enable);
return kvm_call_hyp_nvhe(__tracing_enable, enable);
ret = kvm_call_hyp_nvhe(__tracing_enable, enable);
if (ret)
hyp_trace_clock_enable(&hyp_clock, !enable);
return ret;
}
static int hyp_trace_swap_reader_page(unsigned int cpu, void *priv)
@@ -398,6 +409,7 @@ static const char *__hyp_enter_exit_reason_str(u8 reason)
static const char strs[][12] = {
"smc",
"hvc",
"sys",
"psci",
"host_abort",
"guest_exit",
+4
View File
@@ -2652,6 +2652,10 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
if (kvm_slot_has_gmem(new) && !kvm_memslot_is_gmem_only(new))
return -EINVAL;
/* guest_memfd is incompatible with MTE. */
if (kvm_slot_has_gmem(new) && kvm_has_mte(kvm))
return -EINVAL;
hva = new->userspace_addr;
reg_end = hva + (new->npages << PAGE_SHIFT);
+17 -8
View File
@@ -116,18 +116,27 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
kfree(irq);
irq = oldirq;
} else {
ret = xa_err(__xa_store(&dist->lpi_xa, intid, irq, 0));
/*
* The entry is either empty or contains a dead LPI (refcount=0)
* from the deferred release path, pending cleanup by
* vgic_release_deleted_lpis(). Evict and free it if present.
*/
oldirq = __xa_store(&dist->lpi_xa, intid, irq,
GFP_NOWAIT | __GFP_ACCOUNT);
ret = xa_err(oldirq);
if (ret) {
xa_unlock_irqrestore(&dist->lpi_xa, flags);
kfree(irq);
return ERR_PTR(ret);
}
if (oldirq && !WARN_ON_ONCE(refcount_read(&oldirq->refcount)))
kfree_rcu(oldirq, rcu);
}
xa_unlock_irqrestore(&dist->lpi_xa, flags);
if (ret) {
xa_release(&dist->lpi_xa, intid);
kfree(irq);
return ERR_PTR(ret);
}
/*
* We "cache" the configuration table entries in our struct vgic_irq's.
* However we only have those structs for mapped IRQs, so we read in
+7 -1
View File
@@ -275,7 +275,13 @@ void vgic_v3_deactivate(struct kvm_vcpu *vcpu, u64 val)
lr = vgic_v3_compute_lr(vcpu, irq) & ~ICH_LR_ACTIVE_BIT;
}
if (lr & ICH_LR_HW)
/*
* In the nested state, the irq has already been deactivated via the HW
* bit in the LR. Deactivating again would be harmless except AmpereOne
* errata AC03_CPU_57, AC04_CPU_29 could cause irq delivery to break if
* the deactivation hits the highest priority pending irq.
*/
if ((lr & ICH_LR_HW) && !vgic_state_is_nested(vcpu))
vgic_v3_deactivate_phys(FIELD_GET(ICH_LR_PHYS_ID_MASK, lr));
vgic_v3_fold_lr(vcpu, lr);
+8 -10
View File
@@ -146,11 +146,7 @@ static __must_check bool __vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
static __must_check bool vgic_put_irq_norelease(struct kvm *kvm, struct vgic_irq *irq)
{
if (!__vgic_put_irq(kvm, irq))
return false;
irq->pending_release = true;
return true;
return __vgic_put_irq(kvm, irq);
}
void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
@@ -167,12 +163,14 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
guard(spinlock_irqsave)(&dist->lpi_xa.xa_lock);
}
if (!__vgic_put_irq(kvm, irq))
if (!irq_is_lpi(kvm, irq->intid))
return;
xa_lock_irqsave(&dist->lpi_xa, flags);
vgic_release_lpi_locked(dist, irq);
xa_unlock_irqrestore(&dist->lpi_xa, flags);
if (refcount_dec_and_lock_irqsave(&irq->refcount,
&dist->lpi_xa.xa_lock, &flags)) {
vgic_release_lpi_locked(dist, irq);
xa_unlock_irqrestore(&dist->lpi_xa, flags);
}
}
static void vgic_release_deleted_lpis(struct kvm *kvm)
@@ -184,7 +182,7 @@ static void vgic_release_deleted_lpis(struct kvm *kvm)
xa_lock_irqsave(&dist->lpi_xa, flags);
xa_for_each(&dist->lpi_xa, intid, irq) {
if (irq->pending_release)
if (!refcount_read(&irq->refcount))
vgic_release_lpi_locked(dist, irq);
}
-3
View File
@@ -247,9 +247,6 @@ struct vgic_irq {
* affinity reg (v3).
*/
bool pending_release:1; /* Used for LPIs only, unreferenced IRQ
* pending a release */
bool pending_latch:1; /* The pending latch state used to calculate
* the pending state for both level
* and edge triggered IRQs. */