mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 14:33:24 -04:00
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull kvm fixes from Paolo Bonzini:
"arm64:
- 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
s390:
- several fixes for PCI passthru in s390 kvm
- fix a 7.2-rc regression in the adapter interrupt mapping code
x86:
- Add memory clobber to asm for VMX instructions; without one, the
compiler could reorder them in troublesome ways because "asm
volatile" and "asm goto" only protect against removal of the asm.
- Cancel delayed I/O APIC EOI handling before destroying vCPUs
- Check all address spaces (normal and SMM) for write tracking and large
pages, not just the current one.
- Always update x2APIC MSR intercepts for L1 when AVIC is deactivated,
even if not running L1. If the deactivation is VM-wide rather than being
caused by something in L2's vCPU state, after a nested vmexit L1 will
be able to access the host's APIC state"
* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (21 commits)
KVM: SVM: Update x2APIC MSR intercepts if AVIC is inhibited while L2 is active
KVM: x86/mmu: Check all address spaces before skipping unsync
KVM: x86/mmu: Check write tracking in all address spaces
KVM: x86: Cancel delayed I/O APIC EOI handling before destroying vCPUs
KVM: VMX: add memory clobber to asm for VMX instructions
KVM: s390: Fall back to short-term pinning in MAP ioctl
KVM: s390: pci: Validate AIBV and AISB before pinning guest pages
KVM: s390: pci: Fix resource leak on IRQ registration failure
KVM: s390: pci: Fix NULL dereference on AIBV allocation failure
KVM: s390: pci: Fix missing error codes and memory unaccounting
KVM: s390: pci: Fix memory accounting for pinned/unpinned pages
KVM: s390: pci: Reject adapter interrupt forwarding if already enabled
KVM: arm64: Reject guest_memfd memslots when the VM has MTE
KVM: arm64: Add missing hyp_enter when trapping sysreg
KVM: arm64: Fix hyp_trace_desc allocation size in hyp_trace_load()
KVM: arm64: Fix potential leak in hyp_trace_buffer_alloc_bpages_backing
KVM: arm64: Fix hyp_trace clock disabling
KVM: arm64: vgic: Mitigate potential LPI registration failure
KVM: arm64: vgic: Fix race between LPI release and re-registration
KVM: arm64: Update Fuad Tabba's email address
...
This commit is contained in:
1
.mailmap
1
.mailmap
@@ -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 |
|
||||
+----------------+-----------------+-----------------+-----------------------------+
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -112,9 +112,20 @@ Groups:
|
||||
mask or unmask the adapter, as specified in mask
|
||||
|
||||
KVM_S390_IO_ADAPTER_MAP
|
||||
This is now a no-op. The mapping is purely done by the irq route.
|
||||
Map an adapter indicator or summary page for long-term pinning so that
|
||||
interrupt injection can be performed in atomic context. If long-term
|
||||
pinning is not possible (e.g. file-backed memory), the page is verified
|
||||
via a short-term pin and the ioctl returns success; interrupt injection
|
||||
will use the non-atomic irqfd path with short-term pinning on each
|
||||
interrupt. In Secure Execution mode this is a no-op and the ioctl
|
||||
returns success.
|
||||
|
||||
KVM_S390_IO_ADAPTER_UNMAP
|
||||
This is now a no-op. The mapping is purely done by the irq route.
|
||||
Unmap a previously mapped adapter indicator or summary page and release
|
||||
the long-term pin. If the page was not long-term pinned (e.g. file-backed
|
||||
memory), the map entry is removed and success is returned; if no prior
|
||||
map entry exists, -ENOENT is returned. In Secure Execution mode this is
|
||||
a no-op and the ioctl returns success.
|
||||
|
||||
KVM_DEV_FLIC_AISM
|
||||
modify the adapter-interruption-suppression mode for a given isc if the
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -476,6 +476,11 @@ struct s390_map_info {
|
||||
__u64 guest_addr;
|
||||
__u64 addr;
|
||||
struct page *page;
|
||||
/*
|
||||
* True if the page is long-term pinned. False if long-term pinning
|
||||
* failed and this entry exists only to preserve MAP/UNMAP symmetry.
|
||||
*/
|
||||
bool pinned;
|
||||
};
|
||||
|
||||
struct s390_io_adapter {
|
||||
|
||||
@@ -2520,8 +2520,22 @@ static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
|
||||
map->addr = host_addr;
|
||||
map->page = pin_map_page(kvm, host_addr, FOLL_LONGTERM);
|
||||
if (!map->page) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
/*
|
||||
* Long-term pinning may fail for memory types such as file-backed
|
||||
* memory. Verify that short-term pinning succeeds so that the
|
||||
* non-atomic irqfd path can handle interrupt injection.
|
||||
*/
|
||||
map->page = pin_map_page(kvm, host_addr, 0);
|
||||
if (!map->page) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
unpin_user_page(map->page);
|
||||
map->page = NULL;
|
||||
map->pinned = false;
|
||||
/* Add an entry to preserve MAP/UNMAP symmetry. */
|
||||
} else {
|
||||
map->pinned = true;
|
||||
}
|
||||
spin_lock_irqsave(&adapter->maps_lock, flags);
|
||||
if (adapter->nr_maps < MAX_S390_ADAPTER_MAPS) {
|
||||
@@ -2532,7 +2546,7 @@ static int kvm_s390_adapter_map(struct kvm *kvm, unsigned int id, __u64 addr)
|
||||
ret = -EINVAL;
|
||||
}
|
||||
spin_unlock_irqrestore(&adapter->maps_lock, flags);
|
||||
if (ret)
|
||||
if (ret && map->page)
|
||||
unpin_user_page(map->page);
|
||||
out:
|
||||
if (ret)
|
||||
@@ -2546,6 +2560,7 @@ static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
|
||||
struct s390_map_info *map, *tmp, *map_to_free;
|
||||
struct page *map_page_to_put = NULL;
|
||||
u64 map_addr_to_mark = 0;
|
||||
bool map_pinned = false;
|
||||
unsigned long flags;
|
||||
int found = 0, idx;
|
||||
|
||||
@@ -2560,6 +2575,7 @@ static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
|
||||
list_del(&map->list);
|
||||
map_page_to_put = map->page;
|
||||
map_addr_to_mark = map->guest_addr;
|
||||
map_pinned = map->pinned;
|
||||
map_to_free = map;
|
||||
break;
|
||||
}
|
||||
@@ -2568,11 +2584,18 @@ static int kvm_s390_adapter_unmap(struct kvm *kvm, unsigned int id, __u64 addr)
|
||||
|
||||
if (found) {
|
||||
kfree(map_to_free);
|
||||
idx = srcu_read_lock(&kvm->srcu);
|
||||
mark_page_dirty(kvm, map_addr_to_mark >> PAGE_SHIFT);
|
||||
set_page_dirty_lock(map_page_to_put);
|
||||
srcu_read_unlock(&kvm->srcu, idx);
|
||||
unpin_user_page(map_page_to_put);
|
||||
if (map_pinned) {
|
||||
/*
|
||||
* Only long-term pinned pages need to be marked dirty
|
||||
* and released. Fallback entries exist only for
|
||||
* MAP/UNMAP symmetry.
|
||||
*/
|
||||
idx = srcu_read_lock(&kvm->srcu);
|
||||
mark_page_dirty(kvm, map_addr_to_mark >> PAGE_SHIFT);
|
||||
set_page_dirty_lock(map_page_to_put);
|
||||
srcu_read_unlock(&kvm->srcu, idx);
|
||||
unpin_user_page(map_page_to_put);
|
||||
}
|
||||
}
|
||||
|
||||
return found ? 0 : -ENOENT;
|
||||
@@ -2598,11 +2621,13 @@ void kvm_s390_unmap_all_adapters(struct kvm *kvm)
|
||||
|
||||
list_for_each_entry_safe(map, tmp, &local_list, list) {
|
||||
list_del(&map->list);
|
||||
idx = srcu_read_lock(&kvm->srcu);
|
||||
mark_page_dirty(kvm, map->guest_addr >> PAGE_SHIFT);
|
||||
set_page_dirty_lock(map->page);
|
||||
srcu_read_unlock(&kvm->srcu, idx);
|
||||
unpin_user_page(map->page);
|
||||
if (map->pinned) {
|
||||
idx = srcu_read_lock(&kvm->srcu);
|
||||
mark_page_dirty(kvm, map->guest_addr >> PAGE_SHIFT);
|
||||
set_page_dirty_lock(map->page);
|
||||
srcu_read_unlock(&kvm->srcu, idx);
|
||||
unpin_user_page(map->page);
|
||||
}
|
||||
kfree(map);
|
||||
}
|
||||
}
|
||||
@@ -2929,8 +2954,11 @@ static struct s390_map_info *get_map_info(struct s390_io_adapter *adapter,
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(map, &adapter->maps, list) {
|
||||
if (map->addr == addr)
|
||||
if (map->addr == addr) {
|
||||
if (!map->pinned)
|
||||
return NULL;
|
||||
return map;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -190,40 +190,61 @@ static int kvm_zpci_clear_airq(struct zpci_dev *zdev)
|
||||
return cc ? -EIO : 0;
|
||||
}
|
||||
|
||||
static inline void unaccount_mem(unsigned long nr_pages)
|
||||
static inline void unaccount_mem(struct kvm_zdev *kzdev, unsigned long nr_pages)
|
||||
{
|
||||
struct user_struct *user = get_uid(current_user());
|
||||
struct user_struct *user = kzdev->user_account;
|
||||
struct mm_struct *mm_account = kzdev->mm_account;
|
||||
|
||||
if (user)
|
||||
if (user) {
|
||||
atomic_long_sub(nr_pages, &user->locked_vm);
|
||||
if (current->mm)
|
||||
atomic64_sub(nr_pages, ¤t->mm->pinned_vm);
|
||||
free_uid(user);
|
||||
kzdev->user_account = NULL;
|
||||
}
|
||||
|
||||
if (mm_account) {
|
||||
atomic64_sub(nr_pages, &mm_account->pinned_vm);
|
||||
mmdrop(mm_account);
|
||||
kzdev->mm_account = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int account_mem(unsigned long nr_pages)
|
||||
static inline int account_mem(struct kvm_zdev *kzdev, unsigned long nr_pages)
|
||||
{
|
||||
struct user_struct *user = get_uid(current_user());
|
||||
unsigned long page_limit, cur_pages, new_pages;
|
||||
int rc = 0;
|
||||
|
||||
page_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
|
||||
|
||||
cur_pages = atomic_long_read(&user->locked_vm);
|
||||
do {
|
||||
new_pages = cur_pages + nr_pages;
|
||||
if (new_pages > page_limit)
|
||||
return -ENOMEM;
|
||||
if (new_pages > page_limit) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
} while (!atomic_long_try_cmpxchg(&user->locked_vm, &cur_pages, new_pages));
|
||||
|
||||
atomic64_add(nr_pages, ¤t->mm->pinned_vm);
|
||||
if (current->mm) {
|
||||
mmgrab(current->mm);
|
||||
atomic64_add(nr_pages, ¤t->mm->pinned_vm);
|
||||
}
|
||||
|
||||
kzdev->user_account = user;
|
||||
kzdev->mm_account = current->mm;
|
||||
|
||||
return 0;
|
||||
|
||||
out:
|
||||
free_uid(user);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
|
||||
bool assist)
|
||||
{
|
||||
struct page *pages[1], *aibv_page, *aisb_page = NULL;
|
||||
unsigned int msi_vecs, idx;
|
||||
unsigned int msi_vecs, idx, size;
|
||||
struct zpci_gaite *gaite;
|
||||
unsigned long hva, bit;
|
||||
struct kvm *kvm;
|
||||
@@ -237,6 +258,10 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
|
||||
if (zdev->gisa == 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* AIF already enabled for the device */
|
||||
if (zdev->kzdev->fib.fmt0.aibv != 0)
|
||||
return -EINVAL;
|
||||
|
||||
kvm = zdev->kzdev->kvm;
|
||||
msi_vecs = min_t(unsigned int, fib->fmt0.noi, zdev->max_msi);
|
||||
|
||||
@@ -246,6 +271,14 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
|
||||
return gisc;
|
||||
|
||||
/* Replace AIBV address */
|
||||
size = BITS_TO_LONGS(msi_vecs + fib->fmt0.aibvo) * sizeof(unsigned long);
|
||||
npages = DIV_ROUND_UP((fib->fmt0.aibv & ~PAGE_MASK) + size, PAGE_SIZE);
|
||||
/* AIBV cannot span more than 1 page */
|
||||
if (npages > 1) {
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
idx = srcu_read_lock(&kvm->srcu);
|
||||
hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aibv));
|
||||
npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM, pages);
|
||||
@@ -261,6 +294,12 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
|
||||
|
||||
/* Pin the guest AISB if one was specified */
|
||||
if (fib->fmt0.sum == 1) {
|
||||
/* AISB must be dword aligned */
|
||||
if (fib->fmt0.aisb & 0x7) {
|
||||
rc = -EINVAL;
|
||||
goto unpin1;
|
||||
}
|
||||
|
||||
idx = srcu_read_lock(&kvm->srcu);
|
||||
hva = gfn_to_hva(kvm, gpa_to_gfn((gpa_t)fib->fmt0.aisb));
|
||||
npages = pin_user_pages_fast(hva, 1, FOLL_WRITE | FOLL_LONGTERM,
|
||||
@@ -275,20 +314,28 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
|
||||
}
|
||||
|
||||
/* Account for pinned pages, roll back on failure */
|
||||
if (account_mem(pcount))
|
||||
rc = account_mem(zdev->kzdev, pcount);
|
||||
if (rc)
|
||||
goto unpin2;
|
||||
|
||||
/* AISB must be allocated before we can fill in GAITE */
|
||||
mutex_lock(&aift->aift_lock);
|
||||
bit = airq_iv_alloc_bit(aift->sbv);
|
||||
if (bit == -1UL)
|
||||
if (bit == -1UL) {
|
||||
rc = -ENOMEM;
|
||||
goto unlock;
|
||||
}
|
||||
zdev->aisb = bit; /* store the summary bit number */
|
||||
zdev->aibv = airq_iv_create(msi_vecs, AIRQ_IV_DATA |
|
||||
AIRQ_IV_BITLOCK |
|
||||
AIRQ_IV_GUESTVEC,
|
||||
phys_to_virt(fib->fmt0.aibv));
|
||||
|
||||
if (!zdev->aibv) {
|
||||
rc = -ENOMEM;
|
||||
goto free_aisb;
|
||||
}
|
||||
|
||||
spin_lock_irq(&aift->gait_lock);
|
||||
gaite = aift->gait + zdev->aisb;
|
||||
|
||||
@@ -311,21 +358,39 @@ static int kvm_s390_pci_aif_enable(struct zpci_dev *zdev, struct zpci_fib *fib,
|
||||
aift->kzdev[zdev->aisb] = zdev->kzdev;
|
||||
spin_unlock_irq(&aift->gait_lock);
|
||||
|
||||
/* Update guest FIB for re-issue */
|
||||
fib->fmt0.aisbo = zdev->aisb & 63;
|
||||
fib->fmt0.aisb = virt_to_phys(aift->sbv->vector) + (zdev->aisb / 64) * 8;
|
||||
fib->fmt0.isc = gisc;
|
||||
|
||||
/* Save some guest fib values in the host for later use */
|
||||
zdev->kzdev->fib.fmt0.isc = fib->fmt0.isc;
|
||||
zdev->kzdev->fib.fmt0.isc = gisc;
|
||||
zdev->kzdev->fib.fmt0.aibv = fib->fmt0.aibv;
|
||||
mutex_unlock(&aift->aift_lock);
|
||||
|
||||
/* Issue the clp to setup the irq now */
|
||||
rc = kvm_zpci_set_airq(zdev);
|
||||
return rc;
|
||||
if (!rc) {
|
||||
mutex_unlock(&aift->aift_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Start cleanup */
|
||||
zdev->kzdev->fib.fmt0.isc = 0;
|
||||
zdev->kzdev->fib.fmt0.aibv = 0;
|
||||
|
||||
spin_lock_irq(&aift->gait_lock);
|
||||
gaite->count--;
|
||||
gaite->aisb = 0;
|
||||
gaite->gisc = 0;
|
||||
gaite->aisbo = 0;
|
||||
gaite->gisa = 0;
|
||||
aift->kzdev[zdev->aisb] = NULL;
|
||||
spin_unlock_irq(&aift->gait_lock);
|
||||
|
||||
airq_iv_release(zdev->aibv);
|
||||
zdev->aibv = NULL;
|
||||
|
||||
free_aisb:
|
||||
airq_iv_free_bit(aift->sbv, zdev->aisb);
|
||||
zdev->aisb = 0;
|
||||
unlock:
|
||||
if (pcount > 0)
|
||||
unaccount_mem(zdev->kzdev, pcount);
|
||||
mutex_unlock(&aift->aift_lock);
|
||||
unpin2:
|
||||
if (fib->fmt0.sum == 1)
|
||||
@@ -396,7 +461,7 @@ static int kvm_s390_pci_aif_disable(struct zpci_dev *zdev, bool force)
|
||||
pcount++;
|
||||
}
|
||||
if (pcount > 0)
|
||||
unaccount_mem(pcount);
|
||||
unaccount_mem(kzdev, pcount);
|
||||
out:
|
||||
mutex_unlock(&aift->aift_lock);
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ struct kvm_zdev {
|
||||
struct kvm *kvm;
|
||||
struct zpci_fib fib;
|
||||
struct list_head entry;
|
||||
struct user_struct *user_account;
|
||||
struct mm_struct *mm_account;
|
||||
};
|
||||
|
||||
struct zpci_gaite {
|
||||
|
||||
@@ -722,6 +722,26 @@ static struct kvm_lpage_info *lpage_info_slot(gfn_t gfn,
|
||||
return &slot->arch.lpage_info[level - 2][idx];
|
||||
}
|
||||
|
||||
static bool kvm_gfn_is_lpage_allowed(struct kvm *kvm,
|
||||
const struct kvm_memory_slot *slot,
|
||||
gfn_t gfn, int level)
|
||||
{
|
||||
const struct kvm_memory_slot *other_slot;
|
||||
|
||||
BUILD_BUG_ON(KVM_MAX_NR_ADDRESS_SPACES > 2);
|
||||
|
||||
if (lpage_info_slot(gfn, slot, level)->disallow_lpage)
|
||||
return false;
|
||||
|
||||
if (kvm_arch_nr_memslot_as_ids(kvm) > 1) {
|
||||
other_slot = __gfn_to_memslot(__kvm_memslots(kvm, slot->as_id ^ 1), gfn);
|
||||
if (other_slot && lpage_info_slot(gfn, other_slot, level)->disallow_lpage)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The most significant bit in disallow_lpage tracks whether or not memory
|
||||
* attributes are mixed, i.e. not identical for all gfns at the current level.
|
||||
@@ -2968,7 +2988,7 @@ int mmu_try_to_unsync_pages(struct kvm *kvm, const struct kvm_memory_slot *slot,
|
||||
* write-protected (see above), thus if the gfn can be mapped with a
|
||||
* hugepage and isn't write-tracked, it can't have a shadow page.
|
||||
*/
|
||||
if (!lpage_info_slot(gfn, slot, PG_LEVEL_2M)->disallow_lpage)
|
||||
if (kvm_gfn_is_lpage_allowed(kvm, slot, gfn, PG_LEVEL_2M))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
||||
@@ -130,13 +130,23 @@ void __kvm_write_track_remove_gfn(struct kvm *kvm,
|
||||
kvm_mmu_gfn_allow_lpage(slot, gfn);
|
||||
}
|
||||
|
||||
/*
|
||||
* check if the corresponding access on the specified guest page is tracked.
|
||||
*/
|
||||
static bool __kvm_gfn_is_write_tracked(const struct kvm_memory_slot *slot,
|
||||
gfn_t gfn)
|
||||
{
|
||||
int index;
|
||||
|
||||
if (!slot)
|
||||
return false;
|
||||
|
||||
index = gfn_to_index(gfn, slot->base_gfn, PG_LEVEL_4K);
|
||||
return !!READ_ONCE(slot->arch.gfn_write_track[index]);
|
||||
}
|
||||
|
||||
/* check if write access is tracked on the specified guest page. */
|
||||
bool kvm_gfn_is_write_tracked(struct kvm *kvm,
|
||||
const struct kvm_memory_slot *slot, gfn_t gfn)
|
||||
{
|
||||
int index;
|
||||
const struct kvm_memory_slot *other_slot;
|
||||
|
||||
if (!slot)
|
||||
return false;
|
||||
@@ -144,8 +154,18 @@ bool kvm_gfn_is_write_tracked(struct kvm *kvm,
|
||||
if (!kvm_page_track_write_tracking_enabled(kvm))
|
||||
return false;
|
||||
|
||||
index = gfn_to_index(gfn, slot->base_gfn, PG_LEVEL_4K);
|
||||
return !!READ_ONCE(slot->arch.gfn_write_track[index]);
|
||||
BUILD_BUG_ON(KVM_MAX_NR_ADDRESS_SPACES > 2);
|
||||
|
||||
if (__kvm_gfn_is_write_tracked(slot, gfn))
|
||||
return true;
|
||||
|
||||
if (kvm_arch_nr_memslot_as_ids(kvm) > 1) {
|
||||
other_slot = __gfn_to_memslot(__kvm_memslots(kvm, slot->as_id ^ 1), gfn);
|
||||
if (__kvm_gfn_is_write_tracked(other_slot, gfn))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KVM_EXTERNAL_WRITE_TRACKING
|
||||
|
||||
@@ -240,14 +240,6 @@ static void avic_deactivate_vmcb(struct vcpu_svm *svm)
|
||||
if (!is_sev_es_guest(&svm->vcpu))
|
||||
svm_set_intercept(svm, INTERCEPT_CR8_WRITE);
|
||||
|
||||
/*
|
||||
* If running nested and the guest uses its own MSR bitmap, there
|
||||
* is no need to update L0's msr bitmap
|
||||
*/
|
||||
if (is_guest_mode(&svm->vcpu) &&
|
||||
vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_MSR_PROT))
|
||||
return;
|
||||
|
||||
/* Enabling MSR intercept for x2APIC registers */
|
||||
avic_set_x2apic_msr_interception(svm, true);
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ static __always_inline unsigned long __vmcs_readl(unsigned long field)
|
||||
|
||||
: [output] "=r" (value)
|
||||
: [field] "r" (field)
|
||||
: "cc"
|
||||
: "cc", "memory"
|
||||
: do_fail, do_exception);
|
||||
|
||||
return value;
|
||||
@@ -145,7 +145,7 @@ static __always_inline unsigned long __vmcs_readl(unsigned long field)
|
||||
|
||||
: ASM_CALL_CONSTRAINT, [output] "=&r" (value)
|
||||
: [field] "r" (field)
|
||||
: "cc");
|
||||
: "cc", "memory");
|
||||
return value;
|
||||
|
||||
#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
|
||||
@@ -192,7 +192,7 @@ do { \
|
||||
asm goto("1: " __stringify(insn) " %0\n\t" \
|
||||
"jna %l[error]\n\t" \
|
||||
_ASM_EXTABLE(1b, %l[fault]) \
|
||||
: : op1 : "cc" : error, fault); \
|
||||
: : op1 : "cc", "memory" : error, fault); \
|
||||
return; \
|
||||
error: \
|
||||
instrumentation_begin(); \
|
||||
@@ -208,7 +208,7 @@ do { \
|
||||
asm goto("1: " __stringify(insn) " %1, %0\n\t" \
|
||||
"jna %l[error]\n\t" \
|
||||
_ASM_EXTABLE(1b, %l[fault]) \
|
||||
: : op1, op2 : "cc" : error, fault); \
|
||||
: : op1, op2 : "cc", "memory" : error, fault);\
|
||||
return; \
|
||||
error: \
|
||||
instrumentation_begin(); \
|
||||
|
||||
@@ -13429,9 +13429,15 @@ void kvm_arch_pre_destroy_vm(struct kvm *kvm)
|
||||
* iterating over vCPUs in a different task while vCPUs are being freed
|
||||
* is unsafe, i.e. will lead to use-after-free. The PIT also needs to
|
||||
* be stopped before IRQ routing is freed.
|
||||
*
|
||||
* Do NOT free the in-kernel PIC or I/O APIC here (but as above, make
|
||||
* sure to flush any background work), as KVM expects interrupt routing
|
||||
* structures to be valid until vCPUs are destroyed.
|
||||
*/
|
||||
#ifdef CONFIG_KVM_IOAPIC
|
||||
kvm_free_pit(kvm);
|
||||
if (kvm->arch.vioapic)
|
||||
cancel_delayed_work_sync(&kvm->arch.vioapic->eoi_inject);
|
||||
#endif
|
||||
|
||||
kvm_mmu_pre_destroy_vm(kvm);
|
||||
|
||||
@@ -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. */
|
||||
|
||||
Reference in New Issue
Block a user