diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak index 6ee2ff89ff555dfccf6158d33a2d0bec748df2d6..f9e13f177e660d34bef64432633c72e7930436f7 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 03c5e89f4eae420d66fdf900f628d30b2deb7531..02e10b750db8733a0ed13c4ea3742b7182843362 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 d6c0a490717fc9015477be41993bb2715652dbb0..54d0835f0ad1492964dff96ed06af5869d95e7c7 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 dc455a2bb7a4981d146c5f5d477f8f8d6dee672e..3c086f6155b28e15a4ccb7df93da87e1f1286584 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 55a5581d1bf608c431c6b76eb2cb78785bab0720..047c9636982ebdcf2f5038d2b4387ba6b9200540 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 810a6ef1fc0fe7e5beee365283a588ca4096101d..96b1890b4cba16339e52ca2dbf0f89dc5d8aaf7f 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 dac00cec7c665f0c65ce024352bb1fbbf5ac8cce..afb539adeab1aba750ad48a1233ae409b80f8754 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 412e49ba33c3d2ec9772fa52d362487c6d10b644..bdb538859f5fee3a8a49b4d00a4cb517a7aa24ad 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 fce52a929ccb4f3269dc402126a168983df68f06..130535cdc311bf9d6633268dc138fa01e374c1a2 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 3792463080806ccc899a31f2a45d583dc8adc21e..197e6c0214515b02a2ba8a51e749e7c6a95cd7c2 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -224,6 +224,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 diff --git a/kvm-all.c b/kvm-all.c index cbedc2564eaf49a853d2f9d46cab1cbba053f4ff..55025cc366992b2a1d4a21b426edffe3e37f0ff6 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 837624db46b68e891f5223f7d39d574b7c65691f..ad07ddecd037aa5acba48eabab77e9bd5bc686fb 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 0171de01795005c7a0f578bc0261209440b2368c..8135dda3188d1f2432145ad6707c635c82d57ab6 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 896534bf95a269d0bc3686bd7939906063975c9a..b48c643b36a7d18f6cca36018801595103a5cc23 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