summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--default-configs/s390x-softmmu.mak3
-rw-r--r--hw/intc/s390_flic.c6
-rw-r--r--hw/s390x/ipl.c3
-rw-r--r--hw/s390x/s390-pci-bus.c1
-rw-r--r--hw/s390x/s390-virtio-bus.c5
-rw-r--r--hw/s390x/s390-virtio-bus.h1
-rw-r--r--hw/s390x/s390-virtio-ccw.c67
-rw-r--r--hw/s390x/s390-virtio.c52
-rw-r--r--hw/s390x/virtio-ccw.c22
-rw-r--r--include/sysemu/kvm.h12
-rw-r--r--kvm-all.c21
-rw-r--r--qemu-options.hx12
-rw-r--r--target-s390x/cpu.h34
-rw-r--r--target-s390x/kvm.c132
14 files changed, 311 insertions, 60 deletions
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index 6ee2ff89ff..f9e13f177e 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -1,4 +1,5 @@
-include pci.mak
+CONFIG_PCI=y
+CONFIG_VIRTIO_PCI=y
 CONFIG_VIRTIO=y
 CONFIG_SCLPCONSOLE=y
 CONFIG_S390_FLIC=y
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
index 03c5e89f4e..02e10b750d 100644
--- a/hw/intc/s390_flic.c
+++ b/hw/intc/s390_flic.c
@@ -30,7 +30,6 @@ S390FLICState *s390_get_flic(void)
 void s390_flic_init(void)
 {
     DeviceState *dev;
-    int r;
 
     dev = s390_flic_kvm_create();
     if (!dev) {
@@ -38,10 +37,7 @@ void s390_flic_init(void)
         object_property_add_child(qdev_get_machine(), TYPE_QEMU_S390_FLIC,
                                   OBJECT(dev), NULL);
     }
-    r = qdev_init(dev);
-    if (r) {
-        error_report("flic: couldn't create qdev");
-    }
+    qdev_init_nofail(dev);
 }
 
 static int qemu_s390_register_io_adapter(S390FLICState *fs, uint32_t id,
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index d6c0a49071..54d0835f0a 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -142,9 +142,6 @@ static int s390_ipl_init(SysBusDevice *dev)
             bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
                                             4096);
             ipl->bios_start_addr = ZIPL_IMAGE_START;
-            if (bios_size > 4096) {
-                hw_error("stage1 bootloader is > 4k\n");
-            }
         }
         g_free(bios_filename);
 
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index dc455a2bb7..3c086f6155 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -44,6 +44,7 @@ int chsc_sei_nt2_get_event(void *res)
         QTAILQ_REMOVE(&s->pending_sei, sei_cont, link);
         nt2_res->nt = 2;
         nt2_res->cc = sei_cont->cc;
+        nt2_res->length = cpu_to_be16(sizeof(ChscSeiNt2Res));
         switch (sei_cont->cc) {
         case 1: /* error event */
             eccdf = (PciCcdfErr *)nt2_res->ccdf;
diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c
index 55a5581d1b..047c963698 100644
--- a/hw/s390x/s390-virtio-bus.c
+++ b/hw/s390x/s390-virtio-bus.c
@@ -435,11 +435,6 @@ void s390_virtio_device_update_status(VirtIOS390Device *dev)
     virtio_set_features(vdev, features);
 }
 
-VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus)
-{
-    return bus->console;
-}
-
 /* Find a device by vring address */
 VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
                                              ram_addr_t mem,
diff --git a/hw/s390x/s390-virtio-bus.h b/hw/s390x/s390-virtio-bus.h
index 810a6ef1fc..96b1890b4c 100644
--- a/hw/s390x/s390-virtio-bus.h
+++ b/hw/s390x/s390-virtio-bus.h
@@ -108,7 +108,6 @@ typedef struct VirtIOS390Bus {
 
 void s390_virtio_device_update_status(VirtIOS390Device *dev);
 
-VirtIOS390Device *s390_virtio_bus_console(VirtIOS390Bus *bus);
 VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size);
 
 VirtIOS390Device *s390_virtio_bus_find_vring(VirtIOS390Bus *bus,
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index dac00cec7c..afb539adea 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -22,6 +22,18 @@
 
 #define TYPE_S390_CCW_MACHINE               "s390-ccw-machine"
 
+#define S390_CCW_MACHINE(obj) \
+    OBJECT_CHECK(S390CcwMachineState, (obj), TYPE_S390_CCW_MACHINE)
+
+typedef struct S390CcwMachineState {
+    /*< private >*/
+    MachineState parent_obj;
+
+    /*< public >*/
+    bool aes_key_wrap;
+    bool dea_key_wrap;
+} S390CcwMachineState;
+
 void io_subsystem_reset(void)
 {
     DeviceState *css, *sclp, *flic;
@@ -181,6 +193,10 @@ static void ccw_init(MachineState *machine)
 
     /* Create VirtIO network adapters */
     s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw");
+
+    /* Register savevm handler for guest TOD clock */
+    register_savevm(NULL, "todclock", 0, 1,
+                    gtod_save, gtod_load, kvm_state);
 }
 
 static void ccw_machine_class_init(ObjectClass *oc, void *data)
@@ -203,9 +219,60 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
     nc->nmi_monitor_handler = s390_nmi;
 }
 
+static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp)
+{
+    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+
+    return ms->aes_key_wrap;
+}
+
+static inline void machine_set_aes_key_wrap(Object *obj, bool value,
+                                            Error **errp)
+{
+    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+
+    ms->aes_key_wrap = value;
+}
+
+static inline bool machine_get_dea_key_wrap(Object *obj, Error **errp)
+{
+    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+
+    return ms->dea_key_wrap;
+}
+
+static inline void machine_set_dea_key_wrap(Object *obj, bool value,
+                                            Error **errp)
+{
+    S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+
+    ms->dea_key_wrap = value;
+}
+
+static inline void s390_machine_initfn(Object *obj)
+{
+    object_property_add_bool(obj, "aes-key-wrap",
+                             machine_get_aes_key_wrap,
+                             machine_set_aes_key_wrap, NULL);
+    object_property_set_description(obj, "aes-key-wrap",
+            "enable/disable AES key wrapping using the CPACF wrapping key",
+            NULL);
+    object_property_set_bool(obj, true, "aes-key-wrap", NULL);
+
+    object_property_add_bool(obj, "dea-key-wrap",
+                             machine_get_dea_key_wrap,
+                             machine_set_dea_key_wrap, NULL);
+    object_property_set_description(obj, "dea-key-wrap",
+            "enable/disable DEA key wrapping using the CPACF wrapping key",
+            NULL);
+    object_property_set_bool(obj, true, "dea-key-wrap", NULL);
+}
+
 static const TypeInfo ccw_machine_info = {
     .name          = TYPE_S390_CCW_MACHINE,
     .parent        = TYPE_MACHINE,
+    .instance_size = sizeof(S390CcwMachineState),
+    .instance_init = s390_machine_initfn,
     .class_init    = ccw_machine_class_init,
     .interfaces = (InterfaceInfo[]) {
         { TYPE_NMI },
diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c
index 412e49ba33..bdb538859f 100644
--- a/hw/s390x/s390-virtio.c
+++ b/hw/s390x/s390-virtio.c
@@ -38,6 +38,7 @@
 #include "hw/s390x/sclp.h"
 #include "hw/s390x/s390_flic.h"
 #include "hw/s390x/s390-virtio.h"
+#include "cpu.h"
 
 //#define DEBUG_S390
 
@@ -53,6 +54,9 @@
 #define ZIPL_FILENAME                   "s390-zipl.rom"
 #define TYPE_S390_MACHINE               "s390-machine"
 
+#define S390_TOD_CLOCK_VALUE_MISSING    0x00
+#define S390_TOD_CLOCK_VALUE_PRESENT    0x01
+
 static VirtIOS390Bus *s390_bus;
 static S390CPU **ipi_states;
 
@@ -196,6 +200,51 @@ void s390_create_virtio_net(BusState *bus, const char *name)
     }
 }
 
+void gtod_save(QEMUFile *f, void *opaque)
+{
+    uint64_t tod_low;
+    uint8_t tod_high;
+    int r;
+
+    r = s390_get_clock(&tod_high, &tod_low);
+    if (r) {
+        fprintf(stderr, "WARNING: Unable to get guest clock for migration. "
+                        "Error code %d. Guest clock will not be migrated "
+                        "which could cause the guest to hang.\n", r);
+        qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING);
+        return;
+    }
+
+    qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT);
+    qemu_put_byte(f, tod_high);
+    qemu_put_be64(f, tod_low);
+}
+
+int gtod_load(QEMUFile *f, void *opaque, int version_id)
+{
+    uint64_t tod_low;
+    uint8_t tod_high;
+    int r;
+
+    if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) {
+        fprintf(stderr, "WARNING: Guest clock was not migrated. This could "
+                        "cause the guest to hang.\n");
+        return 0;
+    }
+
+    tod_high = qemu_get_byte(f);
+    tod_low = qemu_get_be64(f);
+
+    r = s390_set_clock(&tod_high, &tod_low);
+    if (r) {
+        fprintf(stderr, "WARNING: Unable to set guest clock value. "
+                        "s390_get_clock returned error %d. This could cause "
+                        "the guest to hang.\n", r);
+    }
+
+    return 0;
+}
+
 /* PC hardware initialisation */
 static void s390_init(MachineState *machine)
 {
@@ -253,6 +302,9 @@ static void s390_init(MachineState *machine)
 
     /* Create VirtIO network adapters */
     s390_create_virtio_net((BusState *)s390_bus, "virtio-net-s390");
+
+    /* Register savevm handler for guest TOD clock */
+    register_savevm(NULL, "todclock", 0, 1, gtod_save, gtod_load, NULL);
 }
 
 void s390_nmi(NMIState *n, int cpu_index, Error **errp)
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index fce52a929c..130535cdc3 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -508,7 +508,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
         if (!ccw.cda) {
             ret = -EFAULT;
         } else {
-            indicators = ldq_phys(&address_space_memory, ccw.cda);
+            indicators = ldq_be_phys(&address_space_memory, ccw.cda);
             dev->indicators = get_indicator(indicators, sizeof(uint64_t));
             sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
             ret = 0;
@@ -528,7 +528,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
         if (!ccw.cda) {
             ret = -EFAULT;
         } else {
-            indicators = ldq_phys(&address_space_memory, ccw.cda);
+            indicators = ldq_be_phys(&address_space_memory, ccw.cda);
             dev->indicators2 = get_indicator(indicators, sizeof(uint64_t));
             sch->curr_status.scsw.count = ccw.count - sizeof(indicators);
             ret = 0;
@@ -548,11 +548,11 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
         if (!ccw.cda) {
             ret = -EFAULT;
         } else {
-            vq_config.index = lduw_phys(&address_space_memory, ccw.cda);
+            vq_config.index = lduw_be_phys(&address_space_memory, ccw.cda);
             vq_config.num_max = virtio_queue_get_num(vdev,
                                                      vq_config.index);
-            stw_phys(&address_space_memory,
-                     ccw.cda + sizeof(vq_config.index), vq_config.num_max);
+            stw_be_phys(&address_space_memory,
+                        ccw.cda + sizeof(vq_config.index), vq_config.num_max);
             sch->curr_status.scsw.count = ccw.count - sizeof(vq_config);
             ret = 0;
         }
@@ -580,13 +580,17 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
             if (!thinint) {
                 ret = -EFAULT;
             } else {
+                uint64_t ind_bit = ldq_be_p(&thinint->ind_bit);
+
                 len = hw_len;
                 dev->summary_indicator =
-                    get_indicator(thinint->summary_indicator, sizeof(uint8_t));
-                dev->indicators = get_indicator(thinint->device_indicator,
-                                                thinint->ind_bit / 8 + 1);
+                    get_indicator(ldq_be_p(&thinint->summary_indicator),
+                                  sizeof(uint8_t));
+                dev->indicators =
+                    get_indicator(ldq_be_p(&thinint->device_indicator),
+                                  ind_bit / 8 + 1);
                 dev->thinint_isc = thinint->isc;
-                dev->routes.adapter.ind_offset = thinint->ind_bit;
+                dev->routes.adapter.ind_offset = ind_bit;
                 dev->routes.adapter.summary_offset = 7;
                 cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len);
                 ret = css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO,
diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h
index 3792463080..197e6c0214 100644
--- a/include/sysemu/kvm.h
+++ b/include/sysemu/kvm.h
@@ -225,6 +225,18 @@ int kvm_vcpu_ioctl(CPUState *cpu, int type, ...);
 int kvm_device_ioctl(int fd, int type, ...);
 
 /**
+ * kvm_vm_check_attr - check for existence of a specific vm attribute
+ * @s: The KVMState pointer
+ * @group: the group
+ * @attr: the attribute of that group to query for
+ *
+ * Returns: 1 if the attribute exists
+ *          0 if the attribute either does not exist or if the vm device
+ *            interface is unavailable
+ */
+int kvm_vm_check_attr(KVMState *s, uint32_t group, uint64_t attr);
+
+/**
  * kvm_create_device - create a KVM device for the device control API
  * @KVMState: The KVMState pointer
  * @type: The KVM device type (see Documentation/virtual/kvm/devices in the
diff --git a/kvm-all.c b/kvm-all.c
index cbedc2564e..55025cc366 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -126,6 +126,7 @@ bool kvm_gsi_routing_allowed;
 bool kvm_gsi_direct_mapping;
 bool kvm_allowed;
 bool kvm_readonly_mem_allowed;
+bool kvm_vm_attributes_allowed;
 
 static const KVMCapabilityInfo kvm_required_capabilites[] = {
     KVM_CAP_INFO(USER_MEMORY),
@@ -1598,6 +1599,9 @@ static int kvm_init(MachineState *ms)
     kvm_resamplefds_allowed =
         (kvm_check_extension(s, KVM_CAP_IRQFD_RESAMPLE) > 0);
 
+    kvm_vm_attributes_allowed =
+        (kvm_check_extension(s, KVM_CAP_VM_ATTRIBUTES) > 0);
+
     ret = kvm_arch_init(ms, s);
     if (ret < 0) {
         goto err;
@@ -1936,6 +1940,23 @@ int kvm_device_ioctl(int fd, int type, ...)
     return ret;
 }
 
+int kvm_vm_check_attr(KVMState *s, uint32_t group, uint64_t attr)
+{
+    int ret;
+    struct kvm_device_attr attribute = {
+        .group = group,
+        .attr = attr,
+    };
+
+    if (!kvm_vm_attributes_allowed) {
+        return 0;
+    }
+
+    ret = kvm_vm_ioctl(s, KVM_HAS_DEVICE_ATTR, &attribute);
+    /* kvm returns 0 on success for HAS_DEVICE_ATTR */
+    return ret ? 0 : 1;
+}
+
 int kvm_has_sync_mmu(void)
 {
     return kvm_check_extension(kvm_state, KVM_CAP_SYNC_MMU);
diff --git a/qemu-options.hx b/qemu-options.hx
index 837624db46..ad07ddecd0 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -37,7 +37,9 @@ DEF("machine", HAS_ARG, QEMU_OPTION_machine, \
     "                kvm_shadow_mem=size of KVM shadow MMU\n"
     "                dump-guest-core=on|off include guest memory in a core dump (default=on)\n"
     "                mem-merge=on|off controls memory merge support (default: on)\n"
-    "                iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n",
+    "                iommu=on|off controls emulated Intel IOMMU (VT-d) support (default=off)\n"
+    "                aes-key-wrap=on|off controls support for AES key wrapping (default=on)\n"
+    "                dea-key-wrap=on|off controls support for DEA key wrapping (default=on)\n",
     QEMU_ARCH_ALL)
 STEXI
 @item -machine [type=]@var{name}[,prop=@var{value}[,...]]
@@ -66,6 +68,14 @@ the host, de-duplicates identical memory pages among VMs instances
 (enabled by default).
 @item iommu=on|off
 Enables or disables emulated Intel IOMMU (VT-d) support. The default is off.
+@item aes-key-wrap=on|off
+Enables or disables AES key wrapping support on s390-ccw hosts. This feature
+controls whether AES wrapping keys will be created to allow
+execution of AES cryptographic functions.  The default is on.
+@item dea-key-wrap=on|off
+Enables or disables DEA key wrapping support on s390-ccw hosts. This feature
+controls whether DEA wrapping keys will be created to allow
+execution of DEA cryptographic functions.  The default is on.
 @end table
 ETEXI
 
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 0171de0179..8135dda318 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -401,6 +401,8 @@ void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq);
 void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq);
 int kvm_s390_inject_flic(struct kvm_s390_irq *irq);
 void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code);
+int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_clock);
+int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_clock);
 #else
 static inline void kvm_s390_virtio_irq(int config_change, uint64_t token)
 {
@@ -408,11 +410,40 @@ static inline void kvm_s390_virtio_irq(int config_change, uint64_t token)
 static inline void kvm_s390_service_interrupt(uint32_t parm)
 {
 }
+static inline int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
+{
+    return -ENOSYS;
+}
+static inline int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low)
+{
+    return -ENOSYS;
+}
 static inline void kvm_s390_access_exception(S390CPU *cpu, uint16_t code,
                                              uint64_t te_code)
 {
 }
 #endif
+
+static inline int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
+{
+    if (kvm_enabled()) {
+        return kvm_s390_get_clock(tod_high, tod_low);
+    }
+    /* Fixme TCG */
+    *tod_high = 0;
+    *tod_low = 0;
+    return 0;
+}
+
+static inline int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low)
+{
+    if (kvm_enabled()) {
+        return kvm_s390_set_clock(tod_high, tod_low);
+    }
+    /* Fixme TCG */
+    return 0;
+}
+
 S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
 unsigned int s390_cpu_halt(S390CPU *cpu);
 void s390_cpu_unhalt(S390CPU *cpu);
@@ -422,6 +453,9 @@ static inline uint8_t s390_cpu_get_state(S390CPU *cpu)
     return cpu->env.cpu_state;
 }
 
+void gtod_save(QEMUFile *f, void *opaque);
+int gtod_load(QEMUFile *f, void *opaque, int version_id);
+
 /* service interrupts are floating therefore we must not pass an cpustate */
 void s390_sclp_extint(uint32_t parm);
 
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 896534bf95..b48c643b36 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -55,6 +55,9 @@
     do { } while (0)
 #endif
 
+#define kvm_vm_check_mem_attr(s, attr) \
+    kvm_vm_check_attr(s, KVM_S390_VM_MEM_CTRL, attr)
+
 #define IPA0_DIAG                       0x8300
 #define IPA0_SIGP                       0xae00
 #define IPA0_B2                         0xb200
@@ -122,16 +125,6 @@ static int cap_async_pf;
 
 static void *legacy_s390_alloc(size_t size, uint64_t *align);
 
-static int kvm_s390_supports_mem_limit(KVMState *s)
-{
-    struct kvm_device_attr attr = {
-        .group = KVM_S390_VM_MEM_CTRL,
-        .attr = KVM_S390_VM_MEM_LIMIT_SIZE,
-    };
-
-    return (kvm_vm_ioctl(s, KVM_HAS_DEVICE_ATTR, &attr) == 0);
-}
-
 static int kvm_s390_query_mem_limit(KVMState *s, uint64_t *memory_limit)
 {
     struct kvm_device_attr attr = {
@@ -153,7 +146,7 @@ int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit)
         .addr = (uint64_t) &new_limit,
     };
 
-    if (!kvm_s390_supports_mem_limit(s)) {
+    if (!kvm_vm_check_mem_attr(s, KVM_S390_VM_MEM_LIMIT_SIZE)) {
         return 0;
     }
 
@@ -167,26 +160,6 @@ int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit)
     return kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr);
 }
 
-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;
@@ -208,7 +181,8 @@ static void kvm_s390_enable_cmma(KVMState *s)
         .attr = KVM_S390_VM_MEM_ENABLE_CMMA,
     };
 
-    if (kvm_s390_check_enable_cmma(s) || kvm_s390_check_clear_cmma(s)) {
+    if (!kvm_vm_check_mem_attr(s, KVM_S390_VM_MEM_ENABLE_CMMA) ||
+        !kvm_vm_check_mem_attr(s, KVM_S390_VM_MEM_CLR_CMMA)) {
         return;
     }
 
@@ -219,14 +193,61 @@ static void kvm_s390_enable_cmma(KVMState *s)
     trace_kvm_enable_cmma(rc);
 }
 
+static void kvm_s390_set_attr(uint64_t attr)
+{
+    struct kvm_device_attr attribute = {
+        .group = KVM_S390_VM_CRYPTO,
+        .attr  = attr,
+    };
+
+    int ret = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attribute);
+
+    if (ret) {
+        error_report("Failed to set crypto device attribute %lu: %s",
+                     attr, strerror(-ret));
+    }
+}
+
+static void kvm_s390_init_aes_kw(void)
+{
+    uint64_t attr = KVM_S390_VM_CRYPTO_DISABLE_AES_KW;
+
+    if (object_property_get_bool(OBJECT(qdev_get_machine()), "aes-key-wrap",
+                                 NULL)) {
+            attr = KVM_S390_VM_CRYPTO_ENABLE_AES_KW;
+    }
+
+    if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO, attr)) {
+            kvm_s390_set_attr(attr);
+    }
+}
+
+static void kvm_s390_init_dea_kw(void)
+{
+    uint64_t attr = KVM_S390_VM_CRYPTO_DISABLE_DEA_KW;
+
+    if (object_property_get_bool(OBJECT(qdev_get_machine()), "dea-key-wrap",
+                                 NULL)) {
+            attr = KVM_S390_VM_CRYPTO_ENABLE_DEA_KW;
+    }
+
+    if (kvm_vm_check_attr(kvm_state, KVM_S390_VM_CRYPTO, attr)) {
+            kvm_s390_set_attr(attr);
+    }
+}
+
+static void kvm_s390_init_crypto(void)
+{
+    kvm_s390_init_aes_kw();
+    kvm_s390_init_dea_kw();
+}
+
 int kvm_arch_init(MachineState *ms, 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);
-    }
+    kvm_s390_enable_cmma(s);
 
     if (!kvm_check_extension(s, KVM_CAP_S390_GMAP)
         || !kvm_check_extension(s, KVM_CAP_S390_COW)) {
@@ -262,6 +283,8 @@ void kvm_s390_reset_vcpu(S390CPU *cpu)
     if (kvm_vcpu_ioctl(cs, KVM_S390_INITIAL_RESET, NULL)) {
         error_report("Initial CPU reset failed on CPU %i", cs->cpu_index);
     }
+
+    kvm_s390_init_crypto();
 }
 
 static int can_sync_regs(CPUState *cs, int regs)
@@ -486,6 +509,45 @@ int kvm_arch_get_registers(CPUState *cs)
     return 0;
 }
 
+int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low)
+{
+    int r;
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_TOD,
+        .attr = KVM_S390_VM_TOD_LOW,
+        .addr = (uint64_t)tod_low,
+    };
+
+    r = kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
+    if (r) {
+        return r;
+    }
+
+    attr.attr = KVM_S390_VM_TOD_HIGH;
+    attr.addr = (uint64_t)tod_high;
+    return kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr);
+}
+
+int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low)
+{
+    int r;
+
+    struct kvm_device_attr attr = {
+        .group = KVM_S390_VM_TOD,
+        .attr = KVM_S390_VM_TOD_LOW,
+        .addr = (uint64_t)tod_low,
+    };
+
+    r = kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+    if (r) {
+        return r;
+    }
+
+    attr.attr = KVM_S390_VM_TOD_HIGH;
+    attr.addr = (uint64_t)tod_high;
+    return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr);
+}
+
 /*
  * Legacy layout for s390:
  * Older S390 KVM requires the topmost vma of the RAM to be