aboutsummaryrefslogtreecommitdiff
path: root/virt
diff options
context:
space:
mode:
Diffstat (limited to 'virt')
-rw-r--r--virt/kvm/Kconfig1
-rw-r--r--virt/kvm/arm/arm.c34
-rw-r--r--virt/kvm/arm/trace.h1
-rw-r--r--virt/kvm/arm/vgic/trace.h1
-rw-r--r--virt/kvm/arm/vgic/vgic-its.c73
-rw-r--r--virt/kvm/coalesced_mmio.c1
-rw-r--r--virt/kvm/coalesced_mmio.h1
-rw-r--r--virt/kvm/kvm_main.c8
-rw-r--r--virt/kvm/vfio.h1
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