diff options
| author | Mark Brown <broonie@kernel.org> | 2026-07-26 21:20:47 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-07-26 21:20:47 +0100 |
| commit | acbb909b497be185ab2e67ebd10fbb00084ccc7e (patch) | |
| tree | 0370f3a12611f860235379a758d480abb93dd929 | |
| parent | dbc916aaae6240f3204101c0c94d1bd93252b712 (diff) | |
| parent | 679d7201c1f09e37fa1c12ce28d84079c17fc87f (diff) | |
| download | linux-next-acbb909b497be185ab2e67ebd10fbb00084ccc7e.tar.gz linux-next-acbb909b497be185ab2e67ebd10fbb00084ccc7e.zip | |
Merge branch 'fixes' of https://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git
| -rw-r--r-- | .mailmap | 1 | ||||
| -rw-r--r-- | Documentation/arch/arm64/silicon-errata.rst | 4 | ||||
| -rw-r--r-- | Documentation/virt/kvm/api.rst | 6 | ||||
| -rw-r--r-- | MAINTAINERS | 2 | ||||
| -rw-r--r-- | arch/arm64/include/asm/kvm_hypevents.h | 1 | ||||
| -rw-r--r-- | arch/arm64/kvm/arm.c | 25 | ||||
| -rw-r--r-- | arch/arm64/kvm/hyp/nvhe/hyp-main.c | 1 | ||||
| -rw-r--r-- | arch/arm64/kvm/hyp_trace.c | 36 | ||||
| -rw-r--r-- | arch/arm64/kvm/mmu.c | 4 | ||||
| -rw-r--r-- | arch/arm64/kvm/vgic/vgic-its.c | 25 | ||||
| -rw-r--r-- | arch/arm64/kvm/vgic/vgic-v3.c | 8 | ||||
| -rw-r--r-- | arch/arm64/kvm/vgic/vgic.c | 18 | ||||
| -rw-r--r-- | include/kvm/arm_vgic.h | 3 |
13 files changed, 93 insertions, 41 deletions
@@ -297,6 +297,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> diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst index 014aa1c215a1..88b4aa45a206 100644 --- a/Documentation/arch/arm64/silicon-errata.rst +++ b/Documentation/arch/arm64/silicon-errata.rst @@ -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 | +----------------+-----------------+-----------------+-----------------------------+ diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index a5f9ee92f43e..e3003a241d5b 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -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. diff --git a/MAINTAINERS b/MAINTAINERS index 1d58335770f7..28714c64d390 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -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> diff --git a/arch/arm64/include/asm/kvm_hypevents.h b/arch/arm64/include/asm/kvm_hypevents.h index 743c49bd878f..5f6e6789d121 100644 --- a/arch/arm64/include/asm/kvm_hypevents.h +++ b/arch/arm64/include/asm/kvm_hypevents.h @@ -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, diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 50adfff75be8..9a6c72a18672 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -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); diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c index d3c69de698f4..d3df96ed8ba4 100644 --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c @@ -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; diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c index 2411b4c32932..9644c424819b 100644 --- a/arch/arm64/kvm/hyp_trace.c +++ b/arch/arm64/kvm/hyp_trace.c @@ -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", diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c index 6c941aaa10c6..2d95203386ba 100644 --- a/arch/arm64/kvm/mmu.c +++ b/arch/arm64/kvm/mmu.c @@ -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); diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c index 740b39875728..36ab3e492915 100644 --- a/arch/arm64/kvm/vgic/vgic-its.c +++ b/arch/arm64/kvm/vgic/vgic-its.c @@ -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 diff --git a/arch/arm64/kvm/vgic/vgic-v3.c b/arch/arm64/kvm/vgic/vgic-v3.c index 9e841e7afd4a..7aa417440f6a 100644 --- a/arch/arm64/kvm/vgic/vgic-v3.c +++ b/arch/arm64/kvm/vgic/vgic-v3.c @@ -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); diff --git a/arch/arm64/kvm/vgic/vgic.c b/arch/arm64/kvm/vgic/vgic.c index ccb7e3a90cd0..74bace10a22e 100644 --- a/arch/arm64/kvm/vgic/vgic.c +++ b/arch/arm64/kvm/vgic/vgic.c @@ -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); } diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index fe49fb56dc3c..cefddc9c621d 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -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. */ |
