summaryrefslogtreecommitdiff
path: root/target-s390x
diff options
context:
space:
mode:
authorDominik Dingel <dingel@linux.vnet.ibm.com>2014-04-11 13:47:40 +0200
committerCornelia Huck <cornelia.huck@de.ibm.com>2014-06-10 09:50:27 +0200
commit4cb88c3c378ae8c86c0ba53619caf6924f72239c (patch)
tree9a1c2b712ab288b337c25daaec48e627961bcb6b /target-s390x
parent08da527fd07cf01dc29ca60a144fbdd60b0fb7c0 (diff)
s390x/kvm: enable/reset cmma via vm attributes
Exploit the new api for userspace-controlled cmma. If supported, enable cmma during kvm initialization and register a reset handler for cmma, which is also called directly from the load IPL code. The reset functionality is needed to reset the cmma state of the guest pages, e.g. if a system reset is triggered via qemu monitor; otherwise this could result in data corruption. A guest triggered reboot may now lead to multiple cmma resets; this is OK, however, as this is slowpath anyway and the simplest way to achieve the intended effects. Signed-off-by: Dominik Dingel <dingel@linux.vnet.ibm.com> Acked-by: Christian Borntraeger <borntraeger@de.ibm.com> Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Diffstat (limited to 'target-s390x')
-rw-r--r--target-s390x/cpu.h12
-rw-r--r--target-s390x/kvm.c58
-rw-r--r--target-s390x/misc_helper.c2
3 files changed, 72 insertions, 0 deletions
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 06454d6da5..808b906861 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -1074,6 +1074,7 @@ void kvm_s390_enable_css_support(S390CPU *cpu);
int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch,
int vq, bool assign);
int kvm_s390_cpu_restart(S390CPU *cpu);
+void kvm_s390_clear_cmma_callback(void *opaque);
#else
static inline void kvm_s390_io_interrupt(S390CPU *cpu,
uint16_t subchannel_id,
@@ -1098,8 +1099,19 @@ static inline int kvm_s390_cpu_restart(S390CPU *cpu)
{
return -ENOSYS;
}
+static inline void kvm_s390_clear_cmma_callback(void *opaque)
+{
+}
#endif
+static inline void cmma_reset(S390CPU *cpu)
+{
+ if (kvm_enabled()) {
+ CPUState *cs = CPU(cpu);
+ kvm_s390_clear_cmma_callback(cs->kvm_state);
+ }
+}
+
static inline int s390_cpu_restart(S390CPU *cpu)
{
if (kvm_enabled()) {
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 7a07f9d753..0a2a2052ee 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -32,6 +32,7 @@
#include "qemu/timer.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
+#include "hw/hw.h"
#include "cpu.h"
#include "sysemu/device_tree.h"
#include "qapi/qmp/qjson.h"
@@ -104,10 +105,67 @@ static int cap_async_pf;
static void *legacy_s390_alloc(size_t size);
+static int kvm_s390_check_clear_cmma(KVMState *s)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_S390_VM_MEM_CTRL,
+ .attr = KVM_S390_VM_MEM_CLR_CMMA,
+ };
+
+ return kvm_vm_ioctl(s, KVM_HAS_DEVICE_ATTR, &attr);
+}
+
+static int kvm_s390_check_enable_cmma(KVMState *s)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_S390_VM_MEM_CTRL,
+ .attr = KVM_S390_VM_MEM_ENABLE_CMMA,
+ };
+
+ return kvm_vm_ioctl(s, KVM_HAS_DEVICE_ATTR, &attr);
+}
+
+void kvm_s390_clear_cmma_callback(void *opaque)
+{
+ int rc;
+ KVMState *s = opaque;
+ struct kvm_device_attr attr = {
+ .group = KVM_S390_VM_MEM_CTRL,
+ .attr = KVM_S390_VM_MEM_CLR_CMMA,
+ };
+
+ rc = kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr);
+ trace_kvm_clear_cmma(rc);
+}
+
+static void kvm_s390_enable_cmma(KVMState *s)
+{
+ int rc;
+ struct kvm_device_attr attr = {
+ .group = KVM_S390_VM_MEM_CTRL,
+ .attr = KVM_S390_VM_MEM_ENABLE_CMMA,
+ };
+
+ if (kvm_s390_check_enable_cmma(s) || kvm_s390_check_clear_cmma(s)) {
+ return;
+ }
+
+ rc = kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr);
+ if (!rc) {
+ qemu_register_reset(kvm_s390_clear_cmma_callback, s);
+ }
+ trace_kvm_enable_cmma(rc);
+}
+
int kvm_arch_init(KVMState *s)
{
cap_sync_regs = kvm_check_extension(s, KVM_CAP_SYNC_REGS);
cap_async_pf = kvm_check_extension(s, KVM_CAP_ASYNC_PF);
+
+ if (kvm_check_extension(s, KVM_CAP_VM_ATTRIBUTES)) {
+ kvm_s390_enable_cmma(s);
+ }
+
if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
|| !kvm_check_extension(s, KVM_CAP_S390_COW)) {
phys_mem_set_alloc(legacy_s390_alloc);
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index 9dae0256fa..519edb81dd 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -136,6 +136,7 @@ static int modified_clear_reset(S390CPU *cpu)
pause_all_vcpus();
cpu_synchronize_all_states();
cpu_full_reset_all();
+ cmma_reset(cpu);
io_subsystem_reset();
scc->load_normal(CPU(cpu));
cpu_synchronize_all_post_reset();
@@ -150,6 +151,7 @@ static int load_normal_reset(S390CPU *cpu)
pause_all_vcpus();
cpu_synchronize_all_states();
cpu_reset_all();
+ cmma_reset(cpu);
io_subsystem_reset();
scc->initial_cpu_reset(CPU(cpu));
scc->load_normal(CPU(cpu));