diff options
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/Kconfig | 1 | ||||
-rw-r--r-- | virt/kvm/arm/arm.c | 34 | ||||
-rw-r--r-- | virt/kvm/arm/trace.h | 1 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/trace.h | 1 | ||||
-rw-r--r-- | virt/kvm/arm/vgic/vgic-its.c | 73 | ||||
-rw-r--r-- | virt/kvm/coalesced_mmio.c | 1 | ||||
-rw-r--r-- | virt/kvm/coalesced_mmio.h | 1 | ||||
-rw-r--r-- | virt/kvm/kvm_main.c | 8 | ||||
-rw-r--r-- | virt/kvm/vfio.h | 1 |
9 files changed, 75 insertions, 46 deletions
diff --git a/virt/kvm/Kconfig b/virt/kvm/Kconfig index b0cc1a34db27..70691c08e1ed 100644 --- a/virt/kvm/Kconfig +++ b/virt/kvm/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # KVM common configuration items and defaults config HAVE_KVM diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c index 01e575b9f78b..a6524ff27de4 100644 --- a/virt/kvm/arm/arm.c +++ b/virt/kvm/arm/arm.c @@ -655,6 +655,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) */ preempt_disable(); + /* Flush FP/SIMD state that can't survive guest entry/exit */ + kvm_fpsimd_flush_cpu_state(); + kvm_pmu_flush_hwstate(vcpu); local_irq_disable(); @@ -1339,21 +1342,12 @@ static void teardown_hyp_mode(void) { int cpu; - if (is_kernel_in_hyp_mode()) - return; - free_hyp_pgds(); for_each_possible_cpu(cpu) free_page(per_cpu(kvm_arm_hyp_stack_page, cpu)); hyp_cpu_pm_exit(); } -static int init_vhe_mode(void) -{ - kvm_info("VHE mode initialized successfully\n"); - return 0; -} - /** * Inits Hyp-mode on all online CPUs */ @@ -1434,8 +1428,6 @@ static int init_hyp_mode(void) } } - kvm_info("Hyp mode initialized successfully\n"); - return 0; out_err: @@ -1509,6 +1501,7 @@ int kvm_arch_init(void *opaque) { int err; int ret, cpu; + bool in_hyp_mode; if (!is_hyp_mode_available()) { kvm_err("HYP mode not available\n"); @@ -1527,21 +1520,28 @@ int kvm_arch_init(void *opaque) if (err) return err; - if (is_kernel_in_hyp_mode()) - err = init_vhe_mode(); - else + in_hyp_mode = is_kernel_in_hyp_mode(); + + if (!in_hyp_mode) { err = init_hyp_mode(); - if (err) - goto out_err; + if (err) + goto out_err; + } err = init_subsystems(); if (err) goto out_hyp; + if (in_hyp_mode) + kvm_info("VHE mode initialized successfully\n"); + else + kvm_info("Hyp mode initialized successfully\n"); + return 0; out_hyp: - teardown_hyp_mode(); + if (!in_hyp_mode) + teardown_hyp_mode(); out_err: teardown_common_resources(); return err; diff --git a/virt/kvm/arm/trace.h b/virt/kvm/arm/trace.h index f7dc5ddd6847..e53b596f483b 100644 --- a/virt/kvm/arm/trace.h +++ b/virt/kvm/arm/trace.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_KVM_H diff --git a/virt/kvm/arm/vgic/trace.h b/virt/kvm/arm/vgic/trace.h index ed3229282888..55fed77a9f73 100644 --- a/virt/kvm/arm/vgic/trace.h +++ b/virt/kvm/arm/vgic/trace.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #if !defined(_TRACE_VGIC_H) || defined(TRACE_HEADER_MULTI_READ) #define _TRACE_VGIC_H diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c index a3754ec719c4..1f761a9991e7 100644 --- a/virt/kvm/arm/vgic/vgic-its.c +++ b/virt/kvm/arm/vgic/vgic-its.c @@ -1552,6 +1552,16 @@ static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its, { mutex_lock(&its->cmd_lock); + /* + * It is UNPREDICTABLE to enable the ITS if any of the CBASER or + * device/collection BASER are invalid + */ + if (!its->enabled && (val & GITS_CTLR_ENABLE) && + (!(its->baser_device_table & GITS_BASER_VALID) || + !(its->baser_coll_table & GITS_BASER_VALID) || + !(its->cbaser & GITS_CBASER_VALID))) + goto out; + its->enabled = !!(val & GITS_CTLR_ENABLE); /* @@ -1560,6 +1570,7 @@ static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its, */ vgic_its_process_commands(kvm, its); +out: mutex_unlock(&its->cmd_lock); } @@ -1866,37 +1877,33 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry, static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz, int start_id, entry_fn_t fn, void *opaque) { - void *entry = kzalloc(esz, GFP_KERNEL); struct kvm *kvm = its->dev->kvm; unsigned long len = size; int id = start_id; gpa_t gpa = base; + char entry[esz]; int ret; + memset(entry, 0, esz); + while (len > 0) { int next_offset; size_t byte_offset; ret = kvm_read_guest(kvm, gpa, entry, esz); if (ret) - goto out; + return ret; next_offset = fn(its, id, entry, opaque); - if (next_offset <= 0) { - ret = next_offset; - goto out; - } + if (next_offset <= 0) + return next_offset; byte_offset = next_offset * esz; id += next_offset; gpa += byte_offset; len -= byte_offset; } - ret = 1; - -out: - kfree(entry); - return ret; + return 1; } /** @@ -2014,6 +2021,14 @@ static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device) return 0; } +/** + * vgic_its_restore_itt - restore the ITT of a device + * + * @its: its handle + * @dev: device handle + * + * Return 0 on success, < 0 on error + */ static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev) { const struct vgic_its_abi *abi = vgic_its_get_abi(its); @@ -2025,6 +2040,10 @@ static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev) ret = scan_its_table(its, base, max_size, ite_esz, 0, vgic_its_restore_ite, dev); + /* scan_its_table returns +1 if all ITEs are invalid */ + if (ret > 0) + ret = 0; + return ret; } @@ -2122,11 +2141,12 @@ static int vgic_its_device_cmp(void *priv, struct list_head *a, static int vgic_its_save_device_tables(struct vgic_its *its) { const struct vgic_its_abi *abi = vgic_its_get_abi(its); + u64 baser = its->baser_device_table; struct its_device *dev; int dte_esz = abi->dte_esz; - u64 baser; - baser = its->baser_device_table; + if (!(baser & GITS_BASER_VALID)) + return 0; list_sort(NULL, &its->device_list, vgic_its_device_cmp); @@ -2181,10 +2201,7 @@ static int handle_l1_dte(struct vgic_its *its, u32 id, void *addr, ret = scan_its_table(its, gpa, SZ_64K, dte_esz, l2_start_id, vgic_its_restore_dte, NULL); - if (ret <= 0) - return ret; - - return 1; + return ret; } /** @@ -2214,8 +2231,9 @@ static int vgic_its_restore_device_tables(struct vgic_its *its) vgic_its_restore_dte, NULL); } + /* scan_its_table returns +1 if all entries are invalid */ if (ret > 0) - ret = -EINVAL; + ret = 0; return ret; } @@ -2272,17 +2290,17 @@ static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz) static int vgic_its_save_collection_table(struct vgic_its *its) { const struct vgic_its_abi *abi = vgic_its_get_abi(its); + u64 baser = its->baser_coll_table; + gpa_t gpa = BASER_ADDRESS(baser); struct its_collection *collection; u64 val; - gpa_t gpa; size_t max_size, filled = 0; int ret, cte_esz = abi->cte_esz; - gpa = BASER_ADDRESS(its->baser_coll_table); - if (!gpa) + if (!(baser & GITS_BASER_VALID)) return 0; - max_size = GITS_BASER_NR_PAGES(its->baser_coll_table) * SZ_64K; + max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; list_for_each_entry(collection, &its->collection_list, coll_list) { ret = vgic_its_save_cte(its, collection, gpa, cte_esz); @@ -2313,17 +2331,18 @@ static int vgic_its_save_collection_table(struct vgic_its *its) static int vgic_its_restore_collection_table(struct vgic_its *its) { const struct vgic_its_abi *abi = vgic_its_get_abi(its); + u64 baser = its->baser_coll_table; int cte_esz = abi->cte_esz; size_t max_size, read = 0; gpa_t gpa; int ret; - if (!(its->baser_coll_table & GITS_BASER_VALID)) + if (!(baser & GITS_BASER_VALID)) return 0; - gpa = BASER_ADDRESS(its->baser_coll_table); + gpa = BASER_ADDRESS(baser); - max_size = GITS_BASER_NR_PAGES(its->baser_coll_table) * SZ_64K; + max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K; while (read < max_size) { ret = vgic_its_restore_cte(its, gpa, cte_esz); @@ -2332,6 +2351,10 @@ static int vgic_its_restore_collection_table(struct vgic_its *its) gpa += cte_esz; read += cte_esz; } + + if (ret > 0) + return 0; + return ret; } diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c index 571c1ce37d15..9e65feb6fa58 100644 --- a/virt/kvm/coalesced_mmio.c +++ b/virt/kvm/coalesced_mmio.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * KVM coalesced MMIO * diff --git a/virt/kvm/coalesced_mmio.h b/virt/kvm/coalesced_mmio.h index 6bca74ca5331..36f84264ed25 100644 --- a/virt/kvm/coalesced_mmio.h +++ b/virt/kvm/coalesced_mmio.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __KVM_COALESCED_MMIO_H__ #define __KVM_COALESCED_MMIO_H__ diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 9deb5a245b83..2dd1a9ca4599 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -122,7 +122,6 @@ static void hardware_disable_all(void); static void kvm_io_bus_destroy(struct kvm_io_bus *bus); -static void kvm_release_pfn_dirty(kvm_pfn_t pfn); static void mark_page_dirty_in_slot(struct kvm_memory_slot *memslot, gfn_t gfn); __visible bool kvm_rebooting; @@ -1679,11 +1678,12 @@ void kvm_release_page_dirty(struct page *page) } EXPORT_SYMBOL_GPL(kvm_release_page_dirty); -static void kvm_release_pfn_dirty(kvm_pfn_t pfn) +void kvm_release_pfn_dirty(kvm_pfn_t pfn) { kvm_set_pfn_dirty(pfn); kvm_release_pfn_clean(pfn); } +EXPORT_SYMBOL_GPL(kvm_release_pfn_dirty); void kvm_set_pfn_dirty(kvm_pfn_t pfn) { @@ -2302,7 +2302,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me, bool yield_to_kernel_mode) continue; } else if (pass && i > last_boosted_vcpu) break; - if (!ACCESS_ONCE(vcpu->preempted)) + if (!READ_ONCE(vcpu->preempted)) continue; if (vcpu == me) continue; @@ -4010,7 +4010,7 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align, if (!vcpu_align) vcpu_align = __alignof__(struct kvm_vcpu); kvm_vcpu_cache = kmem_cache_create("kvm_vcpu", vcpu_size, vcpu_align, - 0, NULL); + SLAB_ACCOUNT, NULL); if (!kvm_vcpu_cache) { r = -ENOMEM; goto out_free_3; diff --git a/virt/kvm/vfio.h b/virt/kvm/vfio.h index ab88c7dc0514..e130a4a03530 100644 --- a/virt/kvm/vfio.h +++ b/virt/kvm/vfio.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef __KVM_VFIO_H #define __KVM_VFIO_H |