diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-08-31 11:29:41 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-08-31 11:29:41 +0100 |
commit | 1415e8ea1fa24ad94b49a03aaf9d21fc95aaa129 (patch) | |
tree | 205bb4ccc831f6db1866e45985d96137457f42f6 | |
parent | 1201d308519f1e915866d7583d5136d03cc1d384 (diff) | |
parent | 2f21b8d431030bcb7478ee9521bdfd3d0ef3901d (diff) | |
download | qemu-1415e8ea1fa24ad94b49a03aaf9d21fc95aaa129.zip qemu-1415e8ea1fa24ad94b49a03aaf9d21fc95aaa129.tar.gz qemu-1415e8ea1fa24ad94b49a03aaf9d21fc95aaa129.tar.bz2 |
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20170830' into staging
First batch of s390x patches:
- 2.11 compat machine
- support the new --s390-pgste linker option, making it possible to
avoid enabling the global vm.allocate_pgste systl if all pieces
are in place
- correctly identify some devices as not hotpluggable
- clean up some tests and enable them for s390x
- wire up the diag288 watchdog in tcg
- clean up dependencies on CONFIG_PCI, making it possible to disable
it by hand
- lots of cleanup in target/s390x/
- fix alignment of the ccw1 structure in the s390-ccw bios
- and some more bugfixes
# gpg: Signature made Wed 30 Aug 2017 17:40:34 BST
# gpg: using RSA key 0xDECF6B93C6F02FAF
# gpg: Good signature from "Cornelia Huck <conny@cornelia-huck.de>"
# gpg: aka "Cornelia Huck <huckc@linux.vnet.ibm.com>"
# gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>"
# gpg: aka "Cornelia Huck <cohuck@kernel.org>"
# gpg: aka "Cornelia Huck <cohuck@redhat.com>"
# Primary key fingerprint: C3D0 D66D C362 4FF6 A8C0 18CE DECF 6B93 C6F0 2FAF
* remotes/cohuck/tags/s390x-20170830: (44 commits)
s390x/pci: fixup trap_msix()
pc-bios/s390-ccw.img: update image
s390-ccw: Fix alignment for CCW1
s390x/s390-stattrib: Mark the storage attribute as not user_creatable
target/s390x: cleanup cpu.h
s390x/kvm: move KVM declarations and stubs to separate files
s390x: avoid calling kvm_ functions outside of target/s390x/
target/s390x: move a couple of functions to cpu.c
target/s390x: introduce internal.h
target/s390x: move get_per_in_range() to misc_helper.c
target/s390x: move s390_do_cpu_reset() to diag.c
target/s390x: move psw_key_valid() to mem_helper.c
target/s390x: move cpu_mmu_idx_to_asc() to excp_helper.c
target/s390x: move cc_name() to helper.c
target/s390x: move gtod_*() declarations to s390-virtio.h
s390x: drop inclusion of sysemu/kvm.h from some files
s390x/cpumodel: factor out determination of default model name
target/s390x: no need to pass kvm_state to savevm_gtod handlers
target/s390x: simplify gs_allowed()
target/s390x: simplify ri_allowed()
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
62 files changed, 1257 insertions, 853 deletions
diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index 46ce479..f85553a 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -1248,7 +1248,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev) int virq; MSIMessage msg = {0, 0}; - if (dev) { + if (pci_available && dev) { msg = pci_get_msi_message(dev, vector); } @@ -1271,7 +1271,7 @@ int kvm_irqchip_add_msi_route(KVMState *s, int vector, PCIDevice *dev) kroute.u.msi.address_lo = (uint32_t)msg.address; kroute.u.msi.address_hi = msg.address >> 32; kroute.u.msi.data = le32_to_cpu(msg.data); - if (kvm_msi_devid_required()) { + if (pci_available && kvm_msi_devid_required()) { kroute.flags = KVM_MSI_VALID_DEVID; kroute.u.msi.devid = pci_requester_id(dev); } @@ -1309,7 +1309,7 @@ int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg, kroute.u.msi.address_lo = (uint32_t)msg.address; kroute.u.msi.address_hi = msg.address >> 32; kroute.u.msi.data = le32_to_cpu(msg.data); - if (kvm_msi_devid_required()) { + if (pci_available && kvm_msi_devid_required()) { kroute.flags = KVM_MSI_VALID_DEVID; kroute.u.msi.devid = pci_requester_id(dev); } @@ -240,6 +240,11 @@ supported_target() { return 1 } + +ld_has() { + $ld --help 2>/dev/null | grep ".$1" >/dev/null 2>&1 +} + # default parameters source_path=$(dirname "$0") cpu="" @@ -5043,7 +5048,7 @@ fi # Use ASLR, no-SEH and DEP if available if test "$mingw32" = "yes" ; then for flag in --dynamicbase --no-seh --nxcompat; do - if $ld --help 2>/dev/null | grep ".$flag" >/dev/null 2>/dev/null ; then + if ld_has $flag ; then LDFLAGS="-Wl,$flag $LDFLAGS" fi done @@ -6522,6 +6527,20 @@ if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then ldflags="$ldflags $textseg_ldflags" fi +# Newer kernels on s390 check for an S390_PGSTE program header and +# enable the pgste page table extensions in that case. This makes +# the vm.allocate_pgste sysctl unnecessary. We enable this program +# header if +# - we build on s390x +# - we build the system emulation for s390x (qemu-system-s390x) +# - KVM is enabled +# - the linker supports --s390-pgste +if test "$TARGET_ARCH" = "s390x" -a "$target_softmmu" = "yes" -a "$ARCH" = "s390x" -a "$kvm" = "yes"; then + if ld_has --s390-pgste ; then + ldflags="-Wl,--s390-pgste $ldflags" + fi +fi + echo "LDFLAGS+=$ldflags" >> $config_target_mak echo "QEMU_CFLAGS+=$cflags" >> $config_target_mak diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak index 51191b7..6ab2bc6 100644 --- a/default-configs/s390x-softmmu.mak +++ b/default-configs/s390x-softmmu.mak @@ -1,5 +1,5 @@ CONFIG_PCI=y -CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_PCI=$(CONFIG_PCI) CONFIG_VHOST_USER_SCSI=$(and $(CONFIG_VHOST_USER),$(CONFIG_LINUX)) CONFIG_VIRTIO=y CONFIG_SCLPCONSOLE=y diff --git a/fsdev/Makefile.objs b/fsdev/Makefile.objs index 659df6e..fb38017 100644 --- a/fsdev/Makefile.objs +++ b/fsdev/Makefile.objs @@ -1,10 +1,7 @@ -ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add. -# only pull in the actual virtio-9p device if we also enabled virtio. -common-obj-y = qemu-fsdev.o 9p-marshal.o 9p-iov-marshal.o -else -common-obj-y = qemu-fsdev-dummy.o -endif +# only pull in the actual 9p backend if we also enabled virtio or xen. +common-obj-$(call land,$(CONFIG_VIRTFS),$(call lor,$(CONFIG_VIRTIO),$(CONFIG_XEN))) = qemu-fsdev.o 9p-marshal.o 9p-iov-marshal.o +common-obj-$(call lnot,$(call land,$(CONFIG_VIRTFS),$(call lor,$(CONFIG_VIRTIO),$(CONFIG_XEN)))) = qemu-fsdev-dummy.o common-obj-y += qemu-fsdev-opts.o qemu-fsdev-throttle.o # Toplevel always builds this; targets without virtio will put it in diff --git a/hw/9pfs/Makefile.objs b/hw/9pfs/Makefile.objs index cab5e94..fd90b62 100644 --- a/hw/9pfs/Makefile.objs +++ b/hw/9pfs/Makefile.objs @@ -7,4 +7,4 @@ common-obj-$(CONFIG_OPEN_BY_HANDLE) += 9p-handle.o common-obj-y += 9p-proxy.o common-obj-$(CONFIG_XEN) += xen-9p-backend.o -obj-y += virtio-9p-device.o +obj-$(CONFIG_VIRTIO) += virtio-9p-device.o diff --git a/hw/Makefile.objs b/hw/Makefile.objs index a2c61f6..cf4cb20 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,4 +1,4 @@ -devices-dirs-$(call land, $(CONFIG_VIRTIO),$(call land,$(CONFIG_VIRTFS),$(CONFIG_PCI))) += 9pfs/ +devices-dirs-$(call land,$(CONFIG_VIRTFS),$(call lor,$(CONFIG_VIRTIO),$(CONFIG_XEN))) += 9pfs/ devices-dirs-$(CONFIG_SOFTMMU) += acpi/ devices-dirs-$(CONFIG_SOFTMMU) += adc/ devices-dirs-$(CONFIG_SOFTMMU) += audio/ diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index be3fd00..7ead17a 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -13,6 +13,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "cpu.h" +#include "kvm_s390x.h" #include <sys/ioctl.h> #include "qemu/error-report.h" #include "qapi/error.h" diff --git a/hw/pci/pci-stub.c b/hw/pci/pci-stub.c index ecad664..d5ce007 100644 --- a/hw/pci/pci-stub.c +++ b/hw/pci/pci-stub.c @@ -27,6 +27,7 @@ #include "hw/pci/msi.h" bool msi_nonbroken; +bool pci_available; PciInfoList *qmp_query_pci(Error **errp) { @@ -38,3 +39,16 @@ void hmp_pcie_aer_inject_error(Monitor *mon, const QDict *qdict) { monitor_printf(mon, "PCI devices not supported\n"); } + +/* kvm-all wants this */ +MSIMessage pci_get_msi_message(PCIDevice *dev, int vector) +{ + g_assert(false); + return (MSIMessage){}; +} + +uint16_t pci_requester_id(PCIDevice *dev) +{ + g_assert(false); + return 0; +} diff --git a/hw/pci/pci.c b/hw/pci/pci.c index 258fbe5..26f346d 100644 --- a/hw/pci/pci.c +++ b/hw/pci/pci.c @@ -49,6 +49,8 @@ # define PCI_DPRINTF(format, ...) do { } while (0) #endif +bool pci_available = true; + static void pcibus_dev_print(Monitor *mon, DeviceState *dev, int indent); static char *pcibus_get_dev_path(DeviceState *dev); static char *pcibus_get_fw_dev_path(DeviceState *dev); diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index b2aade2..7ee19d3 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -11,7 +11,8 @@ obj-y += 3270-ccw.o obj-y += virtio-ccw.o obj-y += css-bridge.o obj-y += ccw-device.o -obj-y += s390-pci-bus.o s390-pci-inst.o +obj-$(CONFIG_PCI) += s390-pci-bus.o s390-pci-inst.o +obj-$(call lnot,$(CONFIG_PCI)) += s390-pci-stub.o obj-y += s390-skeys.o obj-y += s390-stattrib.o obj-$(CONFIG_KVM) += s390-skeys-kvm.o diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 1880b1a..901dc6a 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -1750,10 +1750,10 @@ int css_do_rchp(uint8_t cssid, uint8_t chpid) } /* We don't really use a channel path, so we're done here. */ - css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, + css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, 1, channel_subsys.max_cssid > 0 ? 1 : 0, chpid); if (channel_subsys.max_cssid > 0) { - css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, 0, real_cssid << 8); + css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, 1, 0, real_cssid << 8); } return 0; } @@ -2033,7 +2033,8 @@ void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, } } -void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid) +void css_queue_crw(uint8_t rsc, uint8_t erc, int solicited, + int chain, uint16_t rsid) { CrwContainer *crw_cont; @@ -2045,6 +2046,9 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid) return; } crw_cont->crw.flags = (rsc << 8) | erc; + if (solicited) { + crw_cont->crw.flags |= CRW_FLAGS_MASK_S; + } if (chain) { crw_cont->crw.flags |= CRW_FLAGS_MASK_C; } @@ -2091,9 +2095,9 @@ void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, } chain_crw = (channel_subsys.max_ssid > 0) || (channel_subsys.max_cssid > 0); - css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, chain_crw ? 1 : 0, schid); + css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0, chain_crw ? 1 : 0, schid); if (chain_crw) { - css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0, + css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0, 0, (guest_cssid << 8) | (ssid << 4)); } /* RW_ERC_IPI --> clear pending interrupts */ @@ -2108,7 +2112,7 @@ void css_generate_chp_crws(uint8_t cssid, uint8_t chpid) void css_generate_css_crws(uint8_t cssid) { if (!channel_subsys.sei_pending) { - css_queue_crw(CRW_RSC_CSS, 0, 0, cssid); + css_queue_crw(CRW_RSC_CSS, CRW_ERC_EVENT, 0, 0, cssid); } channel_subsys.sei_pending = true; } diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index cc36003..0d06fc1 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -442,6 +442,8 @@ static void s390_ipl_class_init(ObjectClass *klass, void *data) dc->reset = s390_ipl_reset; dc->vmsd = &vmstate_ipl; set_bit(DEVICE_CATEGORY_MISC, dc->categories); + /* Reason: Loads the ROMs and thus can only be used one time - internally */ + dc->user_creatable = false; } static const TypeInfo s390_ipl_info = { diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 61cfd21..0a31a4a 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -47,7 +47,7 @@ S390pciState *s390_get_phb(void) return phb; } -int chsc_sei_nt2_get_event(void *res) +int pci_chsc_sei_nt2_get_event(void *res) { ChscSeiNt2Res *nt2_res = (ChscSeiNt2Res *)res; PciCcdfAvail *accdf; @@ -87,7 +87,7 @@ int chsc_sei_nt2_get_event(void *res) return rc; } -int chsc_sei_nt2_have_event(void) +int pci_chsc_sei_nt2_have_event(void) { S390pciState *s = s390_get_phb(); @@ -122,16 +122,11 @@ S390PCIBusDevice *s390_pci_find_dev_by_fid(S390pciState *s, uint32_t fid) void s390_pci_sclp_configure(SCCB *sccb) { - PciCfgSccb *psccb = (PciCfgSccb *)sccb; + IoaCfgSccb *psccb = (IoaCfgSccb *)sccb; S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(s390_get_phb(), be32_to_cpu(psccb->aid)); uint16_t rc; - if (be16_to_cpu(sccb->h.length) < 16) { - rc = SCLP_RC_INSUFFICIENT_SCCB_LENGTH; - goto out; - } - if (!pbdev) { DPRINTF("sclp config no dev found\n"); rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED; @@ -155,16 +150,11 @@ out: void s390_pci_sclp_deconfigure(SCCB *sccb) { - PciCfgSccb *psccb = (PciCfgSccb *)sccb; + IoaCfgSccb *psccb = (IoaCfgSccb *)sccb; S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(s390_get_phb(), be32_to_cpu(psccb->aid)); uint16_t rc; - if (be16_to_cpu(sccb->h.length) < 16) { - rc = SCLP_RC_INSUFFICIENT_SCCB_LENGTH; - goto out; - } - if (!pbdev) { DPRINTF("sclp deconfig no dev found\n"); rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED; diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index 67af2c1..bd636ab 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -244,14 +244,6 @@ typedef struct ChscSeiNt2Res { uint8_t ccdf[4016]; } QEMU_PACKED ChscSeiNt2Res; -typedef struct PciCfgSccb { - SCCBHeader header; - uint8_t atype; - uint8_t reserved1; - uint16_t reserved2; - uint32_t aid; -} QEMU_PACKED PciCfgSccb; - typedef struct S390MsixInfo { bool available; uint8_t table_bar; @@ -319,8 +311,8 @@ typedef struct S390pciState { } S390pciState; S390pciState *s390_get_phb(void); -int chsc_sei_nt2_get_event(void *res); -int chsc_sei_nt2_have_event(void); +int pci_chsc_sei_nt2_get_event(void *res); +int pci_chsc_sei_nt2_have_event(void); void s390_pci_sclp_configure(SCCB *sccb); void s390_pci_sclp_deconfigure(SCCB *sccb); void s390_pci_iommu_enable(S390PCIIOMMU *iommu); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index b7beb8c..eba9ffb 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -440,8 +440,8 @@ static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias) { if (pbdev->msix.available && pbdev->msix.table_bar == pcias && offset >= pbdev->msix.table_offset && - offset <= pbdev->msix.table_offset + - (pbdev->msix.entries - 1) * PCI_MSIX_ENTRY_SIZE) { + offset < (pbdev->msix.table_offset + + pbdev->msix.entries * PCI_MSIX_ENTRY_SIZE)) { return 1; } else { return 0; diff --git a/hw/s390x/s390-pci-stub.c b/hw/s390x/s390-pci-stub.c new file mode 100644 index 0000000..7a642d3 --- /dev/null +++ b/hw/s390x/s390-pci-stub.c @@ -0,0 +1,76 @@ +/* stubs for non-pci builds */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "cpu.h" +#include "s390-pci-inst.h" +#include "s390-pci-bus.h" + +/* target/s390x/ioinst.c */ +int pci_chsc_sei_nt2_get_event(void *res) +{ + return 1; +} + +int pci_chsc_sei_nt2_have_event(void) +{ + return 0; +} + +/* hw/s390x/sclp.c */ +void s390_pci_sclp_configure(SCCB *sccb) +{ + sccb->h.response_code = cpu_to_be16(SCLP_RC_ADAPTER_TYPE_NOT_RECOGNIZED); +} + +void s390_pci_sclp_deconfigure(SCCB *sccb) +{ + sccb->h.response_code = cpu_to_be16(SCLP_RC_ADAPTER_TYPE_NOT_RECOGNIZED); +} + +/* target/s390x/kvm.c */ +int clp_service_call(S390CPU *cpu, uint8_t r2) +{ + return -1; +} + +int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) +{ + return -1; +} + +int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) +{ + return -1; +} + +int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) +{ + return -1; +} + +int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) +{ + return -1; +} + +int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, + uint8_t ar) +{ + return -1; +} + +int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) +{ + return -1; +} + +S390pciState *s390_get_phb(void) +{ + return NULL; +} + +S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx) +{ + return NULL; +} diff --git a/hw/s390x/s390-skeys-kvm.c b/hw/s390x/s390-skeys-kvm.c index 131da56..dc54ed8 100644 --- a/hw/s390x/s390-skeys-kvm.c +++ b/hw/s390x/s390-skeys-kvm.c @@ -54,10 +54,14 @@ static int kvm_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn, static void kvm_s390_skeys_class_init(ObjectClass *oc, void *data) { S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); skeyclass->skeys_enabled = kvm_s390_skeys_enabled; skeyclass->get_skeys = kvm_s390_skeys_get; skeyclass->set_skeys = kvm_s390_skeys_set; + + /* Reason: Internal device (only one skeys device for the whole memory) */ + dc->user_creatable = false; } static const TypeInfo kvm_s390_skeys_info = { diff --git a/hw/s390x/s390-skeys.c b/hw/s390x/s390-skeys.c index c0de3b0..53ad5d3 100644 --- a/hw/s390x/s390-skeys.c +++ b/hw/s390x/s390-skeys.c @@ -229,10 +229,14 @@ static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn, static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data) { S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); skeyclass->skeys_enabled = qemu_s390_skeys_enabled; skeyclass->get_skeys = qemu_s390_skeys_get; skeyclass->set_skeys = qemu_s390_skeys_set; + + /* Reason: Internal device (only one skeys device for the whole memory) */ + dc->user_creatable = false; } static const TypeInfo qemu_s390_skeys_info = { diff --git a/hw/s390x/s390-stattrib-kvm.c b/hw/s390x/s390-stattrib-kvm.c index ff3f89f..41770a7 100644 --- a/hw/s390x/s390-stattrib-kvm.c +++ b/hw/s390x/s390-stattrib-kvm.c @@ -17,6 +17,7 @@ #include "sysemu/kvm.h" #include "exec/ram_addr.h" #include "cpu.h" +#include "kvm_s390x.h" Object *kvm_s390_stattrib_create(void) { @@ -163,6 +164,7 @@ static int kvm_s390_stattrib_get_active(S390StAttribState *sa) static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data) { S390StAttribClass *sac = S390_STATTRIB_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); sac->get_stattr = kvm_s390_stattrib_get_stattr; sac->peek_stattr = kvm_s390_stattrib_peek_stattr; @@ -171,6 +173,9 @@ static void kvm_s390_stattrib_class_init(ObjectClass *oc, void *data) sac->get_dirtycount = kvm_s390_stattrib_get_dirtycount; sac->synchronize = kvm_s390_stattrib_synchronize; sac->get_active = kvm_s390_stattrib_get_active; + + /* Reason: Can only be instantiated one time (internally) */ + dc->user_creatable = false; } static const TypeInfo kvm_s390_stattrib_info = { diff --git a/hw/s390x/s390-stattrib.c b/hw/s390x/s390-stattrib.c index d14923f..2902f54 100644 --- a/hw/s390x/s390-stattrib.c +++ b/hw/s390x/s390-stattrib.c @@ -11,12 +11,12 @@ #include "qemu/osdep.h" #include "hw/boards.h" +#include "cpu.h" #include "qmp-commands.h" #include "migration/qemu-file.h" #include "migration/register.h" #include "hw/s390x/storage-attributes.h" #include "qemu/error-report.h" -#include "sysemu/kvm.h" #include "exec/ram_addr.h" #include "qapi/error.h" @@ -306,6 +306,7 @@ static int qemu_s390_get_active(S390StAttribState *sa) static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data) { S390StAttribClass *sa_cl = S390_STATTRIB_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); sa_cl->synchronize = qemu_s390_synchronize_stub; sa_cl->get_stattr = qemu_s390_get_stattr_stub; @@ -314,6 +315,9 @@ static void qemu_s390_stattrib_class_init(ObjectClass *oc, void *data) sa_cl->set_migrationmode = qemu_s390_set_migrationmode_stub; sa_cl->get_dirtycount = qemu_s390_get_dirtycount_stub; sa_cl->get_active = qemu_s390_get_active; + + /* Reason: Can only be instantiated one time (internally) */ + dc->user_creatable = false; } static const TypeInfo qemu_s390_stattrib_info = { diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 1c7af39..dd504dd 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -118,12 +118,11 @@ static void ccw_init(MachineState *machine) { int ret; VirtualCssBus *css_bus; - DeviceState *dev; s390_sclp_init(); s390_memory_init(machine->ram_size); - /* init CPUs */ + /* init CPUs (incl. CPU model) early so s390_has_feature() works */ s390_init_cpus(machine); s390_flic_init(); @@ -134,17 +133,18 @@ static void ccw_init(MachineState *machine) machine->initrd_filename, "s390-ccw.img", "s390-netboot.img", true); - dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); - object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE, - OBJECT(dev), NULL); - qdev_init_nofail(dev); + if (s390_has_feat(S390_FEAT_ZPCI)) { + DeviceState *dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); + object_property_add_child(qdev_get_machine(), + TYPE_S390_PCI_HOST_BRIDGE, + OBJECT(dev), NULL); + qdev_init_nofail(dev); + } /* register hypercalls */ virtio_ccw_register_hcalls(); - if (kvm_enabled()) { - kvm_s390_enable_css_support(s390_cpu_addr2state(0)); - } + s390_enable_css_support(s390_cpu_addr2state(0)); /* * Non mcss-e enabled guests only see the devices from the default * css, which is determined by the value of the squash_mcss property. @@ -161,7 +161,7 @@ static void ccw_init(MachineState *machine) s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw"); /* Register savevm handler for guest TOD clock */ - register_savevm_live(NULL, "todclock", 0, 1, &savevm_gtod, kvm_state); + register_savevm_live(NULL, "todclock", 0, 1, &savevm_gtod, NULL); } static void s390_cpu_plug(HotplugHandler *hotplug_dev, @@ -276,9 +276,6 @@ static S390CcwMachineClass *get_machine_class(void) bool ri_allowed(void) { - if (!kvm_enabled()) { - return false; - } /* for "none" machine this results in true */ return get_machine_class()->ri_allowed; } @@ -291,18 +288,8 @@ bool cpu_model_allowed(void) bool gs_allowed(void) { - if (kvm_enabled()) { - MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine()); - if (object_class_dynamic_cast(OBJECT_CLASS(mc), - TYPE_S390_CCW_MACHINE)) { - S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc); - - return s390mc->gs_allowed; - } - /* Make sure the "none" machine can have gs */ - return true; - } - return false; + /* for "none" machine this results in true */ + return get_machine_class()->gs_allowed; } static char *machine_get_loadparm(Object *obj, Error **errp) @@ -432,6 +419,9 @@ bool css_migration_enabled(void) } \ type_init(ccw_machine_register_##suffix) +#define CCW_COMPAT_2_10 \ + HW_COMPAT_2_10 + #define CCW_COMPAT_2_9 \ HW_COMPAT_2_9 \ {\ @@ -506,8 +496,18 @@ bool css_migration_enabled(void) .value = "0",\ }, +static void ccw_machine_2_11_instance_options(MachineState *machine) +{ +} + +static void ccw_machine_2_11_class_options(MachineClass *mc) +{ +} +DEFINE_CCW_MACHINE(2_11, "2.11", true); + static void ccw_machine_2_10_instance_options(MachineState *machine) { + ccw_machine_2_11_instance_options(machine); if (css_migration_enabled()) { css_register_vmstate(); } @@ -515,8 +515,10 @@ static void ccw_machine_2_10_instance_options(MachineState *machine) static void ccw_machine_2_10_class_options(MachineClass *mc) { + ccw_machine_2_11_class_options(mc); + SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_10); } -DEFINE_CCW_MACHINE(2_10, "2.10", true); +DEFINE_CCW_MACHINE(2_10, "2.10", false); static void ccw_machine_2_9_instance_options(MachineState *machine) { diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index afa4148..da3f49e 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -33,7 +33,6 @@ #include "hw/boards.h" #include "hw/loader.h" #include "hw/virtio/virtio.h" -#include "sysemu/kvm.h" #include "exec/address-spaces.h" #include "sysemu/qtest.h" @@ -93,11 +92,7 @@ void s390_init_cpus(MachineState *machine) gchar *name; if (machine->cpu_model == NULL) { - if (kvm_enabled()) { - machine->cpu_model = "host"; - } else { - machine->cpu_model = "qemu"; - } + machine->cpu_model = s390_default_cpu_model_name(); } cpu_states = g_new0(S390CPU *, max_cpus); diff --git a/hw/s390x/s390-virtio.h b/hw/s390x/s390-virtio.h index f2377a3..ca97fd6 100644 --- a/hw/s390x/s390-virtio.h +++ b/hw/s390x/s390-virtio.h @@ -30,4 +30,6 @@ void s390_create_virtio_net(BusState *bus, const char *name); void s390_nmi(NMIState *n, int cpu_index, Error **errp); void s390_machine_reset(void); void s390_memory_init(ram_addr_t mem_size); +void gtod_save(QEMUFile *f, void *opaque); +int gtod_load(QEMUFile *f, void *opaque, int version_id); #endif diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index 9253dbb..fd09726 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -15,7 +15,6 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "cpu.h" -#include "sysemu/kvm.h" #include "exec/memory.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" @@ -57,7 +56,7 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) CPUState *cpu; int cpu_count = 0; int rnsize, rnmax; - int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state)); + int slots = MIN(machine->ram_slots, s390_get_memslot_count()); IplParameterBlock *ipib = s390_ipl_get_iplb(); CPU_FOREACH(cpu) { @@ -80,7 +79,7 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) prepare_cpu_entries(sclp, read_info->entries, cpu_count); read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO | - SCLP_HAS_PCI_RECONFIG); + SCLP_HAS_IOA_RECONFIG); /* Memory Hotplug is only supported for the ccw machine type */ if (mhd) { @@ -354,6 +353,35 @@ static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb) sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); } +static void sclp_configure_io_adapter(SCLPDevice *sclp, SCCB *sccb, + bool configure) +{ + int rc; + + if (be16_to_cpu(sccb->h.length) < 16) { + rc = SCLP_RC_INSUFFICIENT_SCCB_LENGTH; + goto out_err; + } + + switch (((IoaCfgSccb *)sccb)->atype) { + case SCLP_RECONFIG_PCI_ATYPE: + if (s390_has_feat(S390_FEAT_ZPCI)) { + if (configure) { + s390_pci_sclp_configure(sccb); + } else { + s390_pci_sclp_deconfigure(sccb); + } + return; + } + /* fallthrough */ + default: + rc = SCLP_RC_ADAPTER_TYPE_NOT_RECOGNIZED; + } + + out_err: + sccb->h.response_code = cpu_to_be16(rc); +} + static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code) { SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); @@ -384,11 +412,11 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code) case SCLP_UNASSIGN_STORAGE: sclp_c->unassign_storage(sclp, sccb); break; - case SCLP_CMDW_CONFIGURE_PCI: - s390_pci_sclp_configure(sccb); + case SCLP_CMDW_CONFIGURE_IOA: + sclp_configure_io_adapter(sclp, sccb, true); break; - case SCLP_CMDW_DECONFIGURE_PCI: - s390_pci_sclp_deconfigure(sccb); + case SCLP_CMDW_DECONFIGURE_IOA: + sclp_configure_io_adapter(sclp, sccb, false); break; default: efc->command_handler(ef, sccb, code); diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c index b1f3ef8..023d059 100644 --- a/hw/s390x/sclpcpu.c +++ b/hw/s390x/sclpcpu.c @@ -18,7 +18,6 @@ #include "hw/s390x/event-facility.h" #include "cpu.h" #include "sysemu/cpus.h" -#include "sysemu/kvm.h" typedef struct ConfigMgtData { EventBufferHeader ebh; diff --git a/hw/watchdog/wdt_diag288.c b/hw/watchdog/wdt_diag288.c index a7b64e2..47f2892 100644 --- a/hw/watchdog/wdt_diag288.c +++ b/hw/watchdog/wdt_diag288.c @@ -121,6 +121,7 @@ static void wdt_diag288_class_init(ObjectClass *klass, void *data) dc->realize = wdt_diag288_realize; dc->unrealize = wdt_diag288_unrealize; dc->reset = wdt_diag288_reset; + dc->hotpluggable = false; set_bit(DEVICE_CATEGORY_MISC, dc->categories); dc->vmsd = &vmstate_diag288; diag288->handle_timer = wdt_diag288_handle_timer; diff --git a/include/hw/compat.h b/include/hw/compat.h index 08f3600..3e101f8 100644 --- a/include/hw/compat.h +++ b/include/hw/compat.h @@ -1,6 +1,9 @@ #ifndef HW_COMPAT_H #define HW_COMPAT_H +#define HW_COMPAT_2_10 \ + /* empty */ + #define HW_COMPAT_2_9 \ {\ .driver = "pci-bridge",\ diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index e598b09..8bb6449 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -10,6 +10,8 @@ #include "hw/pci/pcie.h" +extern bool pci_available; + /* PCI bus */ #define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h index 5c5fe6b..0653d3c 100644 --- a/include/hw/s390x/css.h +++ b/include/hw/s390x/css.h @@ -16,6 +16,7 @@ #include "hw/s390x/adapter.h" #include "hw/s390x/s390_flic.h" #include "hw/s390x/ioinst.h" +#include "sysemu/kvm.h" /* Channel subsystem constants. */ #define MAX_DEVNO 65535 @@ -150,7 +151,8 @@ void copy_scsw_to_guest(SCSW *dest, const SCSW *src); void css_inject_io_interrupt(SubchDev *sch); void css_reset(void); void css_reset_sch(SubchDev *sch); -void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid); +void css_queue_crw(uint8_t rsc, uint8_t erc, int solicited, + int chain, uint16_t rsid); void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, int hotplugged, int add); void css_generate_chp_crws(uint8_t cssid, uint8_t chpid); diff --git a/include/hw/s390x/ioinst.h b/include/hw/s390x/ioinst.h index 92d1565..5f2db69 100644 --- a/include/hw/s390x/ioinst.h +++ b/include/hw/s390x/ioinst.h @@ -201,8 +201,16 @@ typedef struct CRW { #define CRW_FLAGS_MASK_A 0x0080 #define CRW_FLAGS_MASK_ERC 0x003f -#define CRW_ERC_INIT 0x02 -#define CRW_ERC_IPI 0x04 +#define CRW_ERC_EVENT 0x00 /* event information pending */ +#define CRW_ERC_AVAIL 0x01 /* available */ +#define CRW_ERC_INIT 0x02 /* initialized */ +#define CRW_ERC_TERROR 0x03 /* temporary error */ +#define CRW_ERC_IPI 0x04 /* installed parm initialized */ +#define CRW_ERC_TERM 0x05 /* terminal */ +#define CRW_ERC_PERRN 0x06 /* perm. error, facility not init */ +#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */ +#define CRW_ERC_PMOD 0x08 /* installed parameters modified */ +#define CRW_ERC_IPR 0x0A /* installed parameters restored */ #define CRW_RSC_SUBCH 0x3 #define CRW_RSC_CHP 0x4 diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index e71d526..a72d096 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -44,10 +44,10 @@ #define SCLP_CMDW_DECONFIGURE_CPU 0x00100001 /* SCLP PCI codes */ -#define SCLP_HAS_PCI_RECONFIG 0x0000000040000000ULL -#define SCLP_CMDW_CONFIGURE_PCI 0x001a0001 -#define SCLP_CMDW_DECONFIGURE_PCI 0x001b0001 -#define SCLP_RECONFIG_PCI_ATPYE 2 +#define SCLP_HAS_IOA_RECONFIG 0x0000000040000000ULL +#define SCLP_CMDW_CONFIGURE_IOA 0x001a0001 +#define SCLP_CMDW_DECONFIGURE_IOA 0x001b0001 +#define SCLP_RECONFIG_PCI_ATYPE 2 /* SCLP response codes */ #define SCLP_RC_NORMAL_READ_COMPLETION 0x0010 @@ -59,6 +59,7 @@ #define SCLP_RC_INSUFFICIENT_SCCB_LENGTH 0x0300 #define SCLP_RC_STANDBY_READ_COMPLETION 0x0410 #define SCLP_RC_ADAPTER_IN_RESERVED_STATE 0x05f0 +#define SCLP_RC_ADAPTER_TYPE_NOT_RECOGNIZED 0x06f0 #define SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED 0x09f0 #define SCLP_RC_INVALID_FUNCTION 0x40f0 #define SCLP_RC_NO_EVENT_BUFFERS_STORED 0x60f0 @@ -167,6 +168,14 @@ typedef struct AssignStorage { uint16_t rn; } QEMU_PACKED AssignStorage; +typedef struct IoaCfgSccb { + SCCBHeader header; + uint8_t atype; + uint8_t reserved1; + uint16_t reserved2; + uint32_t aid; +} QEMU_PACKED IoaCfgSccb; + typedef struct SCCB { SCCBHeader h; char data[SCCB_DATA_LEN]; diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img Binary files differindex 0a08c39..0b03929 100644 --- a/pc-bios/s390-ccw.img +++ b/pc-bios/s390-ccw.img diff --git a/pc-bios/s390-ccw/cio.h b/pc-bios/s390-ccw/cio.h index f5b4549..55eaeee 100644 --- a/pc-bios/s390-ccw/cio.h +++ b/pc-bios/s390-ccw/cio.h @@ -133,7 +133,7 @@ struct ccw1 { __u8 flags; __u16 count; __u32 cda; -} __attribute__ ((packed)); +} __attribute__ ((packed, aligned(8))); #define CCW_FLAG_DC 0x80 #define CCW_FLAG_CC 0x40 diff --git a/target/s390x/Makefile.objs b/target/s390x/Makefile.objs index f42cd1f..9615256 100644 --- a/target/s390x/Makefile.objs +++ b/target/s390x/Makefile.objs @@ -3,6 +3,7 @@ obj-$(CONFIG_TCG) += translate.o cc_helper.o excp_helper.o fpu_helper.o obj-$(CONFIG_TCG) += int_helper.o mem_helper.o misc_helper.o obj-$(CONFIG_SOFTMMU) += machine.o ioinst.o arch_dump.o mmu_helper.o diag.o obj-$(CONFIG_KVM) += kvm.o +obj-$(call lnot,$(CONFIG_KVM)) += kvm-stub.o # build and run feature list generator feat-src = $(SRC_PATH)/target/$(TARGET_BASE_ARCH)/ diff --git a/target/s390x/arch_dump.c b/target/s390x/arch_dump.c index 96c9fb9..9b0bf92 100644 --- a/target/s390x/arch_dump.c +++ b/target/s390x/arch_dump.c @@ -13,10 +13,10 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" #include "elf.h" #include "exec/cpu-all.h" #include "sysemu/dump.h" -#include "sysemu/kvm.h" struct S390xUserRegsStruct { diff --git a/target/s390x/cc_helper.c b/target/s390x/cc_helper.c index 1cf8551..f008897 100644 --- a/target/s390x/cc_helper.c +++ b/target/s390x/cc_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" #include "exec/exec-all.h" #include "exec/helper-proto.h" #include "qemu/host-utils.h" diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 489bc25..7267b60 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -26,6 +26,9 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "cpu.h" +#include "internal.h" +#include "kvm_s390x.h" +#include "sysemu/kvm.h" #include "qemu-common.h" #include "qemu/cutils.h" #include "qemu/timer.h" @@ -391,6 +394,92 @@ unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) return s390_count_running_cpus(); } + +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; +} + +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; +} + +int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) +{ + if (kvm_enabled()) { + return kvm_s390_set_mem_limit(new_limit, hw_limit); + } + return 0; +} + +void s390_cmma_reset(void) +{ + if (kvm_enabled()) { + kvm_s390_cmma_reset(); + } +} + +int s390_cpu_restart(S390CPU *cpu) +{ + if (kvm_enabled()) { + return kvm_s390_cpu_restart(cpu); + } + return -ENOSYS; +} + +int s390_get_memslot_count(void) +{ + if (kvm_enabled()) { + return kvm_s390_get_memslot_count(); + } else { + return MAX_AVAIL_SLOTS; + } +} + +int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id, + int vq, bool assign) +{ + if (kvm_enabled()) { + return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign); + } else { + return 0; + } +} + +void s390_crypto_reset(void) +{ + if (kvm_enabled()) { + kvm_s390_crypto_reset(); + } +} + +bool s390_get_squash_mcss(void) +{ + if (object_property_get_bool(OBJECT(qdev_get_machine()), "s390-squash-mcss", + NULL)) { + return true; + } + + return false; +} + +void s390_enable_css_support(S390CPU *cpu) +{ + if (kvm_enabled()) { + kvm_s390_enable_css_support(cpu); + } +} #endif static gchar *s390_gdb_arch_name(CPUState *cs) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 29fdd5d..4ec3380 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -213,22 +213,6 @@ static inline S390CPU *s390_env_get_cpu(CPUS390XState *env) extern const struct VMStateDescription vmstate_s390_cpu; #endif -void s390_cpu_do_interrupt(CPUState *cpu); -bool s390_cpu_exec_interrupt(CPUState *cpu, int int_req); -void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, - int flags); -int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, - int cpuid, void *opaque); - -hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); -hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr); -int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); -int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); -void s390_cpu_gdb_init(CPUState *cs); -void s390x_cpu_debug_excp_handler(CPUState *cs); - -#include "sysemu/kvm.h" - /* distinguish between 24 bit and 31 bit addressing */ #define HIGH_ORDER_BIT 0x80000000 @@ -366,17 +350,6 @@ void s390x_cpu_debug_excp_handler(CPUState *cs); #define MMU_SECONDARY_IDX 1 #define MMU_HOME_IDX 2 -static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key) -{ - uint16_t pkm = env->cregs[3] >> 16; - - if (env->psw.mask & PSW_MASK_PSTATE) { - /* PSW key has range 0..15, it is valid if the bit is 1 in the PKM */ - return pkm & (0x80 >> psw_key); - } - return true; -} - static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch) { switch (env->psw.mask & PSW_MASK_ASC) { @@ -393,20 +366,6 @@ static inline int cpu_mmu_index(CPUS390XState *env, bool ifetch) } } -static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx) -{ - switch (mmu_idx) { - case MMU_PRIMARY_IDX: - return PSW_ASC_PRIMARY; - case MMU_SECONDARY_IDX: - return PSW_ASC_SECONDARY; - case MMU_HOME_IDX: - return PSW_ASC_HOME; - default: - abort(); - } -} - static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, target_ulong *cs_base, uint32_t *flags) { @@ -415,26 +374,6 @@ static inline void cpu_get_tb_cpu_state(CPUS390XState* env, target_ulong *pc, *flags = (env->psw.mask >> FLAG_MASK_PSW_SHIFT) & FLAG_MASK_PSW; } -#define MAX_ILEN 6 - -/* While the PoO talks about ILC (a number between 1-3) what is actually - stored in LowCore is shifted left one bit (an even between 2-6). As - this is the actual length of the insn and therefore more useful, that - is what we want to pass around and manipulate. To make sure that we - have applied this distinction universally, rename the "ILC" to "ILEN". */ -static inline int get_ilen(uint8_t opc) -{ - switch (opc >> 6) { - case 0: - return 2; - case 1: - case 2: - return 4; - default: - return 6; - } -} - /* PER bits from control register 9 */ #define PER_CR9_EVENT_BRANCH 0x80000000 #define PER_CR9_EVENT_IFETCH 0x40000000 @@ -451,203 +390,6 @@ static inline int get_ilen(uint8_t opc) #define PER_CODE_EVENT_STORE_REAL 0x0800 #define PER_CODE_EVENT_NULLIFICATION 0x0100 -/* Compute the ATMID field that is stored in the per_perc_atmid lowcore - entry when a PER exception is triggered. */ -static inline uint8_t get_per_atmid(CPUS390XState *env) -{ - return ((env->psw.mask & PSW_MASK_64) ? (1 << 7) : 0) | - ( (1 << 6) ) | - ((env->psw.mask & PSW_MASK_32) ? (1 << 5) : 0) | - ((env->psw.mask & PSW_MASK_DAT)? (1 << 4) : 0) | - ((env->psw.mask & PSW_ASC_SECONDARY)? (1 << 3) : 0) | - ((env->psw.mask & PSW_ASC_ACCREG)? (1 << 2) : 0); -} - -/* Check if an address is within the PER starting address and the PER - ending address. The address range might loop. */ -static inline bool get_per_in_range(CPUS390XState *env, uint64_t addr) -{ - if (env->cregs[10] <= env->cregs[11]) { - return env->cregs[10] <= addr && addr <= env->cregs[11]; - } else { - return env->cregs[10] <= addr || addr <= env->cregs[11]; - } -} - -S390CPU *cpu_s390x_init(const char *cpu_model); -S390CPU *s390x_new_cpu(const char *cpu_model, int64_t id, Error **errp); -S390CPU *cpu_s390x_create(const char *cpu_model, Error **errp); -void s390x_translate_init(void); - -/* you can call this signal handler from your SIGBUS and SIGSEGV - signal handlers to inform the virtual CPU of exceptions. non zero - is returned if the signal was handled by the virtual CPU. */ -int cpu_s390x_signal_handler(int host_signum, void *pinfo, - void *puc); -int s390_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, - int mmu_idx); - - -#ifndef CONFIG_USER_ONLY -void do_restart_interrupt(CPUS390XState *env); -void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, - MMUAccessType access_type, - int mmu_idx, uintptr_t retaddr); - -static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb, - uint8_t *ar) -{ - hwaddr addr = 0; - uint8_t reg; - - reg = ipb >> 28; - if (reg > 0) { - addr = env->regs[reg]; - } - addr += (ipb >> 16) & 0xfff; - if (ar) { - *ar = reg; - } - - return addr; -} - -/* Base/displacement are at the same locations. */ -#define decode_basedisp_rs decode_basedisp_s - -/* helper functions for run_on_cpu() */ -static inline void s390_do_cpu_reset(CPUState *cs, run_on_cpu_data arg) -{ - S390CPUClass *scc = S390_CPU_GET_CLASS(cs); - - scc->cpu_reset(cs); -} -static inline void s390_do_cpu_full_reset(CPUState *cs, run_on_cpu_data arg) -{ - cpu_reset(cs); -} - -void s390x_tod_timer(void *opaque); -void s390x_cpu_timer(void *opaque); - -int s390_virtio_hypercall(CPUS390XState *env); - -#ifdef CONFIG_KVM -void kvm_s390_service_interrupt(uint32_t parm); -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_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, - int len, bool is_write); -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_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 int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, - void *hostbuf, int len, bool is_write) -{ - 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); -unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu); -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); - -void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param, - uint64_t param64); - -/* ioinst.c */ -void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1); -void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1); -void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1); -void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); -void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); -void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb); -void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); -int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); -void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb); -int ioinst_handle_tpi(S390CPU *cpu, uint32_t ipb); -void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2, - uint32_t ipb); -void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1); -void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1); -void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1); - -/* service interrupts are floating therefore we must not pass an cpustate */ -void s390_sclp_extint(uint32_t parm); - -#else -static inline unsigned int s390_cpu_halt(S390CPU *cpu) -{ - return 0; -} - -static inline void s390_cpu_unhalt(S390CPU *cpu) -{ -} - -static inline unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) -{ - return 0; -} -#endif - -extern void subsystem_reset(void); - -#define cpu_init(model) CPU(cpu_s390x_init(model)) -#define cpu_signal_handler cpu_s390x_signal_handler - -void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf); -#define cpu_list s390_cpu_list -void s390_cpu_model_register_props(Object *obj); -void s390_cpu_model_class_register_props(ObjectClass *oc); -void s390_realize_cpu_model(CPUState *cs, Error **errp); -ObjectClass *s390_cpu_class_by_name(const char *name); - #define EXCP_EXT 1 /* external interrupt */ #define EXCP_SVC 2 /* supervisor call (syscall) */ #define EXCP_PGM 3 /* program interruption */ @@ -683,115 +425,6 @@ ObjectClass *s390_cpu_class_by_name(const char *name); /* Total Core Registers. */ #define S390_NUM_CORE_REGS 18 -/* CC optimization */ - -/* Instead of computing the condition codes after each x86 instruction, - * QEMU just stores the result (called CC_DST), the type of operation - * (called CC_OP) and whatever operands are needed (CC_SRC and possibly - * CC_VR). When the condition codes are needed, the condition codes can - * be calculated using this information. Condition codes are not generated - * if they are only needed for conditional branches. - */ -enum cc_op { - CC_OP_CONST0 = 0, /* CC is 0 */ - CC_OP_CONST1, /* CC is 1 */ - CC_OP_CONST2, /* CC is 2 */ - CC_OP_CONST3, /* CC is 3 */ - - CC_OP_DYNAMIC, /* CC calculation defined by env->cc_op */ - CC_OP_STATIC, /* CC value is env->cc_op */ - - CC_OP_NZ, /* env->cc_dst != 0 */ - CC_OP_LTGT_32, /* signed less/greater than (32bit) */ - CC_OP_LTGT_64, /* signed less/greater than (64bit) */ - CC_OP_LTUGTU_32, /* unsigned less/greater than (32bit) */ - CC_OP_LTUGTU_64, /* unsigned less/greater than (64bit) */ - CC_OP_LTGT0_32, /* signed less/greater than 0 (32bit) */ - CC_OP_LTGT0_64, /* signed less/greater than 0 (64bit) */ - - CC_OP_ADD_64, /* overflow on add (64bit) */ - CC_OP_ADDU_64, /* overflow on unsigned add (64bit) */ - CC_OP_ADDC_64, /* overflow on unsigned add-carry (64bit) */ - CC_OP_SUB_64, /* overflow on subtraction (64bit) */ - CC_OP_SUBU_64, /* overflow on unsigned subtraction (64bit) */ - CC_OP_SUBB_64, /* overflow on unsigned sub-borrow (64bit) */ - CC_OP_ABS_64, /* sign eval on abs (64bit) */ - CC_OP_NABS_64, /* sign eval on nabs (64bit) */ - - CC_OP_ADD_32, /* overflow on add (32bit) */ - CC_OP_ADDU_32, /* overflow on unsigned add (32bit) */ - CC_OP_ADDC_32, /* overflow on unsigned add-carry (32bit) */ - CC_OP_SUB_32, /* overflow on subtraction (32bit) */ - CC_OP_SUBU_32, /* overflow on unsigned subtraction (32bit) */ - CC_OP_SUBB_32, /* overflow on unsigned sub-borrow (32bit) */ - CC_OP_ABS_32, /* sign eval on abs (64bit) */ - CC_OP_NABS_32, /* sign eval on nabs (64bit) */ - - CC_OP_COMP_32, /* complement */ - CC_OP_COMP_64, /* complement */ - - CC_OP_TM_32, /* test under mask (32bit) */ - CC_OP_TM_64, /* test under mask (64bit) */ - - CC_OP_NZ_F32, /* FP dst != 0 (32bit) */ - CC_OP_NZ_F64, /* FP dst != 0 (64bit) */ - CC_OP_NZ_F128, /* FP dst != 0 (128bit) */ - - CC_OP_ICM, /* insert characters under mask */ - CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ - CC_OP_SLA_64, /* Calculate shift left signed (64bit) */ - CC_OP_FLOGR, /* find leftmost one */ - CC_OP_MAX -}; - -static const char *cc_names[] = { - [CC_OP_CONST0] = "CC_OP_CONST0", - [CC_OP_CONST1] = "CC_OP_CONST1", - [CC_OP_CONST2] = "CC_OP_CONST2", - [CC_OP_CONST3] = "CC_OP_CONST3", - [CC_OP_DYNAMIC] = "CC_OP_DYNAMIC", - [CC_OP_STATIC] = "CC_OP_STATIC", - [CC_OP_NZ] = "CC_OP_NZ", - [CC_OP_LTGT_32] = "CC_OP_LTGT_32", - [CC_OP_LTGT_64] = "CC_OP_LTGT_64", - [CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32", - [CC_OP_LTUGTU_64] = "CC_OP_LTUGTU_64", - [CC_OP_LTGT0_32] = "CC_OP_LTGT0_32", - [CC_OP_LTGT0_64] = "CC_OP_LTGT0_64", - [CC_OP_ADD_64] = "CC_OP_ADD_64", - [CC_OP_ADDU_64] = "CC_OP_ADDU_64", - [CC_OP_ADDC_64] = "CC_OP_ADDC_64", - [CC_OP_SUB_64] = "CC_OP_SUB_64", - [CC_OP_SUBU_64] = "CC_OP_SUBU_64", - [CC_OP_SUBB_64] = "CC_OP_SUBB_64", - [CC_OP_ABS_64] = "CC_OP_ABS_64", - [CC_OP_NABS_64] = "CC_OP_NABS_64", - [CC_OP_ADD_32] = "CC_OP_ADD_32", - [CC_OP_ADDU_32] = "CC_OP_ADDU_32", - [CC_OP_ADDC_32] = "CC_OP_ADDC_32", - [CC_OP_SUB_32] = "CC_OP_SUB_32", - [CC_OP_SUBU_32] = "CC_OP_SUBU_32", - [CC_OP_SUBB_32] = "CC_OP_SUBB_32", - [CC_OP_ABS_32] = "CC_OP_ABS_32", - [CC_OP_NABS_32] = "CC_OP_NABS_32", - [CC_OP_COMP_32] = "CC_OP_COMP_32", - [CC_OP_COMP_64] = "CC_OP_COMP_64", - [CC_OP_TM_32] = "CC_OP_TM_32", - [CC_OP_TM_64] = "CC_OP_TM_64", - [CC_OP_NZ_F32] = "CC_OP_NZ_F32", - [CC_OP_NZ_F64] = "CC_OP_NZ_F64", - [CC_OP_NZ_F128] = "CC_OP_NZ_F128", - [CC_OP_ICM] = "CC_OP_ICM", - [CC_OP_SLA_32] = "CC_OP_SLA_32", - [CC_OP_SLA_64] = "CC_OP_SLA_64", - [CC_OP_FLOGR] = "CC_OP_FLOGR", -}; - -static inline const char *cc_name(int cc_op) -{ - return cc_names[cc_op]; -} - static inline void setcc(S390CPU *cpu, uint64_t cc) { CPUS390XState *env = &cpu->env; @@ -801,130 +434,6 @@ static inline void setcc(S390CPU *cpu, uint64_t cc) env->cc_op = cc; } -#ifndef CONFIG_USER_ONLY - -typedef struct LowCore -{ - /* prefix area: defined by architecture */ - uint32_t ccw1[2]; /* 0x000 */ - uint32_t ccw2[4]; /* 0x008 */ - uint8_t pad1[0x80-0x18]; /* 0x018 */ - uint32_t ext_params; /* 0x080 */ - uint16_t cpu_addr; /* 0x084 */ - uint16_t ext_int_code; /* 0x086 */ - uint16_t svc_ilen; /* 0x088 */ - uint16_t svc_code; /* 0x08a */ - uint16_t pgm_ilen; /* 0x08c */ - uint16_t pgm_code; /* 0x08e */ - uint32_t data_exc_code; /* 0x090 */ - uint16_t mon_class_num; /* 0x094 */ - uint16_t per_perc_atmid; /* 0x096 */ - uint64_t per_address; /* 0x098 */ - uint8_t exc_access_id; /* 0x0a0 */ - uint8_t per_access_id; /* 0x0a1 */ - uint8_t op_access_id; /* 0x0a2 */ - uint8_t ar_access_id; /* 0x0a3 */ - uint8_t pad2[0xA8-0xA4]; /* 0x0a4 */ - uint64_t trans_exc_code; /* 0x0a8 */ - uint64_t monitor_code; /* 0x0b0 */ - uint16_t subchannel_id; /* 0x0b8 */ - uint16_t subchannel_nr; /* 0x0ba */ - uint32_t io_int_parm; /* 0x0bc */ - uint32_t io_int_word; /* 0x0c0 */ - uint8_t pad3[0xc8-0xc4]; /* 0x0c4 */ - uint32_t stfl_fac_list; /* 0x0c8 */ - uint8_t pad4[0xe8-0xcc]; /* 0x0cc */ - uint32_t mcck_interruption_code[2]; /* 0x0e8 */ - uint8_t pad5[0xf4-0xf0]; /* 0x0f0 */ - uint32_t external_damage_code; /* 0x0f4 */ - uint64_t failing_storage_address; /* 0x0f8 */ - uint8_t pad6[0x110-0x100]; /* 0x100 */ - uint64_t per_breaking_event_addr; /* 0x110 */ - uint8_t pad7[0x120-0x118]; /* 0x118 */ - PSW restart_old_psw; /* 0x120 */ - PSW external_old_psw; /* 0x130 */ - PSW svc_old_psw; /* 0x140 */ - PSW program_old_psw; /* 0x150 */ - PSW mcck_old_psw; /* 0x160 */ - PSW io_old_psw; /* 0x170 */ - uint8_t pad8[0x1a0-0x180]; /* 0x180 */ - PSW restart_new_psw; /* 0x1a0 */ - PSW external_new_psw; /* 0x1b0 */ - PSW svc_new_psw; /* 0x1c0 */ - PSW program_new_psw; /* 0x1d0 */ - PSW mcck_new_psw; /* 0x1e0 */ - PSW io_new_psw; /* 0x1f0 */ - PSW return_psw; /* 0x200 */ - uint8_t irb[64]; /* 0x210 */ - uint64_t sync_enter_timer; /* 0x250 */ - uint64_t async_enter_timer; /* 0x258 */ - uint64_t exit_timer; /* 0x260 */ - uint64_t last_update_timer; /* 0x268 */ - uint64_t user_timer; /* 0x270 */ - uint64_t system_timer; /* 0x278 */ - uint64_t last_update_clock; /* 0x280 */ - uint64_t steal_clock; /* 0x288 */ - PSW return_mcck_psw; /* 0x290 */ - uint8_t pad9[0xc00-0x2a0]; /* 0x2a0 */ - /* System info area */ - uint64_t save_area[16]; /* 0xc00 */ - uint8_t pad10[0xd40-0xc80]; /* 0xc80 */ - uint64_t kernel_stack; /* 0xd40 */ - uint64_t thread_info; /* 0xd48 */ - uint64_t async_stack; /* 0xd50 */ - uint64_t kernel_asce; /* 0xd58 */ - uint64_t user_asce; /* 0xd60 */ - uint64_t panic_stack; /* 0xd68 */ - uint64_t user_exec_asce; /* 0xd70 */ - uint8_t pad11[0xdc0-0xd78]; /* 0xd78 */ - - /* SMP info area: defined by DJB */ - uint64_t clock_comparator; /* 0xdc0 */ - uint64_t ext_call_fast; /* 0xdc8 */ - uint64_t percpu_offset; /* 0xdd0 */ - uint64_t current_task; /* 0xdd8 */ - uint32_t softirq_pending; /* 0xde0 */ - uint32_t pad_0x0de4; /* 0xde4 */ - uint64_t int_clock; /* 0xde8 */ - uint8_t pad12[0xe00-0xdf0]; /* 0xdf0 */ - - /* 0xe00 is used as indicator for dump tools */ - /* whether the kernel died with panic() or not */ - uint32_t panic_magic; /* 0xe00 */ - - uint8_t pad13[0x11b8-0xe04]; /* 0xe04 */ - - /* 64 bit extparam used for pfault, diag 250 etc */ - uint64_t ext_params2; /* 0x11B8 */ - - uint8_t pad14[0x1200-0x11C0]; /* 0x11C0 */ - - /* System info area */ - - uint64_t floating_pt_save_area[16]; /* 0x1200 */ - uint64_t gpregs_save_area[16]; /* 0x1280 */ - uint32_t st_status_fixed_logout[4]; /* 0x1300 */ - uint8_t pad15[0x1318-0x1310]; /* 0x1310 */ - uint32_t prefixreg_save_area; /* 0x1318 */ - uint32_t fpt_creg_save_area; /* 0x131c */ - uint8_t pad16[0x1324-0x1320]; /* 0x1320 */ - uint32_t tod_progreg_save_area; /* 0x1324 */ - uint32_t cpu_timer_save_area[2]; /* 0x1328 */ - uint32_t clock_comp_save_area[2]; /* 0x1330 */ - uint8_t pad17[0x1340-0x1338]; /* 0x1338 */ - uint32_t access_regs_save_area[16]; /* 0x1340 */ - uint64_t cregs_save_area[16]; /* 0x1380 */ - - /* align to the top of the prefix area */ - - uint8_t pad18[0x2000-0x1400]; /* 0x1400 */ -} QEMU_PACKED LowCore; - -LowCore *cpu_map_lowcore(CPUS390XState *env); -void cpu_unmap_lowcore(LowCore *lowcore); - -#endif - /* STSI */ #define STSI_LEVEL_MASK 0x00000000f0000000ULL #define STSI_LEVEL_CURRENT 0x0000000000000000ULL @@ -1100,210 +609,10 @@ struct sysib_322 { /* SIGP order code mask corresponding to bit positions 56-63 */ #define SIGP_ORDER_MASK 0x000000ff -void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); -uint64_t get_psw_mask(CPUS390XState *env); -target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr); -int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, - target_ulong *raddr, int *flags, bool exc); -int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code); -uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, - uint64_t vr); -void s390_cpu_recompute_watchpoints(CPUState *cs); - -int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf, - int len, bool is_write); - -#define s390_cpu_virt_mem_read(cpu, laddr, ar, dest, len) \ - s390_cpu_virt_mem_rw(cpu, laddr, ar, dest, len, false) -#define s390_cpu_virt_mem_write(cpu, laddr, ar, dest, len) \ - s390_cpu_virt_mem_rw(cpu, laddr, ar, dest, len, true) -#define s390_cpu_virt_mem_check_write(cpu, laddr, ar, len) \ - s390_cpu_virt_mem_rw(cpu, laddr, ar, NULL, len, true) - -/* The value of the TOD clock for 1.1.1970. */ -#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL - -/* Converts ns to s390's clock format */ -static inline uint64_t time2tod(uint64_t ns) { - return (ns << 9) / 125; -} - -/* Converts s390's clock format to ns */ -static inline uint64_t tod2time(uint64_t t) { - return (t * 125) >> 9; -} - /* from s390-virtio-ccw */ #define MEM_SECTION_SIZE 0x10000000UL #define MAX_AVAIL_SLOTS 32 -/* fpu_helper.c */ -uint32_t set_cc_nz_f32(float32 v); -uint32_t set_cc_nz_f64(float64 v); -uint32_t set_cc_nz_f128(float128 v); - -/* misc_helper.c */ -#ifndef CONFIG_USER_ONLY -int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3); -void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3); -#endif -/* automatically detect the instruction length */ -#define ILEN_AUTO 0xff -void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); -void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen); -void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, - uintptr_t retaddr); - -#ifdef CONFIG_KVM -void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code); -void kvm_s390_io_interrupt(uint16_t subchannel_id, - uint16_t subchannel_nr, uint32_t io_int_parm, - uint32_t io_int_word); -void kvm_s390_crw_mchk(void); -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); -int kvm_s390_get_memslot_count(KVMState *s); -int kvm_s390_cmma_active(void); -void kvm_s390_cmma_reset(void); -int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); -void kvm_s390_reset_vcpu(S390CPU *cpu); -int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit); -void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); -int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); -int kvm_s390_get_ri(void); -int kvm_s390_get_gs(void); -void kvm_s390_crypto_reset(void); -#else -static inline void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code) -{ -} -static inline void kvm_s390_io_interrupt(uint16_t subchannel_id, - uint16_t subchannel_nr, - uint32_t io_int_parm, - uint32_t io_int_word) -{ -} -static inline void kvm_s390_crw_mchk(void) -{ -} -static inline void kvm_s390_enable_css_support(S390CPU *cpu) -{ -} -static inline int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, - uint32_t sch, int vq, - bool assign) -{ - return -ENOSYS; -} -static inline int kvm_s390_cpu_restart(S390CPU *cpu) -{ - return -ENOSYS; -} -static inline void kvm_s390_cmma_reset(void) -{ -} -static inline int kvm_s390_get_memslot_count(KVMState *s) -{ - return MAX_AVAIL_SLOTS; -} -static inline int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state) -{ - return -ENOSYS; -} -static inline void kvm_s390_reset_vcpu(S390CPU *cpu) -{ -} -static inline int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, - uint64_t *hw_limit) -{ - return 0; -} -static inline void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu) -{ -} -static inline int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) -{ - return 0; -} -static inline int kvm_s390_get_ri(void) -{ - return 0; -} -static inline int kvm_s390_get_gs(void) -{ - return 0; -} -static inline void kvm_s390_crypto_reset(void) -{ -} -#endif - -static inline int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit) -{ - if (kvm_enabled()) { - return kvm_s390_set_mem_limit(kvm_state, new_limit, hw_limit); - } - return 0; -} - -static inline void s390_cmma_reset(void) -{ - if (kvm_enabled()) { - kvm_s390_cmma_reset(); - } -} - -static inline int s390_cpu_restart(S390CPU *cpu) -{ - if (kvm_enabled()) { - return kvm_s390_cpu_restart(cpu); - } - return -ENOSYS; -} - -static inline int s390_get_memslot_count(KVMState *s) -{ - if (kvm_enabled()) { - return kvm_s390_get_memslot_count(s); - } else { - return MAX_AVAIL_SLOTS; - } -} - -void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, - uint32_t io_int_parm, uint32_t io_int_word); -void s390_crw_mchk(void); - -static inline int s390_assign_subch_ioeventfd(EventNotifier *notifier, - uint32_t sch_id, int vq, - bool assign) -{ - if (kvm_enabled()) { - return kvm_s390_assign_subch_ioeventfd(notifier, sch_id, vq, assign); - } else { - return 0; - } -} - -static inline void s390_crypto_reset(void) -{ - if (kvm_enabled()) { - kvm_s390_crypto_reset(); - } -} - -static inline bool s390_get_squash_mcss(void) -{ - if (object_property_get_bool(OBJECT(qdev_get_machine()), "s390-squash-mcss", - NULL)) { - return true; - } - - return false; -} - /* machine check interruption code */ /* subclasses */ @@ -1349,4 +658,72 @@ static inline bool s390_get_squash_mcss(void) #define MCIC_VB_CT 0x0000000000020000ULL #define MCIC_VB_CC 0x0000000000010000ULL + +/* cpu.c */ +int s390_get_clock(uint8_t *tod_high, uint64_t *tod_low); +int s390_set_clock(uint8_t *tod_high, uint64_t *tod_low); +void s390_crypto_reset(void); +bool s390_get_squash_mcss(void); +int s390_get_memslot_count(void); +int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit); +void s390_cmma_reset(void); +int s390_cpu_restart(S390CPU *cpu); +void s390_enable_css_support(S390CPU *cpu); +int s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch_id, + int vq, bool assign); +#ifndef CONFIG_USER_ONLY +unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu); +#else +static inline unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu) +{ + return 0; +} +#endif /* CONFIG_USER_ONLY */ + + +/* cpu_models.c */ +void s390_cpu_list(FILE *f, fprintf_function cpu_fprintf); +#define cpu_list s390_cpu_list +const char *s390_default_cpu_model_name(void); + + +/* helper.c */ +S390CPU *cpu_s390x_init(const char *cpu_model); +#define cpu_init(model) CPU(cpu_s390x_init(model)) +S390CPU *s390x_new_cpu(const char *cpu_model, int64_t id, Error **errp); +/* you can call this signal handler from your SIGBUS and SIGSEGV + signal handlers to inform the virtual CPU of exceptions. non zero + is returned if the signal was handled by the virtual CPU. */ +int cpu_s390x_signal_handler(int host_signum, void *pinfo, void *puc); +#define cpu_signal_handler cpu_s390x_signal_handler + + +/* interrupt.c */ +void s390_crw_mchk(void); +void s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, + uint32_t io_int_parm, uint32_t io_int_word); +/* automatically detect the instruction length */ +#define ILEN_AUTO 0xff +void program_interrupt(CPUS390XState *env, uint32_t code, int ilen); +/* service interrupts are floating therefore we must not pass an cpustate */ +void s390_sclp_extint(uint32_t parm); + + +/* mmu_helper.c */ +int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf, + int len, bool is_write); +#define s390_cpu_virt_mem_read(cpu, laddr, ar, dest, len) \ + s390_cpu_virt_mem_rw(cpu, laddr, ar, dest, len, false) +#define s390_cpu_virt_mem_write(cpu, laddr, ar, dest, len) \ + s390_cpu_virt_mem_rw(cpu, laddr, ar, dest, len, true) +#define s390_cpu_virt_mem_check_write(cpu, laddr, ar, len) \ + s390_cpu_virt_mem_rw(cpu, laddr, ar, NULL, len, true) + + +/* outside of target/s390x/ */ +S390CPU *s390_cpu_addr2state(uint16_t cpu_addr); +extern void subsystem_reset(void); +int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code); +int s390_virtio_hypercall(CPUS390XState *env); + #endif diff --git a/target/s390x/cpu_models.c b/target/s390x/cpu_models.c index fa1338f..18cbf91 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -12,6 +12,9 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" +#include "kvm_s390x.h" +#include "sysemu/kvm.h" #include "gen-features.h" #include "qapi/error.h" #include "qapi/visitor.h" @@ -1200,6 +1203,14 @@ ObjectClass *s390_cpu_class_by_name(const char *name) return oc; } +const char *s390_default_cpu_model_name(void) +{ + if (kvm_enabled()) { + return "host"; + } + return "qemu"; +} + static const TypeInfo qemu_s390_cpu_type_info = { .name = S390_CPU_TYPE_NAME("qemu"), .parent = TYPE_S390_CPU, diff --git a/target/s390x/diag.c b/target/s390x/diag.c index 10ac845..e6b5e6d 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -14,6 +14,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" #include "exec/address-spaces.h" #include "exec/exec-all.h" #include "hw/watchdog/wdt_diag288.h" @@ -39,6 +40,13 @@ static int modified_clear_reset(S390CPU *cpu) return 0; } +static inline void s390_do_cpu_reset(CPUState *cs, run_on_cpu_data arg) +{ + S390CPUClass *scc = S390_CPU_GET_CLASS(cs); + + scc->cpu_reset(cs); +} + static int load_normal_reset(S390CPU *cpu) { S390CPUClass *scc = S390_CPU_GET_CLASS(cpu); diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index d183377..361f970 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "cpu.h" +#include "internal.h" #include "qemu/timer.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" @@ -68,6 +69,20 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr address, #else /* !CONFIG_USER_ONLY */ +static inline uint64_t cpu_mmu_idx_to_asc(int mmu_idx) +{ + switch (mmu_idx) { + case MMU_PRIMARY_IDX: + return PSW_ASC_PRIMARY; + case MMU_SECONDARY_IDX: + return PSW_ASC_SECONDARY; + case MMU_HOME_IDX: + return PSW_ASC_HOME; + default: + abort(); + } +} + int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr orig_vaddr, int rw, int mmu_idx) { diff --git a/target/s390x/fpu_helper.c b/target/s390x/fpu_helper.c index 26f124f..ffbeb3b 100644 --- a/target/s390x/fpu_helper.c +++ b/target/s390x/fpu_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" #include "exec/helper-proto.h" diff --git a/target/s390x/gdbstub.c b/target/s390x/gdbstub.c index a7efafe..b8c81da 100644 --- a/target/s390x/gdbstub.c +++ b/target/s390x/gdbstub.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "cpu.h" +#include "internal.h" #include "exec/exec-all.h" #include "exec/gdbstub.h" #include "qemu/bitops.h" diff --git a/target/s390x/helper.c b/target/s390x/helper.c index 0c989b1..3adb9de 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qapi/error.h" #include "cpu.h" +#include "internal.h" #include "exec/gdbstub.h" #include "qemu/timer.h" #include "exec/exec-all.h" @@ -352,3 +353,51 @@ void s390_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, cpu_fprintf(f, "\n"); } + +const char *cc_name(enum cc_op cc_op) +{ + static const char * const cc_names[] = { + [CC_OP_CONST0] = "CC_OP_CONST0", + [CC_OP_CONST1] = "CC_OP_CONST1", + [CC_OP_CONST2] = "CC_OP_CONST2", + [CC_OP_CONST3] = "CC_OP_CONST3", + [CC_OP_DYNAMIC] = "CC_OP_DYNAMIC", + [CC_OP_STATIC] = "CC_OP_STATIC", + [CC_OP_NZ] = "CC_OP_NZ", + [CC_OP_LTGT_32] = "CC_OP_LTGT_32", + [CC_OP_LTGT_64] = "CC_OP_LTGT_64", + [CC_OP_LTUGTU_32] = "CC_OP_LTUGTU_32", + [CC_OP_LTUGTU_64] = "CC_OP_LTUGTU_64", + [CC_OP_LTGT0_32] = "CC_OP_LTGT0_32", + [CC_OP_LTGT0_64] = "CC_OP_LTGT0_64", + [CC_OP_ADD_64] = "CC_OP_ADD_64", + [CC_OP_ADDU_64] = "CC_OP_ADDU_64", + [CC_OP_ADDC_64] = "CC_OP_ADDC_64", + [CC_OP_SUB_64] = "CC_OP_SUB_64", + [CC_OP_SUBU_64] = "CC_OP_SUBU_64", + [CC_OP_SUBB_64] = "CC_OP_SUBB_64", + [CC_OP_ABS_64] = "CC_OP_ABS_64", + [CC_OP_NABS_64] = "CC_OP_NABS_64", + [CC_OP_ADD_32] = "CC_OP_ADD_32", + [CC_OP_ADDU_32] = "CC_OP_ADDU_32", + [CC_OP_ADDC_32] = "CC_OP_ADDC_32", + [CC_OP_SUB_32] = "CC_OP_SUB_32", + [CC_OP_SUBU_32] = "CC_OP_SUBU_32", + [CC_OP_SUBB_32] = "CC_OP_SUBB_32", + [CC_OP_ABS_32] = "CC_OP_ABS_32", + [CC_OP_NABS_32] = "CC_OP_NABS_32", + [CC_OP_COMP_32] = "CC_OP_COMP_32", + [CC_OP_COMP_64] = "CC_OP_COMP_64", + [CC_OP_TM_32] = "CC_OP_TM_32", + [CC_OP_TM_64] = "CC_OP_TM_64", + [CC_OP_NZ_F32] = "CC_OP_NZ_F32", + [CC_OP_NZ_F64] = "CC_OP_NZ_F64", + [CC_OP_NZ_F128] = "CC_OP_NZ_F128", + [CC_OP_ICM] = "CC_OP_ICM", + [CC_OP_SLA_32] = "CC_OP_SLA_32", + [CC_OP_SLA_64] = "CC_OP_SLA_64", + [CC_OP_FLOGR] = "CC_OP_FLOGR", + }; + + return cc_names[cc_op]; +} diff --git a/target/s390x/int_helper.c b/target/s390x/int_helper.c index f26f36a..0076bea 100644 --- a/target/s390x/int_helper.c +++ b/target/s390x/int_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" #include "exec/exec-all.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" diff --git a/target/s390x/internal.h b/target/s390x/internal.h new file mode 100644 index 0000000..b4d3583 --- /dev/null +++ b/target/s390x/internal.h @@ -0,0 +1,391 @@ +/* + * s390x internal definitions and helpers + * + * Copyright (c) 2009 Ulrich Hecht + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef S390X_INTERNAL_H +#define S390X_INTERNAL_H + +#include "cpu.h" + +#ifndef CONFIG_USER_ONLY +typedef struct LowCore { + /* prefix area: defined by architecture */ + uint32_t ccw1[2]; /* 0x000 */ + uint32_t ccw2[4]; /* 0x008 */ + uint8_t pad1[0x80 - 0x18]; /* 0x018 */ + uint32_t ext_params; /* 0x080 */ + uint16_t cpu_addr; /* 0x084 */ + uint16_t ext_int_code; /* 0x086 */ + uint16_t svc_ilen; /* 0x088 */ + uint16_t svc_code; /* 0x08a */ + uint16_t pgm_ilen; /* 0x08c */ + uint16_t pgm_code; /* 0x08e */ + uint32_t data_exc_code; /* 0x090 */ + uint16_t mon_class_num; /* 0x094 */ + uint16_t per_perc_atmid; /* 0x096 */ + uint64_t per_address; /* 0x098 */ + uint8_t exc_access_id; /* 0x0a0 */ + uint8_t per_access_id; /* 0x0a1 */ + uint8_t op_access_id; /* 0x0a2 */ + uint8_t ar_access_id; /* 0x0a3 */ + uint8_t pad2[0xA8 - 0xA4]; /* 0x0a4 */ + uint64_t trans_exc_code; /* 0x0a8 */ + uint64_t monitor_code; /* 0x0b0 */ + uint16_t subchannel_id; /* 0x0b8 */ + uint16_t subchannel_nr; /* 0x0ba */ + uint32_t io_int_parm; /* 0x0bc */ + uint32_t io_int_word; /* 0x0c0 */ + uint8_t pad3[0xc8 - 0xc4]; /* 0x0c4 */ + uint32_t stfl_fac_list; /* 0x0c8 */ + uint8_t pad4[0xe8 - 0xcc]; /* 0x0cc */ + uint32_t mcck_interruption_code[2]; /* 0x0e8 */ + uint8_t pad5[0xf4 - 0xf0]; /* 0x0f0 */ + uint32_t external_damage_code; /* 0x0f4 */ + uint64_t failing_storage_address; /* 0x0f8 */ + uint8_t pad6[0x110 - 0x100]; /* 0x100 */ + uint64_t per_breaking_event_addr; /* 0x110 */ + uint8_t pad7[0x120 - 0x118]; /* 0x118 */ + PSW restart_old_psw; /* 0x120 */ + PSW external_old_psw; /* 0x130 */ + PSW svc_old_psw; /* 0x140 */ + PSW program_old_psw; /* 0x150 */ + PSW mcck_old_psw; /* 0x160 */ + PSW io_old_psw; /* 0x170 */ + uint8_t pad8[0x1a0 - 0x180]; /* 0x180 */ + PSW restart_new_psw; /* 0x1a0 */ + PSW external_new_psw; /* 0x1b0 */ + PSW svc_new_psw; /* 0x1c0 */ + PSW program_new_psw; /* 0x1d0 */ + PSW mcck_new_psw; /* 0x1e0 */ + PSW io_new_psw; /* 0x1f0 */ + PSW return_psw; /* 0x200 */ + uint8_t irb[64]; /* 0x210 */ + uint64_t sync_enter_timer; /* 0x250 */ + uint64_t async_enter_timer; /* 0x258 */ + uint64_t exit_timer; /* 0x260 */ + uint64_t last_update_timer; /* 0x268 */ + uint64_t user_timer; /* 0x270 */ + uint64_t system_timer; /* 0x278 */ + uint64_t last_update_clock; /* 0x280 */ + uint64_t steal_clock; /* 0x288 */ + PSW return_mcck_psw; /* 0x290 */ + uint8_t pad9[0xc00 - 0x2a0]; /* 0x2a0 */ + /* System info area */ + uint64_t save_area[16]; /* 0xc00 */ + uint8_t pad10[0xd40 - 0xc80]; /* 0xc80 */ + uint64_t kernel_stack; /* 0xd40 */ + uint64_t thread_info; /* 0xd48 */ + uint64_t async_stack; /* 0xd50 */ + uint64_t kernel_asce; /* 0xd58 */ + uint64_t user_asce; /* 0xd60 */ + uint64_t panic_stack; /* 0xd68 */ + uint64_t user_exec_asce; /* 0xd70 */ + uint8_t pad11[0xdc0 - 0xd78]; /* 0xd78 */ + + /* SMP info area: defined by DJB */ + uint64_t clock_comparator; /* 0xdc0 */ + uint64_t ext_call_fast; /* 0xdc8 */ + uint64_t percpu_offset; /* 0xdd0 */ + uint64_t current_task; /* 0xdd8 */ + uint32_t softirq_pending; /* 0xde0 */ + uint32_t pad_0x0de4; /* 0xde4 */ + uint64_t int_clock; /* 0xde8 */ + uint8_t pad12[0xe00 - 0xdf0]; /* 0xdf0 */ + + /* 0xe00 is used as indicator for dump tools */ + /* whether the kernel died with panic() or not */ + uint32_t panic_magic; /* 0xe00 */ + + uint8_t pad13[0x11b8 - 0xe04]; /* 0xe04 */ + + /* 64 bit extparam used for pfault, diag 250 etc */ + uint64_t ext_params2; /* 0x11B8 */ + + uint8_t pad14[0x1200 - 0x11C0]; /* 0x11C0 */ + + /* System info area */ + + uint64_t floating_pt_save_area[16]; /* 0x1200 */ + uint64_t gpregs_save_area[16]; /* 0x1280 */ + uint32_t st_status_fixed_logout[4]; /* 0x1300 */ + uint8_t pad15[0x1318 - 0x1310]; /* 0x1310 */ + uint32_t prefixreg_save_area; /* 0x1318 */ + uint32_t fpt_creg_save_area; /* 0x131c */ + uint8_t pad16[0x1324 - 0x1320]; /* 0x1320 */ + uint32_t tod_progreg_save_area; /* 0x1324 */ + uint32_t cpu_timer_save_area[2]; /* 0x1328 */ + uint32_t clock_comp_save_area[2]; /* 0x1330 */ + uint8_t pad17[0x1340 - 0x1338]; /* 0x1338 */ + uint32_t access_regs_save_area[16]; /* 0x1340 */ + uint64_t cregs_save_area[16]; /* 0x1380 */ + + /* align to the top of the prefix area */ + + uint8_t pad18[0x2000 - 0x1400]; /* 0x1400 */ +} QEMU_PACKED LowCore; +#endif /* CONFIG_USER_ONLY */ + +#define MAX_ILEN 6 + +/* While the PoO talks about ILC (a number between 1-3) what is actually + stored in LowCore is shifted left one bit (an even between 2-6). As + this is the actual length of the insn and therefore more useful, that + is what we want to pass around and manipulate. To make sure that we + have applied this distinction universally, rename the "ILC" to "ILEN". */ +static inline int get_ilen(uint8_t opc) +{ + switch (opc >> 6) { + case 0: + return 2; + case 1: + case 2: + return 4; + default: + return 6; + } +} + +/* Compute the ATMID field that is stored in the per_perc_atmid lowcore + entry when a PER exception is triggered. */ +static inline uint8_t get_per_atmid(CPUS390XState *env) +{ + return ((env->psw.mask & PSW_MASK_64) ? (1 << 7) : 0) | + (1 << 6) | + ((env->psw.mask & PSW_MASK_32) ? (1 << 5) : 0) | + ((env->psw.mask & PSW_MASK_DAT) ? (1 << 4) : 0) | + ((env->psw.mask & PSW_ASC_SECONDARY) ? (1 << 3) : 0) | + ((env->psw.mask & PSW_ASC_ACCREG) ? (1 << 2) : 0); +} + +/* CC optimization */ + +/* Instead of computing the condition codes after each x86 instruction, + * QEMU just stores the result (called CC_DST), the type of operation + * (called CC_OP) and whatever operands are needed (CC_SRC and possibly + * CC_VR). When the condition codes are needed, the condition codes can + * be calculated using this information. Condition codes are not generated + * if they are only needed for conditional branches. + */ +enum cc_op { + CC_OP_CONST0 = 0, /* CC is 0 */ + CC_OP_CONST1, /* CC is 1 */ + CC_OP_CONST2, /* CC is 2 */ + CC_OP_CONST3, /* CC is 3 */ + + CC_OP_DYNAMIC, /* CC calculation defined by env->cc_op */ + CC_OP_STATIC, /* CC value is env->cc_op */ + + CC_OP_NZ, /* env->cc_dst != 0 */ + CC_OP_LTGT_32, /* signed less/greater than (32bit) */ + CC_OP_LTGT_64, /* signed less/greater than (64bit) */ + CC_OP_LTUGTU_32, /* unsigned less/greater than (32bit) */ + CC_OP_LTUGTU_64, /* unsigned less/greater than (64bit) */ + CC_OP_LTGT0_32, /* signed less/greater than 0 (32bit) */ + CC_OP_LTGT0_64, /* signed less/greater than 0 (64bit) */ + + CC_OP_ADD_64, /* overflow on add (64bit) */ + CC_OP_ADDU_64, /* overflow on unsigned add (64bit) */ + CC_OP_ADDC_64, /* overflow on unsigned add-carry (64bit) */ + CC_OP_SUB_64, /* overflow on subtraction (64bit) */ + CC_OP_SUBU_64, /* overflow on unsigned subtraction (64bit) */ + CC_OP_SUBB_64, /* overflow on unsigned sub-borrow (64bit) */ + CC_OP_ABS_64, /* sign eval on abs (64bit) */ + CC_OP_NABS_64, /* sign eval on nabs (64bit) */ + + CC_OP_ADD_32, /* overflow on add (32bit) */ + CC_OP_ADDU_32, /* overflow on unsigned add (32bit) */ + CC_OP_ADDC_32, /* overflow on unsigned add-carry (32bit) */ + CC_OP_SUB_32, /* overflow on subtraction (32bit) */ + CC_OP_SUBU_32, /* overflow on unsigned subtraction (32bit) */ + CC_OP_SUBB_32, /* overflow on unsigned sub-borrow (32bit) */ + CC_OP_ABS_32, /* sign eval on abs (64bit) */ + CC_OP_NABS_32, /* sign eval on nabs (64bit) */ + + CC_OP_COMP_32, /* complement */ + CC_OP_COMP_64, /* complement */ + + CC_OP_TM_32, /* test under mask (32bit) */ + CC_OP_TM_64, /* test under mask (64bit) */ + + CC_OP_NZ_F32, /* FP dst != 0 (32bit) */ + CC_OP_NZ_F64, /* FP dst != 0 (64bit) */ + CC_OP_NZ_F128, /* FP dst != 0 (128bit) */ + + CC_OP_ICM, /* insert characters under mask */ + CC_OP_SLA_32, /* Calculate shift left signed (32bit) */ + CC_OP_SLA_64, /* Calculate shift left signed (64bit) */ + CC_OP_FLOGR, /* find leftmost one */ + CC_OP_MAX +}; + +/* The value of the TOD clock for 1.1.1970. */ +#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL + +/* Converts ns to s390's clock format */ +static inline uint64_t time2tod(uint64_t ns) +{ + return (ns << 9) / 125; +} + +/* Converts s390's clock format to ns */ +static inline uint64_t tod2time(uint64_t t) +{ + return (t * 125) >> 9; +} + +static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb, + uint8_t *ar) +{ + hwaddr addr = 0; + uint8_t reg; + + reg = ipb >> 28; + if (reg > 0) { + addr = env->regs[reg]; + } + addr += (ipb >> 16) & 0xfff; + if (ar) { + *ar = reg; + } + + return addr; +} + +/* Base/displacement are at the same locations. */ +#define decode_basedisp_rs decode_basedisp_s + +static inline void s390_do_cpu_full_reset(CPUState *cs, run_on_cpu_data arg) +{ + cpu_reset(cs); +} + +static inline uint8_t s390_cpu_get_state(S390CPU *cpu) +{ + return cpu->env.cpu_state; +} + + +/* arch_dump.c */ +int s390_cpu_write_elf64_note(WriteCoreDumpFunction f, CPUState *cs, + int cpuid, void *opaque); + + +/* cc_helper.c */ +const char *cc_name(enum cc_op cc_op); +void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr); +uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, + uint64_t vr); + + +/* cpu.c */ +#ifndef CONFIG_USER_ONLY +unsigned int s390_cpu_halt(S390CPU *cpu); +void s390_cpu_unhalt(S390CPU *cpu); +#else +static inline unsigned int s390_cpu_halt(S390CPU *cpu) +{ + return 0; +} + +static inline void s390_cpu_unhalt(S390CPU *cpu) +{ +} +#endif /* CONFIG_USER_ONLY */ + + +/* cpu_models.c */ +void s390_cpu_model_register_props(Object *obj); +void s390_cpu_model_class_register_props(ObjectClass *oc); +void s390_realize_cpu_model(CPUState *cs, Error **errp); +ObjectClass *s390_cpu_class_by_name(const char *name); + + +/* excp_helper.c */ +void s390x_cpu_debug_excp_handler(CPUState *cs); +void s390_cpu_do_interrupt(CPUState *cpu); +bool s390_cpu_exec_interrupt(CPUState *cpu, int int_req); +int s390_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw, + int mmu_idx); +void s390x_cpu_do_unaligned_access(CPUState *cs, vaddr addr, + MMUAccessType access_type, + int mmu_idx, uintptr_t retaddr); + + +/* fpu_helper.c */ +uint32_t set_cc_nz_f32(float32 v); +uint32_t set_cc_nz_f64(float64 v); +uint32_t set_cc_nz_f128(float128 v); + + +/* gdbstub.c */ +int s390_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int s390_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +void s390_cpu_gdb_init(CPUState *cs); + + +/* helper.c */ +void s390_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf, + int flags); +hwaddr s390_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +hwaddr s390_cpu_get_phys_addr_debug(CPUState *cpu, vaddr addr); +uint64_t get_psw_mask(CPUS390XState *env); +void s390_cpu_recompute_watchpoints(CPUState *cs); +void s390x_tod_timer(void *opaque); +void s390x_cpu_timer(void *opaque); +S390CPU *cpu_s390x_create(const char *cpu_model, Error **errp); +void do_restart_interrupt(CPUS390XState *env); +#ifndef CONFIG_USER_ONLY +LowCore *cpu_map_lowcore(CPUS390XState *env); +void cpu_unmap_lowcore(LowCore *lowcore); +#endif /* CONFIG_USER_ONLY */ + + +/* interrupt.c */ +void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilen); +void cpu_inject_ext(S390CPU *cpu, uint32_t code, uint32_t param, + uint64_t param64); + + +/* ioinst.c */ +void ioinst_handle_xsch(S390CPU *cpu, uint64_t reg1); +void ioinst_handle_csch(S390CPU *cpu, uint64_t reg1); +void ioinst_handle_hsch(S390CPU *cpu, uint64_t reg1); +void ioinst_handle_msch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); +void ioinst_handle_ssch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); +void ioinst_handle_stcrw(S390CPU *cpu, uint32_t ipb); +void ioinst_handle_stsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); +int ioinst_handle_tsch(S390CPU *cpu, uint64_t reg1, uint32_t ipb); +void ioinst_handle_chsc(S390CPU *cpu, uint32_t ipb); +int ioinst_handle_tpi(S390CPU *cpu, uint32_t ipb); +void ioinst_handle_schm(S390CPU *cpu, uint64_t reg1, uint64_t reg2, + uint32_t ipb); +void ioinst_handle_rsch(S390CPU *cpu, uint64_t reg1); +void ioinst_handle_rchp(S390CPU *cpu, uint64_t reg1); +void ioinst_handle_sal(S390CPU *cpu, uint64_t reg1); + + +/* mem_helper.c */ +target_ulong mmu_real2abs(CPUS390XState *env, target_ulong raddr); + + +/* mmu_helper.c */ +int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, + target_ulong *raddr, int *flags, bool exc); + + +/* misc_helper.c */ +void QEMU_NORETURN runtime_exception(CPUS390XState *env, int excp, + uintptr_t retaddr); +int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3); +void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3); + + +/* translate.c */ +void s390x_translate_init(void); + +#endif /* S390X_INTERNAL_H */ diff --git a/target/s390x/interrupt.c b/target/s390x/interrupt.c index fde3da7..058e219 100644 --- a/target/s390x/interrupt.c +++ b/target/s390x/interrupt.c @@ -10,6 +10,8 @@ #include "qemu/osdep.h" #include "qemu/log.h" #include "cpu.h" +#include "kvm_s390x.h" +#include "internal.h" #include "exec/exec-all.h" #include "sysemu/kvm.h" #include "hw/s390x/ioinst.h" diff --git a/target/s390x/ioinst.c b/target/s390x/ioinst.c index 51fbea6..47490f8 100644 --- a/target/s390x/ioinst.c +++ b/target/s390x/ioinst.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" #include "hw/s390x/ioinst.h" #include "trace.h" #include "hw/s390x/s390-pci-bus.h" @@ -599,6 +600,22 @@ static int chsc_sei_nt0_have_event(void) return 0; } +static int chsc_sei_nt2_get_event(void *res) +{ + if (s390_has_feat(S390_FEAT_ZPCI)) { + return pci_chsc_sei_nt2_get_event(res); + } + return 1; +} + +static int chsc_sei_nt2_have_event(void) +{ + if (s390_has_feat(S390_FEAT_ZPCI)) { + return pci_chsc_sei_nt2_have_event(); + } + return 0; +} + #define CHSC_SEI_NT0 (1ULL << 63) #define CHSC_SEI_NT2 (1ULL << 61) static void ioinst_handle_chsc_sei(ChscReq *req, ChscResp *res) diff --git a/target/s390x/kvm-stub.c b/target/s390x/kvm-stub.c new file mode 100644 index 0000000..261e1cd --- /dev/null +++ b/target/s390x/kvm-stub.c @@ -0,0 +1,111 @@ +/* + * QEMU KVM support -- s390x specific function stubs. + * + * Copyright (c) 2009 Ulrich Hecht + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "cpu.h" +#include "kvm_s390x.h" + +void kvm_s390_service_interrupt(uint32_t parm) +{ +} + +void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code) +{ +} + +int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, + int len, bool is_write) +{ + return -ENOSYS; +} + +void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code) +{ +} + +void kvm_s390_io_interrupt(uint16_t subchannel_id, uint16_t subchannel_nr, + uint32_t io_int_parm, uint32_t io_int_word) +{ +} + +void kvm_s390_crw_mchk(void) +{ +} + +int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state) +{ + return -ENOSYS; +} + +void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu) +{ +} + +int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu) +{ + return 0; +} + +int kvm_s390_get_ri(void) +{ + return 0; +} + +int kvm_s390_get_gs(void) +{ + return 0; +} + +int kvm_s390_get_clock(uint8_t *tod_high, uint64_t *tod_low) +{ + return -ENOSYS; +} + +int kvm_s390_set_clock(uint8_t *tod_high, uint64_t *tod_low) +{ + return -ENOSYS; +} + +void kvm_s390_enable_css_support(S390CPU *cpu) +{ +} + +int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, + int vq, bool assign) +{ + return -ENOSYS; +} + +int kvm_s390_cpu_restart(S390CPU *cpu) +{ + return -ENOSYS; +} + +void kvm_s390_cmma_reset(void) +{ +} + +int kvm_s390_get_memslot_count(void) +{ + return MAX_AVAIL_SLOTS; +} + +void kvm_s390_reset_vcpu(S390CPU *cpu) +{ +} + +int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit) +{ + return 0; +} + +void kvm_s390_crypto_reset(void) +{ +} diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index c4c5791..d07763f 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -29,6 +29,8 @@ #include "qemu-common.h" #include "cpu.h" +#include "internal.h" +#include "kvm_s390x.h" #include "qemu/error-report.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" @@ -145,7 +147,7 @@ static int active_cmma; static void *legacy_s390_alloc(size_t size, uint64_t *align); -static int kvm_s390_query_mem_limit(KVMState *s, uint64_t *memory_limit) +static int kvm_s390_query_mem_limit(uint64_t *memory_limit) { struct kvm_device_attr attr = { .group = KVM_S390_VM_MEM_CTRL, @@ -153,10 +155,10 @@ static int kvm_s390_query_mem_limit(KVMState *s, uint64_t *memory_limit) .addr = (uint64_t) memory_limit, }; - return kvm_vm_ioctl(s, KVM_GET_DEVICE_ATTR, &attr); + return kvm_vm_ioctl(kvm_state, KVM_GET_DEVICE_ATTR, &attr); } -int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit) +int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit) { int rc; @@ -166,18 +168,18 @@ int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit) .addr = (uint64_t) &new_limit, }; - if (!kvm_vm_check_mem_attr(s, KVM_S390_VM_MEM_LIMIT_SIZE)) { + if (!kvm_vm_check_mem_attr(kvm_state, KVM_S390_VM_MEM_LIMIT_SIZE)) { return 0; } - rc = kvm_s390_query_mem_limit(s, hw_limit); + rc = kvm_s390_query_mem_limit(hw_limit); if (rc) { return rc; } else if (*hw_limit < new_limit) { return -E2BIG; } - return kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr); + return kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ATTR, &attr); } int kvm_s390_cmma_active(void) @@ -1191,7 +1193,11 @@ static int kvm_clp_service_call(S390CPU *cpu, struct kvm_run *run) { uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16; - return clp_service_call(cpu, r2); + if (s390_has_feat(S390_FEAT_ZPCI)) { + return clp_service_call(cpu, r2); + } else { + return -1; + } } static int kvm_pcilg_service_call(S390CPU *cpu, struct kvm_run *run) @@ -1199,7 +1205,11 @@ static int kvm_pcilg_service_call(S390CPU *cpu, struct kvm_run *run) uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20; uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16; - return pcilg_service_call(cpu, r1, r2); + if (s390_has_feat(S390_FEAT_ZPCI)) { + return pcilg_service_call(cpu, r1, r2); + } else { + return -1; + } } static int kvm_pcistg_service_call(S390CPU *cpu, struct kvm_run *run) @@ -1207,7 +1217,11 @@ static int kvm_pcistg_service_call(S390CPU *cpu, struct kvm_run *run) uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20; uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16; - return pcistg_service_call(cpu, r1, r2); + if (s390_has_feat(S390_FEAT_ZPCI)) { + return pcistg_service_call(cpu, r1, r2); + } else { + return -1; + } } static int kvm_stpcifc_service_call(S390CPU *cpu, struct kvm_run *run) @@ -1216,10 +1230,14 @@ static int kvm_stpcifc_service_call(S390CPU *cpu, struct kvm_run *run) uint64_t fiba; uint8_t ar; - cpu_synchronize_state(CPU(cpu)); - fiba = get_base_disp_rxy(cpu, run, &ar); + if (s390_has_feat(S390_FEAT_ZPCI)) { + cpu_synchronize_state(CPU(cpu)); + fiba = get_base_disp_rxy(cpu, run, &ar); - return stpcifc_service_call(cpu, r1, fiba, ar); + return stpcifc_service_call(cpu, r1, fiba, ar); + } else { + return -1; + } } static int kvm_sic_service_call(S390CPU *cpu, struct kvm_run *run) @@ -1247,7 +1265,11 @@ static int kvm_rpcit_service_call(S390CPU *cpu, struct kvm_run *run) uint8_t r1 = (run->s390_sieic.ipb & 0x00f00000) >> 20; uint8_t r2 = (run->s390_sieic.ipb & 0x000f0000) >> 16; - return rpcit_service_call(cpu, r1, r2); + if (s390_has_feat(S390_FEAT_ZPCI)) { + return rpcit_service_call(cpu, r1, r2); + } else { + return -1; + } } static int kvm_pcistb_service_call(S390CPU *cpu, struct kvm_run *run) @@ -1257,10 +1279,14 @@ static int kvm_pcistb_service_call(S390CPU *cpu, struct kvm_run *run) uint64_t gaddr; uint8_t ar; - cpu_synchronize_state(CPU(cpu)); - gaddr = get_base_disp_rsy(cpu, run, &ar); + if (s390_has_feat(S390_FEAT_ZPCI)) { + cpu_synchronize_state(CPU(cpu)); + gaddr = get_base_disp_rsy(cpu, run, &ar); - return pcistb_service_call(cpu, r1, r3, gaddr, ar); + return pcistb_service_call(cpu, r1, r3, gaddr, ar); + } else { + return -1; + } } static int kvm_mpcifc_service_call(S390CPU *cpu, struct kvm_run *run) @@ -1269,10 +1295,14 @@ static int kvm_mpcifc_service_call(S390CPU *cpu, struct kvm_run *run) uint64_t fiba; uint8_t ar; - cpu_synchronize_state(CPU(cpu)); - fiba = get_base_disp_rxy(cpu, run, &ar); + if (s390_has_feat(S390_FEAT_ZPCI)) { + cpu_synchronize_state(CPU(cpu)); + fiba = get_base_disp_rxy(cpu, run, &ar); - return mpcifc_service_call(cpu, r1, fiba, ar); + return mpcifc_service_call(cpu, r1, fiba, ar); + } else { + return -1; + } } static int handle_b9(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1) @@ -2289,9 +2319,9 @@ int kvm_s390_assign_subch_ioeventfd(EventNotifier *notifier, uint32_t sch, return kvm_vm_ioctl(kvm_state, KVM_IOEVENTFD, &kick); } -int kvm_s390_get_memslot_count(KVMState *s) +int kvm_s390_get_memslot_count(void) { - return kvm_check_extension(s, KVM_CAP_NR_MEMSLOTS); + return kvm_check_extension(kvm_state, KVM_CAP_NR_MEMSLOTS); } int kvm_s390_get_ri(void) @@ -2662,7 +2692,9 @@ void kvm_s390_get_host_cpu_model(S390CPUModel *model, Error **errp) } /* We emulate a zPCI bus and AEN, therefore we don't need HW support */ - set_bit(S390_FEAT_ZPCI, model->features); + if (pci_available) { + set_bit(S390_FEAT_ZPCI, model->features); + } set_bit(S390_FEAT_ADAPTER_EVENT_NOTIFICATION, model->features); if (s390_known_cpu_type(cpu_type)) { diff --git a/target/s390x/kvm_s390x.h b/target/s390x/kvm_s390x.h new file mode 100644 index 0000000..2d594bd --- /dev/null +++ b/target/s390x/kvm_s390x.h @@ -0,0 +1,47 @@ +/* + * QEMU KVM support -- s390x specific functions. + * + * Copyright (c) 2009 Ulrich Hecht + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + */ + +#ifndef KVM_S390X_H +#define KVM_S390X_H + +struct kvm_s390_irq; + +void kvm_s390_floating_interrupt(struct kvm_s390_irq *irq); +void kvm_s390_service_interrupt(uint32_t parm); +void kvm_s390_vcpu_interrupt(S390CPU *cpu, struct kvm_s390_irq *irq); +void kvm_s390_access_exception(S390CPU *cpu, uint16_t code, uint64_t te_code); +int kvm_s390_mem_op(S390CPU *cpu, vaddr addr, uint8_t ar, void *hostbuf, + int len, bool is_write); +void kvm_s390_program_interrupt(S390CPU *cpu, uint16_t code); +void kvm_s390_io_interrupt(uint16_t subchannel_id, + uint16_t subchannel_nr, uint32_t io_int_parm, + uint32_t io_int_word); +void kvm_s390_crw_mchk(void); +int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state); +void kvm_s390_vcpu_interrupt_pre_save(S390CPU *cpu); +int kvm_s390_vcpu_interrupt_post_load(S390CPU *cpu); +int kvm_s390_get_ri(void); +int kvm_s390_get_gs(void); +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); +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); +int kvm_s390_get_memslot_count(void); +int kvm_s390_cmma_active(void); +void kvm_s390_cmma_reset(void); +void kvm_s390_reset_vcpu(S390CPU *cpu); +int kvm_s390_set_mem_limit(uint64_t new_limit, uint64_t *hw_limit); +void kvm_s390_crypto_reset(void); + +/* implemented outside of target/s390x/ */ +int kvm_s390_inject_flic(struct kvm_s390_irq *irq); + +#endif /* KVM_S390X_H */ diff --git a/target/s390x/machine.c b/target/s390x/machine.c index 2dcadfd..097a147 100644 --- a/target/s390x/machine.c +++ b/target/s390x/machine.c @@ -17,6 +17,8 @@ #include "qemu/osdep.h" #include "hw/hw.h" #include "cpu.h" +#include "internal.h" +#include "kvm_s390x.h" #include "sysemu/kvm.h" static int cpu_post_load(void *opaque, int version_id) diff --git a/target/s390x/mem_helper.c b/target/s390x/mem_helper.c index c71dce4..ec4760e 100644 --- a/target/s390x/mem_helper.c +++ b/target/s390x/mem_helper.c @@ -20,6 +20,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" #include "exec/address-spaces.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" @@ -56,6 +57,17 @@ void tlb_fill(CPUState *cs, target_ulong addr, MMUAccessType access_type, #define HELPER_LOG(x...) #endif +static inline bool psw_key_valid(CPUS390XState *env, uint8_t psw_key) +{ + uint16_t pkm = env->cregs[3] >> 16; + + if (env->psw.mask & PSW_MASK_PSTATE) { + /* PSW key has range 0..15, it is valid if the bit is 1 in the PKM */ + return pkm & (0x80 >> psw_key); + } + return true; +} + /* Reduce the length so that addr + len doesn't cross a page boundary. */ static inline uint32_t adj_len_to_page(uint32_t len, uint64_t addr) { diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index d23ffcd..50cc046 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -21,6 +21,7 @@ #include "qemu/osdep.h" #include "qemu/main-loop.h" #include "cpu.h" +#include "internal.h" #include "exec/memory.h" #include "qemu/host-utils.h" #include "exec/helper-proto.h" @@ -103,13 +104,17 @@ void HELPER(diag)(CPUS390XState *env, uint32_t r1, uint32_t r3, uint32_t num) handle_diag_308(env, r1, r3); r = 0; break; + case 0x288: + /* time bomb (watchdog) */ + r = handle_diag_288(env, r1, r3); + break; default: r = -1; break; } if (r) { - program_interrupt(env, PGM_OPERATION, ILEN_AUTO); + program_interrupt(env, PGM_SPECIFICATION, ILEN_AUTO); } } @@ -451,6 +456,17 @@ void HELPER(per_check_exception)(CPUS390XState *env) } } +/* Check if an address is within the PER starting address and the PER + ending address. The address range might loop. */ +static inline bool get_per_in_range(CPUS390XState *env, uint64_t addr) +{ + if (env->cregs[10] <= env->cregs[11]) { + return env->cregs[10] <= addr && addr <= env->cregs[11]; + } else { + return env->cregs[10] <= addr || addr <= env->cregs[11]; + } +} + void HELPER(per_branch)(CPUS390XState *env, uint64_t from, uint64_t to) { if ((env->cregs[9] & PER_CR9_EVENT_BRANCH)) { diff --git a/target/s390x/mmu_helper.c b/target/s390x/mmu_helper.c index 1ad0158..b528c59 100644 --- a/target/s390x/mmu_helper.c +++ b/target/s390x/mmu_helper.c @@ -19,6 +19,8 @@ #include "qemu/error-report.h" #include "exec/address-spaces.h" #include "cpu.h" +#include "internal.h" +#include "kvm_s390x.h" #include "sysemu/kvm.h" #include "trace.h" #include "hw/s390x/storage-keys.h" diff --git a/target/s390x/translate.c b/target/s390x/translate.c index cd96a8d..4b0db7b 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -30,6 +30,7 @@ #include "qemu/osdep.h" #include "cpu.h" +#include "internal.h" #include "disas/disas.h" #include "exec/exec-all.h" #include "tcg-op.h" diff --git a/tests/Makefile.include b/tests/Makefile.include index 37c1bed..f08b741 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -283,8 +283,8 @@ ifeq ($(CONFIG_VHOST_USER_NET_TEST_i386),) check-qtest-x86_64-$(CONFIG_VHOST_USER_NET_TEST_x86_64) += tests/vhost-user-test$(EXESUF) endif check-qtest-i386-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) -check-qtest-i386-y += tests/test-filter-mirror$(EXESUF) -check-qtest-i386-y += tests/test-filter-redirector$(EXESUF) +check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) +check-qtest-i386-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF) check-qtest-i386-y += tests/postcopy-test$(EXESUF) check-qtest-i386-y += tests/test-x86-cpuid-compat$(EXESUF) check-qtest-i386-y += tests/numa-test$(EXESUF) @@ -325,8 +325,8 @@ check-qtest-ppc64-y += tests/usb-hcd-xhci-test$(EXESUF) gcov-files-ppc64-y += hw/usb/hcd-xhci.c check-qtest-ppc64-y += $(check-qtest-virtio-y) check-qtest-ppc64-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) -check-qtest-ppc64-y += tests/test-filter-mirror$(EXESUF) -check-qtest-ppc64-y += tests/test-filter-redirector$(EXESUF) +check-qtest-ppc64-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) +check-qtest-ppc64-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF) check-qtest-ppc64-y += tests/display-vga-test$(EXESUF) check-qtest-ppc64-y += tests/numa-test$(EXESUF) check-qtest-ppc64-$(CONFIG_IVSHMEM) += tests/ivshmem-test$(EXESUF) @@ -360,6 +360,10 @@ check-qtest-microblazeel-y = $(check-qtest-microblaze-y) check-qtest-xtensaeb-y = $(check-qtest-xtensa-y) check-qtest-s390x-y = tests/boot-serial-test$(EXESUF) +check-qtest-s390x-$(CONFIG_SLIRP) += tests/pxe-test$(EXESUF) +check-qtest-s390x-$(CONFIG_SLIRP) += tests/test-netfilter$(EXESUF) +check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-mirror$(EXESUF) +check-qtest-s390x-$(CONFIG_POSIX) += tests/test-filter-redirector$(EXESUF) check-qtest-generic-y += tests/qom-test$(EXESUF) check-qtest-generic-y += tests/test-hmp$(EXESUF) diff --git a/tests/boot-sector.c b/tests/boot-sector.c index e3880f4..9ee8537 100644 --- a/tests/boot-sector.c +++ b/tests/boot-sector.c @@ -21,13 +21,12 @@ #define SIGNATURE 0xdead #define SIGNATURE_OFFSET 0x10 #define BOOT_SECTOR_ADDRESS 0x7c00 +#define SIGNATURE_ADDR (BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET) -/* Boot sector code: write SIGNATURE into memory, +/* x86 boot sector code: write SIGNATURE into memory, * then halt. - * Q35 machine requires a minimum 0x7e000 bytes disk. - * (bug or feature?) */ -static uint8_t boot_sector[0x7e000] = { +static uint8_t x86_boot_sector[512] = { /* The first sector will be placed at RAM address 00007C00, and * the BIOS transfers control to 00007C00 */ @@ -50,8 +49,8 @@ static uint8_t boot_sector[0x7e000] = { [0x07] = HIGH(SIGNATURE), /* 7c08: mov %ax,0x7c10 */ [0x08] = 0xa3, - [0x09] = LOW(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), - [0x0a] = HIGH(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET), + [0x09] = LOW(SIGNATURE_ADDR), + [0x0a] = HIGH(SIGNATURE_ADDR), /* 7c0b cli */ [0x0b] = 0xfa, @@ -68,11 +67,28 @@ static uint8_t boot_sector[0x7e000] = { [0x1FF] = 0xAA, }; +/* For s390x, use a mini "kernel" with the appropriate signature */ +static const uint8_t s390x_psw[] = { + 0x00, 0x08, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00 +}; +static const uint8_t s390x_code[] = { + 0xa7, 0xf4, 0x00, 0x0a, /* j 0x10010 */ + 0x00, 0x00, 0x00, 0x00, + 'S', '3', '9', '0', + 'E', 'P', 0x00, 0x01, + 0xa7, 0x38, HIGH(SIGNATURE_ADDR), LOW(SIGNATURE_ADDR), /* lhi r3,0x7c10 */ + 0xa7, 0x48, LOW(SIGNATURE), HIGH(SIGNATURE), /* lhi r4,0xadde */ + 0x40, 0x40, 0x30, 0x00, /* sth r4,0(r3) */ + 0xa7, 0xf4, 0xff, 0xfa /* j 0x10010 */ +}; + /* Create boot disk file. */ int boot_sector_init(char *fname) { int fd, ret; - size_t len = sizeof boot_sector; + size_t len; + char *boot_code; + const char *arch = qtest_get_arch(); fd = mkstemp(fname); if (fd < 0) { @@ -80,16 +96,31 @@ int boot_sector_init(char *fname) return 1; } - /* For Open Firmware based system, we can use a Forth script instead */ - if (strcmp(qtest_get_arch(), "ppc64") == 0) { - len = sprintf((char *)boot_sector, "\\ Bootscript\n%x %x c! %x %x c!\n", - LOW(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET, - HIGH(SIGNATURE), BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); + if (g_str_equal(arch, "i386") || g_str_equal(arch, "x86_64")) { + /* Q35 requires a minimum 0x7e000 bytes disk (bug or feature?) */ + len = MAX(0x7e000, sizeof(x86_boot_sector)); + boot_code = g_malloc0(len); + memcpy(boot_code, x86_boot_sector, sizeof(x86_boot_sector)); + } else if (g_str_equal(arch, "ppc64")) { + /* For Open Firmware based system, use a Forth script */ + boot_code = g_strdup_printf("\\ Bootscript\n%x %x c! %x %x c!\n", + LOW(SIGNATURE), SIGNATURE_ADDR, + HIGH(SIGNATURE), SIGNATURE_ADDR + 1); + len = strlen(boot_code); + } else if (g_str_equal(arch, "s390x")) { + len = 0x10000 + sizeof(s390x_code); + boot_code = g_malloc0(len); + memcpy(boot_code, s390x_psw, sizeof(s390x_psw)); + memcpy(&boot_code[0x10000], s390x_code, sizeof(s390x_code)); + } else { + g_assert_not_reached(); } - ret = write(fd, boot_sector, len); + ret = write(fd, boot_code, len); close(fd); + g_free(boot_code); + if (ret != len) { fprintf(stderr, "Could not write \"%s\"", fname); return 1; @@ -115,8 +146,8 @@ void boot_sector_test(void) * instruction. */ for (i = 0; i < TEST_CYCLES; ++i) { - signature_low = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET); - signature_high = readb(BOOT_SECTOR_ADDRESS + SIGNATURE_OFFSET + 1); + signature_low = readb(SIGNATURE_ADDR); + signature_high = readb(SIGNATURE_ADDR + 1); signature = (signature_high << 8) | signature_low; if (signature == SIGNATURE) { break; diff --git a/tests/pxe-test.c b/tests/pxe-test.c index cf6e225..0d70afc 100644 --- a/tests/pxe-test.c +++ b/tests/pxe-test.c @@ -51,6 +51,11 @@ static void test_pxe_spapr_vlan(void) test_pxe_one("-device spapr-vlan,netdev=" NETNAME, true); } +static void test_pxe_virtio_ccw(void) +{ + test_pxe_one("-device virtio-net-ccw,bootindex=1,netdev=" NETNAME, false); +} + int main(int argc, char *argv[]) { int ret; @@ -68,6 +73,8 @@ int main(int argc, char *argv[]) } else if (strcmp(arch, "ppc64") == 0) { qtest_add_func("pxe/virtio", test_pxe_virtio_pci); qtest_add_func("pxe/spapr-vlan", test_pxe_spapr_vlan); + } else if (g_str_equal(arch, "s390x")) { + qtest_add_func("pxe/virtio-ccw", test_pxe_virtio_ccw); } ret = g_test_run(); boot_sector_cleanup(disk); diff --git a/tests/test-filter-mirror.c b/tests/test-filter-mirror.c index 9f84402..d569d27 100644 --- a/tests/test-filter-mirror.c +++ b/tests/test-filter-mirror.c @@ -17,9 +17,6 @@ static void test_mirror(void) { -#ifndef _WIN32 -/* socketpair(PF_UNIX) which does not exist on windows */ - int send_sock[2], recv_sock; char *cmdline; uint32_t ret = 0, len = 0; @@ -28,6 +25,11 @@ static void test_mirror(void) char *recv_buf; uint32_t size = sizeof(send_buf); size = htonl(size); + const char *devstr = "e1000"; + + if (g_str_equal(qtest_get_arch(), "s390x")) { + devstr = "virtio-net-ccw"; + } ret = socketpair(PF_UNIX, SOCK_STREAM, 0, send_sock); g_assert_cmpint(ret, !=, -1); @@ -36,10 +38,10 @@ static void test_mirror(void) g_assert_cmpint(ret, !=, -1); cmdline = g_strdup_printf("-netdev socket,id=qtest-bn0,fd=%d " - "-device e1000,netdev=qtest-bn0,id=qtest-e0 " + "-device %s,netdev=qtest-bn0,id=qtest-e0 " "-chardev socket,id=mirror0,path=%s,server,nowait " "-object filter-mirror,id=qtest-f0,netdev=qtest-bn0,queue=tx,outdev=mirror0 " - , send_sock[1], sock_path); + , send_sock[1], devstr, sock_path); qtest_start(cmdline); g_free(cmdline); @@ -74,8 +76,6 @@ static void test_mirror(void) g_free(recv_buf); close(recv_sock); unlink(sock_path); - -#endif } int main(int argc, char **argv) diff --git a/tests/test-filter-redirector.c b/tests/test-filter-redirector.c index 0c4b8d5..3afd411 100644 --- a/tests/test-filter-redirector.c +++ b/tests/test-filter-redirector.c @@ -57,11 +57,18 @@ #include "qemu/error-report.h" #include "qemu/main-loop.h" -static void test_redirector_tx(void) +static const char *get_devstr(void) { -#ifndef _WIN32 -/* socketpair(PF_UNIX) which does not exist on windows */ + if (g_str_equal(qtest_get_arch(), "s390x")) { + return "virtio-net-ccw"; + } + + return "rtl8139"; +} + +static void test_redirector_tx(void) +{ int backend_sock[2], recv_sock; char *cmdline; uint32_t ret = 0, len = 0; @@ -81,7 +88,7 @@ static void test_redirector_tx(void) g_assert_cmpint(ret, !=, -1); cmdline = g_strdup_printf("-netdev socket,id=qtest-bn0,fd=%d " - "-device rtl8139,netdev=qtest-bn0,id=qtest-e0 " + "-device %s,netdev=qtest-bn0,id=qtest-e0 " "-chardev socket,id=redirector0,path=%s,server,nowait " "-chardev socket,id=redirector1,path=%s,server,nowait " "-chardev socket,id=redirector2,path=%s,nowait " @@ -90,8 +97,8 @@ static void test_redirector_tx(void) "-object filter-redirector,id=qtest-f1,netdev=qtest-bn0," "queue=tx,indev=redirector2 " "-object filter-redirector,id=qtest-f2,netdev=qtest-bn0," - "queue=tx,outdev=redirector1 " - , backend_sock[1], sock_path0, sock_path1, sock_path0); + "queue=tx,outdev=redirector1 ", backend_sock[1], get_devstr(), + sock_path0, sock_path1, sock_path0); qtest_start(cmdline); g_free(cmdline); @@ -129,15 +136,10 @@ static void test_redirector_tx(void) unlink(sock_path0); unlink(sock_path1); qtest_end(); - -#endif } static void test_redirector_rx(void) { -#ifndef _WIN32 -/* socketpair(PF_UNIX) which does not exist on windows */ - int backend_sock[2], send_sock; char *cmdline; uint32_t ret = 0, len = 0; @@ -157,7 +159,7 @@ static void test_redirector_rx(void) g_assert_cmpint(ret, !=, -1); cmdline = g_strdup_printf("-netdev socket,id=qtest-bn0,fd=%d " - "-device rtl8139,netdev=qtest-bn0,id=qtest-e0 " + "-device %s,netdev=qtest-bn0,id=qtest-e0 " "-chardev socket,id=redirector0,path=%s,server,nowait " "-chardev socket,id=redirector1,path=%s,server,nowait " "-chardev socket,id=redirector2,path=%s,nowait " @@ -166,8 +168,8 @@ static void test_redirector_rx(void) "-object filter-redirector,id=qtest-f1,netdev=qtest-bn0," "queue=rx,outdev=redirector2 " "-object filter-redirector,id=qtest-f2,netdev=qtest-bn0," - "queue=rx,indev=redirector1 " - , backend_sock[1], sock_path0, sock_path1, sock_path0); + "queue=rx,indev=redirector1 ", backend_sock[1], get_devstr(), + sock_path0, sock_path1, sock_path0); qtest_start(cmdline); g_free(cmdline); @@ -203,8 +205,6 @@ static void test_redirector_rx(void) unlink(sock_path0); unlink(sock_path1); qtest_end(); - -#endif } int main(int argc, char **argv) diff --git a/tests/test-netfilter.c b/tests/test-netfilter.c index 8b5a9b2..2506473 100644 --- a/tests/test-netfilter.c +++ b/tests/test-netfilter.c @@ -182,6 +182,12 @@ static void remove_netdev_with_multi_netfilter(void) int main(int argc, char **argv) { int ret; + char *args; + const char *devstr = "e1000"; + + if (g_str_equal(qtest_get_arch(), "s390x")) { + devstr = "virtio-net-ccw"; + } g_test_init(&argc, &argv, NULL); qtest_add_func("/netfilter/addremove_one", add_one_netfilter); @@ -191,10 +197,13 @@ int main(int argc, char **argv) qtest_add_func("/netfilter/remove_netdev_multi", remove_netdev_with_multi_netfilter); - qtest_start("-netdev user,id=qtest-bn0 -device e1000,netdev=qtest-bn0"); + args = g_strdup_printf("-netdev user,id=qtest-bn0 " + "-device %s,netdev=qtest-bn0", devstr); + qtest_start(args); ret = g_test_run(); qtest_end(); + g_free(args); return ret; } |