diff options
author | Peter Maydell | 2017-09-19 19:08:48 +0200 |
---|---|---|
committer | Peter Maydell | 2017-09-19 19:08:48 +0200 |
commit | c51700273ad9802a21c19f8d2b4bcb67c38e74ac (patch) | |
tree | 2ce01f3c430947dd0d8c467900bdc557422c2b8d | |
parent | Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging (diff) | |
parent | MAINTAINERS/s390x: add terminal3270.c (diff) | |
download | qemu-c51700273ad9802a21c19f8d2b4bcb67c38e74ac.tar.gz qemu-c51700273ad9802a21c19f8d2b4bcb67c38e74ac.tar.xz qemu-c51700273ad9802a21c19f8d2b4bcb67c38e74ac.zip |
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20170919-v2' into staging
Assorted s390x patches:
- introduce virtio-gpu-ccw, with virtio-gpu endian fixes
- lots of cleanup in the s390x code
- make device_add work for s390x cpus
- enable seccomp on s390x
- an ivshmem endian fix
- set the reserved DHCP client architecture id for netboot
- fixes in the css and pci support
# gpg: Signature made Tue 19 Sep 2017 17:39:45 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-20170919-v2: (38 commits)
MAINTAINERS/s390x: add terminal3270.c
virtio-ccw: Create a virtio gpu device for the ccw bus
virtio-gpu: Handle endian conversion
s390x/ccw: create s390 phb for compat reasons as well
configure: Allow --enable-seccomp on s390x, too
virtio-ccw: remove stale comments on endianness
s390x: allow CPU hotplug in random core-id order
s390x: generate sclp cpu information from possible_cpus
s390x: get rid of cpu_s390x_create()
s390x: get rid of cpu_states and use possible_cpus instead
s390x: implement query-hotpluggable-cpus
s390x: CPU hot unplug via device_del cannot work for now
s390x: allow cpu hotplug via device_add
s390x: print CPU definitions in sorted order
target/s390x: rename next_cpu_id to next_core_id
target/s390x: use "core-id" for cpu number/address/id handling
target/s390x: set cpu->id for linux user when realizing
s390x: allow only 1 CPU with TCG
target/s390x: use program_interrupt() in per_check_exception()
target/s390x: use trigger_pgm_exception() in s390_cpu_handle_mmu_fault()
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
46 files changed, 591 insertions, 519 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index ef7c191dbb..3d735979ef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -789,6 +789,7 @@ M: Christian Borntraeger <borntraeger@de.ibm.com> M: Alexander Graf <agraf@suse.de> S: Supported F: hw/char/sclp*.[hc] +F: hw/char/terminal3270.c F: hw/s390x/ F: include/hw/s390x/ F: pc-bios/s390-ccw/ @@ -2025,7 +2025,7 @@ if test "$seccomp" != "no" ; then arm|aarch64) libseccomp_minver="2.2.3" ;; - ppc|ppc64) + ppc|ppc64|s390x) libseccomp_minver="2.3.0" ;; *) @@ -15,7 +15,6 @@ #include "qemu/cutils.h" #include "elf.h" #include "cpu.h" -#include "exec/cpu-all.h" #include "exec/hwaddr.h" #include "monitor/monitor.h" #include "sysemu/kvm.h" @@ -56,7 +56,6 @@ #endif #endif -#include "exec/cpu-all.h" #include "qemu/rcu_queue.h" #include "qemu/main-loop.h" #include "translate-all.h" diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c index 622ee300f9..3a8f1e1a2d 100644 --- a/hw/display/virtio-gpu.c +++ b/hw/display/virtio-gpu.c @@ -30,6 +30,48 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id); static void virtio_gpu_cleanup_mapping(struct virtio_gpu_simple_resource *res); +static void +virtio_gpu_ctrl_hdr_bswap(struct virtio_gpu_ctrl_hdr *hdr) +{ + le32_to_cpus(&hdr->type); + le32_to_cpus(&hdr->flags); + le64_to_cpus(&hdr->fence_id); + le32_to_cpus(&hdr->ctx_id); + le32_to_cpus(&hdr->padding); +} + +static void virtio_gpu_bswap_32(void *ptr, + size_t size) +{ +#ifdef HOST_WORDS_BIGENDIAN + + size_t i; + struct virtio_gpu_ctrl_hdr *hdr = (struct virtio_gpu_ctrl_hdr *) ptr; + + virtio_gpu_ctrl_hdr_bswap(hdr); + + i = sizeof(struct virtio_gpu_ctrl_hdr); + while (i < size) { + le32_to_cpus((uint32_t *)(ptr + i)); + i = i + sizeof(uint32_t); + } + +#endif +} + +static void +virtio_gpu_t2d_bswap(struct virtio_gpu_transfer_to_host_2d *t2d) +{ + virtio_gpu_ctrl_hdr_bswap(&t2d->hdr); + le32_to_cpus(&t2d->r.x); + le32_to_cpus(&t2d->r.y); + le32_to_cpus(&t2d->r.width); + le32_to_cpus(&t2d->r.height); + le64_to_cpus(&t2d->offset); + le32_to_cpus(&t2d->resource_id); + le32_to_cpus(&t2d->padding); +} + #ifdef CONFIG_VIRGL #include <virglrenderer.h> #define VIRGL(_g, _virgl, _simple, ...) \ @@ -205,6 +247,7 @@ void virtio_gpu_ctrl_response(VirtIOGPU *g, resp->fence_id = cmd->cmd_hdr.fence_id; resp->ctx_id = cmd->cmd_hdr.ctx_id; } + virtio_gpu_ctrl_hdr_bswap(resp); s = iov_from_buf(cmd->elem.in_sg, cmd->elem.in_num, 0, resp, resp_len); if (s != resp_len) { qemu_log_mask(LOG_GUEST_ERROR, @@ -236,8 +279,8 @@ virtio_gpu_fill_display_info(VirtIOGPU *g, for (i = 0; i < g->conf.max_outputs; i++) { if (g->enabled_output_bitmask & (1 << i)) { dpy_info->pmodes[i].enabled = 1; - dpy_info->pmodes[i].r.width = g->req_state[i].width; - dpy_info->pmodes[i].r.height = g->req_state[i].height; + dpy_info->pmodes[i].r.width = cpu_to_le32(g->req_state[i].width); + dpy_info->pmodes[i].r.height = cpu_to_le32(g->req_state[i].height); } } } @@ -287,6 +330,7 @@ static void virtio_gpu_resource_create_2d(VirtIOGPU *g, struct virtio_gpu_resource_create_2d c2d; VIRTIO_GPU_FILL_CMD(c2d); + virtio_gpu_bswap_32(&c2d, sizeof(c2d)); trace_virtio_gpu_cmd_res_create_2d(c2d.resource_id, c2d.format, c2d.width, c2d.height); @@ -360,6 +404,7 @@ static void virtio_gpu_resource_unref(VirtIOGPU *g, struct virtio_gpu_resource_unref unref; VIRTIO_GPU_FILL_CMD(unref); + virtio_gpu_bswap_32(&unref, sizeof(unref)); trace_virtio_gpu_cmd_res_unref(unref.resource_id); res = virtio_gpu_find_resource(g, unref.resource_id); @@ -383,6 +428,7 @@ static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g, struct virtio_gpu_transfer_to_host_2d t2d; VIRTIO_GPU_FILL_CMD(t2d); + virtio_gpu_t2d_bswap(&t2d); trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id); res = virtio_gpu_find_resource(g, t2d.resource_id); @@ -439,6 +485,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g, int i; VIRTIO_GPU_FILL_CMD(rf); + virtio_gpu_bswap_32(&rf, sizeof(rf)); trace_virtio_gpu_cmd_res_flush(rf.resource_id, rf.r.width, rf.r.height, rf.r.x, rf.r.y); @@ -511,6 +558,7 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g, struct virtio_gpu_set_scanout ss; VIRTIO_GPU_FILL_CMD(ss); + virtio_gpu_bswap_32(&ss, sizeof(ss)); trace_virtio_gpu_cmd_set_scanout(ss.scanout_id, ss.resource_id, ss.r.width, ss.r.height, ss.r.x, ss.r.y); @@ -633,13 +681,15 @@ int virtio_gpu_create_mapping_iov(struct virtio_gpu_resource_attach_backing *ab, *addr = g_malloc0(sizeof(uint64_t) * ab->nr_entries); } for (i = 0; i < ab->nr_entries; i++) { - hwaddr len = ents[i].length; - (*iov)[i].iov_len = ents[i].length; - (*iov)[i].iov_base = cpu_physical_memory_map(ents[i].addr, &len, 1); + uint64_t a = le64_to_cpu(ents[i].addr); + uint32_t l = le32_to_cpu(ents[i].length); + hwaddr len = l; + (*iov)[i].iov_len = l; + (*iov)[i].iov_base = cpu_physical_memory_map(a, &len, 1); if (addr) { - (*addr)[i] = ents[i].addr; + (*addr)[i] = a; } - if (!(*iov)[i].iov_base || len != ents[i].length) { + if (!(*iov)[i].iov_base || len != l) { qemu_log_mask(LOG_GUEST_ERROR, "%s: failed to map MMIO memory for" " resource %d element %d\n", __func__, ab->resource_id, i); @@ -686,6 +736,7 @@ virtio_gpu_resource_attach_backing(VirtIOGPU *g, int ret; VIRTIO_GPU_FILL_CMD(ab); + virtio_gpu_bswap_32(&ab, sizeof(ab)); trace_virtio_gpu_cmd_res_back_attach(ab.resource_id); res = virtio_gpu_find_resource(g, ab.resource_id); @@ -718,6 +769,7 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g, struct virtio_gpu_resource_detach_backing detach; VIRTIO_GPU_FILL_CMD(detach); + virtio_gpu_bswap_32(&detach, sizeof(detach)); trace_virtio_gpu_cmd_res_back_detach(detach.resource_id); res = virtio_gpu_find_resource(g, detach.resource_id); @@ -734,6 +786,7 @@ static void virtio_gpu_simple_process_cmd(VirtIOGPU *g, struct virtio_gpu_ctrl_command *cmd) { VIRTIO_GPU_FILL_CMD(cmd->cmd_hdr); + virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr); switch (cmd->cmd_hdr.type) { case VIRTIO_GPU_CMD_GET_DISPLAY_INFO: @@ -879,6 +932,7 @@ static void virtio_gpu_handle_cursor(VirtIODevice *vdev, VirtQueue *vq) "%s: cursor size incorrect %zu vs %zu\n", __func__, s, sizeof(cursor_info)); } else { + virtio_gpu_bswap_32(&cursor_info, sizeof(cursor_info)); update_cursor(g, &cursor_info); } virtqueue_push(vq, elem, 0); @@ -1135,7 +1189,7 @@ static void virtio_gpu_device_realize(DeviceState *qdev, Error **errp) } g->config_size = sizeof(struct virtio_gpu_config); - g->virtio_config.num_scanouts = g->conf.max_outputs; + g->virtio_config.num_scanouts = cpu_to_le32(g->conf.max_outputs); virtio_init(VIRTIO_DEVICE(g), "virtio-gpu", VIRTIO_ID_GPU, g->config_size); diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c index 47a015f072..b3ef3ec1e3 100644 --- a/hw/misc/ivshmem.c +++ b/hw/misc/ivshmem.c @@ -653,7 +653,7 @@ static int64_t ivshmem_recv_msg(IVShmemState *s, int *pfd, Error **errp) } while (n < sizeof(msg)); *pfd = qemu_chr_fe_get_msgfd(&s->server_chr); - return msg; + return le64_to_cpu(msg); } static void ivshmem_recv_setup(IVShmemState *s, Error **errp) diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index 7ee19d3abc..dc704b57d6 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -1,4 +1,3 @@ -obj-y += s390-virtio.o obj-y += s390-virtio-hcall.o obj-y += sclp.o obj-y += event-facility.o diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 901dc6a0f3..75d4f301fb 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -793,7 +793,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, CCW1 ccw; if (!ccw_addr) { - return -EIO; + return -EINVAL; /* channel-program check */ } /* Check doubleword aligned and 31 or 24 (fmt 0) bit addressable. */ if (ccw_addr & (sch->ccw_fmt_1 ? 0x80000007 : 0xff000007)) { @@ -980,22 +980,6 @@ static void sch_handle_start_func_virtual(SubchDev *sch) SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; s->cpa = sch->channel_prog + 8; break; - case -EFAULT: - /* memory problem, generate channel data check */ - s->ctrl &= ~SCSW_ACTL_START_PEND; - s->cstat = SCSW_CSTAT_DATA_CHECK; - s->ctrl &= ~SCSW_CTRL_MASK_STCTL; - s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | - SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; - s->cpa = sch->channel_prog + 8; - break; - case -EBUSY: - /* subchannel busy, generate deferred cc 1 */ - s->flags &= ~SCSW_FLAGS_MASK_CC; - s->flags |= (1 << 8); - s->ctrl &= ~SCSW_CTRL_MASK_STCTL; - s->ctrl |= SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; - break; case -EINPROGRESS: /* channel program has been suspended */ s->ctrl &= ~SCSW_ACTL_START_PEND; @@ -1276,16 +1260,16 @@ int css_do_xsch(SubchDev *sch) goto out; } + if (s->ctrl & SCSW_CTRL_MASK_STCTL) { + ret = -EINPROGRESS; + goto out; + } + if (!(s->ctrl & SCSW_CTRL_MASK_FCTL) || ((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) || (!(s->ctrl & (SCSW_ACTL_RESUME_PEND | SCSW_ACTL_START_PEND | SCSW_ACTL_SUSP))) || (s->ctrl & SCSW_ACTL_SUBCH_ACTIVE)) { - ret = -EINPROGRESS; - goto out; - } - - if (s->ctrl & SCSW_CTRL_MASK_STCTL) { ret = -EBUSY; goto out; } diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 0a31a4ae88..3b9965fde0 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -199,8 +199,8 @@ static S390PCIBusDevice *s390_pci_find_dev_by_uid(S390pciState *s, uint16_t uid) return NULL; } -static S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s, - const char *target) +S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s, + const char *target) { S390PCIBusDevice *pbdev; @@ -397,6 +397,17 @@ static IOMMUTLBEntry s390_translate_iommu(IOMMUMemoryRegion *mr, hwaddr addr, return ret; } +static void s390_pci_iommu_replay(IOMMUMemoryRegion *iommu, + IOMMUNotifier *notifier) +{ + /* It's impossible to plug a pci device on s390x that already has iommu + * mappings which need to be replayed, that is due to the "one iommu per + * zpci device" construct. But when we support migration of vfio-pci + * devices in future, we need to revisit this. + */ + return; +} + static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, int devfn) { @@ -465,19 +476,13 @@ static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data, unsigned int size) { S390PCIBusDevice *pbdev = opaque; - uint32_t idx = data >> ZPCI_MSI_VEC_BITS; uint32_t vec = data & ZPCI_MSI_VEC_MASK; uint64_t ind_bit; uint32_t sum_bit; - uint32_t e = 0; - - DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data, idx, vec); - if (!pbdev) { - e |= (vec << ERR_EVENT_MVN_OFFSET); - s390_pci_generate_error_event(ERR_EVENT_NOMSI, idx, 0, addr, e); - return; - } + assert(pbdev); + DPRINTF("write_msix data 0x%" PRIx64 " idx %d vec 0x%x\n", data, + pbdev->idx, vec); if (pbdev->state != ZPCI_FS_ENABLED) { return; @@ -1051,6 +1056,7 @@ static void s390_iommu_memory_region_class_init(ObjectClass *klass, void *data) IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); imrc->translate = s390_translate_iommu; + imrc->replay = s390_pci_iommu_replay; } static const TypeInfo s390_iommu_memory_region_info = { diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h index bd636abc28..560bd82a0f 100644 --- a/hw/s390x/s390-pci-bus.h +++ b/hw/s390x/s390-pci-bus.h @@ -322,6 +322,8 @@ void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, uint32_t fid, S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx); S390PCIBusDevice *s390_pci_find_dev_by_fh(S390pciState *s, uint32_t fh); S390PCIBusDevice *s390_pci_find_dev_by_fid(S390pciState *s, uint32_t fid); +S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s, + const char *target); S390PCIBusDevice *s390_pci_find_next_avail_dev(S390pciState *s, S390PCIBusDevice *pbdev); diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index eba9ffb5f2..8e088f3dc9 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -413,29 +413,6 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) return 0; } -static void update_msix_table_msg_data(S390PCIBusDevice *pbdev, uint64_t offset, - uint64_t *data, uint8_t len) -{ - uint32_t val; - uint8_t *msg_data; - - if (offset % PCI_MSIX_ENTRY_SIZE != 8) { - return; - } - - if (len != 4) { - DPRINTF("access msix table msg data but len is %d\n", len); - return; - } - - msg_data = (uint8_t *)data - offset % PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_VECTOR_CTRL; - val = pci_get_long(msg_data) | - ((pbdev->fh & FH_MASK_INDEX) << ZPCI_MSI_VEC_BITS); - pci_set_long(msg_data, val); - DPRINTF("update msix msg_data to 0x%" PRIx64 "\n", *data); -} - static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias) { if (pbdev->msix.available && pbdev->msix.table_bar == pcias && @@ -508,7 +485,6 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) if (trap_msix(pbdev, offset, pcias)) { offset = offset - pbdev->msix.table_offset; mr = &pbdev->pdev->msix_table_mmio; - update_msix_table_msg_data(pbdev, offset, &data, len); } else { mr = pbdev->pdev->io_regions[pcias].memory; } diff --git a/hw/s390x/s390-pci-stub.c b/hw/s390x/s390-pci-stub.c index 7a642d376c..ad4c5a7719 100644 --- a/hw/s390x/s390-pci-stub.c +++ b/hw/s390x/s390-pci-stub.c @@ -70,7 +70,8 @@ S390pciState *s390_get_phb(void) return NULL; } -S390PCIBusDevice *s390_pci_find_dev_by_idx(S390pciState *s, uint32_t idx) +S390PCIBusDevice *s390_pci_find_dev_by_target(S390pciState *s, + const char *target) { return NULL; } diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index dd504dd5ae..fafbc6d4fe 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -2,6 +2,7 @@ * virtio ccw machine * * Copyright 2012 IBM Corp. + * Copyright (c) 2009 Alexander Graf <agraf@suse.de> * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> * * This work is licensed under the terms of the GNU GPL, version 2 or (at @@ -15,13 +16,14 @@ #include "cpu.h" #include "hw/boards.h" #include "exec/address-spaces.h" -#include "s390-virtio.h" +#include "hw/s390x/s390-virtio-hcall.h" #include "hw/s390x/sclp.h" #include "hw/s390x/s390_flic.h" #include "hw/s390x/ioinst.h" #include "hw/s390x/css.h" #include "virtio-ccw.h" #include "qemu/config-file.h" +#include "qemu/error-report.h" #include "s390-pci-bus.h" #include "hw/s390x/storage-keys.h" #include "hw/s390x/storage-attributes.h" @@ -31,6 +33,67 @@ #include "hw/s390x/css-bridge.h" #include "migration/register.h" #include "cpu_models.h" +#include "qapi/qmp/qerror.h" +#include "hw/nmi.h" + +S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) +{ + static MachineState *ms; + + if (!ms) { + ms = MACHINE(qdev_get_machine()); + g_assert(ms->possible_cpus); + } + + /* CPU address corresponds to the core_id and the index */ + if (cpu_addr >= ms->possible_cpus->len) { + return NULL; + } + return S390_CPU(ms->possible_cpus->cpus[cpu_addr].cpu); +} + +static void s390_init_cpus(MachineState *machine) +{ + MachineClass *mc = MACHINE_GET_CLASS(machine); + const char *typename; + gchar **model_pieces; + ObjectClass *oc; + CPUClass *cc; + int i; + + if (machine->cpu_model == NULL) { + machine->cpu_model = s390_default_cpu_model_name(); + } + if (tcg_enabled() && max_cpus > 1) { + error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " + "supported by TCG (1) on s390x", max_cpus); + exit(1); + } + + /* initialize possible_cpus */ + mc->possible_cpu_arch_ids(machine); + + model_pieces = g_strsplit(machine->cpu_model, ",", 2); + if (!model_pieces[0]) { + error_report("Invalid/empty CPU model name"); + exit(1); + } + + oc = cpu_class_by_name(TYPE_S390_CPU, model_pieces[0]); + if (!oc) { + error_report("Unable to find CPU definition: %s", model_pieces[0]); + exit(1); + } + typename = object_class_get_name(oc); + cc = CPU_CLASS(oc); + /* after parsing, properties will be applied to all *typename* instances */ + cc->parse_features(typename, model_pieces[1], &error_fatal); + g_strfreev(model_pieces); + + for (i = 0; i < smp_cpus; i++) { + s390x_new_cpu(typename, i, &error_fatal); + } +} static const char *const reset_dev_types[] = { TYPE_VIRTUAL_CSS_BRIDGE, @@ -94,7 +157,7 @@ static void virtio_ccw_register_hcalls(void) virtio_ccw_hcall_early_printk); } -void s390_memory_init(ram_addr_t mem_size) +static void s390_memory_init(ram_addr_t mem_size) { MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); @@ -109,11 +172,105 @@ void s390_memory_init(ram_addr_t mem_size) s390_stattrib_init(); } +#define S390_TOD_CLOCK_VALUE_MISSING 0x00 +#define S390_TOD_CLOCK_VALUE_PRESENT 0x01 + +static void gtod_save(QEMUFile *f, void *opaque) +{ + uint64_t tod_low; + uint8_t tod_high; + int r; + + r = s390_get_clock(&tod_high, &tod_low); + if (r) { + warn_report("Unable to get guest clock for migration: %s", + strerror(-r)); + error_printf("Guest clock will not be migrated " + "which could cause the guest to hang."); + qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING); + return; + } + + qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT); + qemu_put_byte(f, tod_high); + qemu_put_be64(f, tod_low); +} + +static int gtod_load(QEMUFile *f, void *opaque, int version_id) +{ + uint64_t tod_low; + uint8_t tod_high; + int r; + + if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) { + warn_report("Guest clock was not migrated. This could " + "cause the guest to hang."); + return 0; + } + + tod_high = qemu_get_byte(f); + tod_low = qemu_get_be64(f); + + r = s390_set_clock(&tod_high, &tod_low); + if (r) { + warn_report("Unable to set guest clock for migration: %s", + strerror(-r)); + error_printf("Guest clock will not be restored " + "which could cause the guest to hang."); + } + + return 0; +} + static SaveVMHandlers savevm_gtod = { .save_state = gtod_save, .load_state = gtod_load, }; +static void s390_init_ipl_dev(const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, const char *firmware, + const char *netboot_fw, bool enforce_bios) +{ + Object *new = object_new(TYPE_S390_IPL); + DeviceState *dev = DEVICE(new); + + if (kernel_filename) { + qdev_prop_set_string(dev, "kernel", kernel_filename); + } + if (initrd_filename) { + qdev_prop_set_string(dev, "initrd", initrd_filename); + } + qdev_prop_set_string(dev, "cmdline", kernel_cmdline); + qdev_prop_set_string(dev, "firmware", firmware); + qdev_prop_set_string(dev, "netboot_fw", netboot_fw); + qdev_prop_set_bit(dev, "enforce_bios", enforce_bios); + object_property_add_child(qdev_get_machine(), TYPE_S390_IPL, + new, NULL); + object_unref(new); + qdev_init_nofail(dev); +} + +static void s390_create_virtio_net(BusState *bus, const char *name) +{ + int i; + + for (i = 0; i < nb_nics; i++) { + NICInfo *nd = &nd_table[i]; + DeviceState *dev; + + if (!nd->model) { + nd->model = g_strdup("virtio"); + } + + qemu_check_nic_model(nd, "virtio"); + + dev = qdev_create(bus, name); + qdev_set_nic_properties(dev, nd); + qdev_init_nofail(dev); + } +} + static void ccw_init(MachineState *machine) { int ret; @@ -167,14 +324,24 @@ static void ccw_init(MachineState *machine) static void s390_cpu_plug(HotplugHandler *hotplug_dev, DeviceState *dev, Error **errp) { - gchar *name; + MachineState *ms = MACHINE(hotplug_dev); S390CPU *cpu = S390_CPU(dev); - CPUState *cs = CPU(dev); - name = g_strdup_printf("cpu[%i]", cpu->env.cpu_num); - object_property_set_link(OBJECT(hotplug_dev), OBJECT(cs), name, - errp); - g_free(name); + g_assert(!ms->possible_cpus->cpus[cpu->env.core_id].cpu); + ms->possible_cpus->cpus[cpu->env.core_id].cpu = OBJECT(dev); +} + +static void s390_machine_reset(void) +{ + S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0)); + + s390_cmma_reset(); + qemu_devices_reset(); + s390_crypto_reset(); + + /* all cpus are stopped - configure and start the ipl cpu only */ + s390_ipl_prepare_cpu(ipl_cpu); + s390_cpu_set_state(CPU_STATE_OPERATING, ipl_cpu); } static void s390_machine_device_plug(HotplugHandler *hotplug_dev, @@ -185,6 +352,45 @@ static void s390_machine_device_plug(HotplugHandler *hotplug_dev, } } +static void s390_machine_device_unplug_request(HotplugHandler *hotplug_dev, + DeviceState *dev, Error **errp) +{ + if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { + error_setg(errp, "CPU hot unplug not supported on this machine"); + return; + } +} + +static CpuInstanceProperties s390_cpu_index_to_props(MachineState *machine, + unsigned cpu_index) +{ + g_assert(machine->possible_cpus && cpu_index < machine->possible_cpus->len); + + return machine->possible_cpus->cpus[cpu_index].props; +} + +static const CPUArchIdList *s390_possible_cpu_arch_ids(MachineState *ms) +{ + int i; + + if (ms->possible_cpus) { + g_assert(ms->possible_cpus && ms->possible_cpus->len == max_cpus); + return ms->possible_cpus; + } + + ms->possible_cpus = g_malloc0(sizeof(CPUArchIdList) + + sizeof(CPUArchId) * max_cpus); + ms->possible_cpus->len = max_cpus; + for (i = 0; i < ms->possible_cpus->len; i++) { + ms->possible_cpus->cpus[i].vcpus_count = 1; + ms->possible_cpus->cpus[i].arch_id = i; + ms->possible_cpus->cpus[i].props.has_core_id = true; + ms->possible_cpus->cpus[i].props.core_id = i; + } + + return ms->possible_cpus; +} + static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, DeviceState *dev) { @@ -197,8 +403,21 @@ static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, static void s390_hot_add_cpu(const int64_t id, Error **errp) { MachineState *machine = MACHINE(qdev_get_machine()); + ObjectClass *oc; + + g_assert(machine->possible_cpus->cpus[0].cpu); + oc = OBJECT_CLASS(CPU_GET_CLASS(machine->possible_cpus->cpus[0].cpu)); - s390x_new_cpu(machine->cpu_model, id, errp); + s390x_new_cpu(object_class_get_name(oc), id, errp); +} + +static void s390_nmi(NMIState *n, int cpu_index, Error **errp) +{ + CPUState *cs = qemu_get_cpu(cpu_index); + + if (s390_cpu_restart(S390_CPU(cs))) { + error_setg(errp, QERR_UNSUPPORTED); + } } static void ccw_machine_class_init(ObjectClass *oc, void *data) @@ -223,8 +442,12 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data) mc->no_sdcard = 1; mc->use_sclp = 1; mc->max_cpus = 248; + mc->has_hotpluggable_cpus = true; mc->get_hotplug_handler = s390_get_hotplug_handler; + mc->cpu_index_to_instance_props = s390_cpu_index_to_props; + mc->possible_cpu_arch_ids = s390_possible_cpu_arch_ids; hc->plug = s390_machine_device_plug; + hc->unplug_request = s390_machine_device_unplug_request; nc->nmi_monitor_handler = s390_nmi; } diff --git a/hw/s390x/s390-virtio-hcall.c b/hw/s390x/s390-virtio-hcall.c index 23d67d6170..ec7cf8beb3 100644 --- a/hw/s390x/s390-virtio-hcall.c +++ b/hw/s390x/s390-virtio-hcall.c @@ -11,7 +11,7 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "hw/s390x/s390-virtio.h" +#include "hw/s390x/s390-virtio-hcall.h" #define MAX_DIAG_SUBCODES 255 diff --git a/hw/s390x/s390-virtio-hcall.h b/hw/s390x/s390-virtio-hcall.h new file mode 100644 index 0000000000..cbc270eef3 --- /dev/null +++ b/hw/s390x/s390-virtio-hcall.h @@ -0,0 +1,21 @@ +/* + * Support for virtio hypercalls on s390x + * + * Copyright 2012 IBM Corp. + * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 or (at + * your option) any later version. See the COPYING file in the top-level + * directory. + */ + +#ifndef HW_S390_VIRTIO_HCALL_H +#define HW_S390_VIRTIO_HCALL_H + +#include "standard-headers/asm-s390/kvm_virtio.h" +#include "standard-headers/asm-s390/virtio-ccw.h" + +typedef int (*s390_virtio_fn)(const uint64_t *args); +void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn); +int s390_virtio_hypercall(CPUS390XState *env); +#endif /* HW_S390_VIRTIO_HCALL_H */ diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c deleted file mode 100644 index 0e91c465f2..0000000000 --- a/hw/s390x/s390-virtio.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * QEMU S390 virtio target - * - * Copyright (c) 2009 Alexander Graf <agraf@suse.de> - * Copyright IBM Corp 2012 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * Contributions after 2012-10-29 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - * - * You should have received a copy of the GNU (Lesser) General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "qapi/qmp/qerror.h" -#include "qemu/error-report.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "sysemu/sysemu.h" -#include "net/net.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "hw/virtio/virtio.h" -#include "exec/address-spaces.h" -#include "sysemu/qtest.h" - -#include "hw/s390x/sclp.h" -#include "hw/s390x/s390_flic.h" -#include "hw/s390x/s390-virtio.h" -#include "hw/s390x/storage-keys.h" -#include "hw/s390x/ipl.h" -#include "cpu.h" - -#define MAX_BLK_DEVS 10 - -#define S390_TOD_CLOCK_VALUE_MISSING 0x00 -#define S390_TOD_CLOCK_VALUE_PRESENT 0x01 - -static S390CPU **cpu_states; - -S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) -{ - if (cpu_addr >= max_cpus) { - return NULL; - } - - /* Fast lookup via CPU ID */ - return cpu_states[cpu_addr]; -} - -void s390_init_ipl_dev(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *firmware, - const char *netboot_fw, - bool enforce_bios) -{ - Object *new = object_new(TYPE_S390_IPL); - DeviceState *dev = DEVICE(new); - - if (kernel_filename) { - qdev_prop_set_string(dev, "kernel", kernel_filename); - } - if (initrd_filename) { - qdev_prop_set_string(dev, "initrd", initrd_filename); - } - qdev_prop_set_string(dev, "cmdline", kernel_cmdline); - qdev_prop_set_string(dev, "firmware", firmware); - qdev_prop_set_string(dev, "netboot_fw", netboot_fw); - qdev_prop_set_bit(dev, "enforce_bios", enforce_bios); - object_property_add_child(qdev_get_machine(), TYPE_S390_IPL, - new, NULL); - object_unref(new); - qdev_init_nofail(dev); -} - -void s390_init_cpus(MachineState *machine) -{ - int i; - gchar *name; - - if (machine->cpu_model == NULL) { - machine->cpu_model = s390_default_cpu_model_name(); - } - - cpu_states = g_new0(S390CPU *, max_cpus); - - for (i = 0; i < max_cpus; i++) { - name = g_strdup_printf("cpu[%i]", i); - object_property_add_link(OBJECT(machine), name, TYPE_S390_CPU, - (Object **) &cpu_states[i], - object_property_allow_set_link, - OBJ_PROP_LINK_UNREF_ON_RELEASE, - &error_abort); - g_free(name); - } - - for (i = 0; i < smp_cpus; i++) { - s390x_new_cpu(machine->cpu_model, i, &error_fatal); - } -} - - -void s390_create_virtio_net(BusState *bus, const char *name) -{ - int i; - - for (i = 0; i < nb_nics; i++) { - NICInfo *nd = &nd_table[i]; - DeviceState *dev; - - if (!nd->model) { - nd->model = g_strdup("virtio"); - } - - qemu_check_nic_model(nd, "virtio"); - - dev = qdev_create(bus, name); - qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); - } -} - -void gtod_save(QEMUFile *f, void *opaque) -{ - uint64_t tod_low; - uint8_t tod_high; - int r; - - r = s390_get_clock(&tod_high, &tod_low); - if (r) { - warn_report("Unable to get guest clock for migration: %s", - strerror(-r)); - error_printf("Guest clock will not be migrated " - "which could cause the guest to hang."); - qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING); - return; - } - - qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT); - qemu_put_byte(f, tod_high); - qemu_put_be64(f, tod_low); -} - -int gtod_load(QEMUFile *f, void *opaque, int version_id) -{ - uint64_t tod_low; - uint8_t tod_high; - int r; - - if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) { - warn_report("Guest clock was not migrated. This could " - "cause the guest to hang."); - return 0; - } - - tod_high = qemu_get_byte(f); - tod_low = qemu_get_be64(f); - - r = s390_set_clock(&tod_high, &tod_low); - if (r) { - warn_report("Unable to set guest clock for migration: %s", - strerror(-r)); - error_printf("Guest clock will not be restored " - "which could cause the guest to hang."); - } - - return 0; -} - -void s390_nmi(NMIState *n, int cpu_index, Error **errp) -{ - CPUState *cs = qemu_get_cpu(cpu_index); - - if (s390_cpu_restart(S390_CPU(cs))) { - error_setg(errp, QERR_UNSUPPORTED); - } -} - -void s390_machine_reset(void) -{ - S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0)); - - s390_cmma_reset(); - qemu_devices_reset(); - s390_crypto_reset(); - - /* all cpus are stopped - configure and start the ipl cpu only */ - s390_ipl_prepare_cpu(ipl_cpu); - s390_cpu_set_state(CPU_STATE_OPERATING, ipl_cpu); -} diff --git a/hw/s390x/s390-virtio.h b/hw/s390x/s390-virtio.h deleted file mode 100644 index ca97fd6814..0000000000 --- a/hw/s390x/s390-virtio.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Virtio interfaces for s390 - * - * Copyright 2012 IBM Corp. - * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or (at - * your option) any later version. See the COPYING file in the top-level - * directory. - */ - -#ifndef HW_S390_VIRTIO_H -#define HW_S390_VIRTIO_H - -#include "hw/nmi.h" -#include "standard-headers/asm-s390/kvm_virtio.h" -#include "standard-headers/asm-s390/virtio-ccw.h" - -typedef int (*s390_virtio_fn)(const uint64_t *args); -void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn); - -void s390_init_cpus(MachineState *machine); -void s390_init_ipl_dev(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *firmware, - const char *netboot_fw, - bool enforce_bios); -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 fd097262c7..30aefbfd15 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -34,16 +34,21 @@ static inline SCLPDevice *get_sclp_device(void) return sclp; } -static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int count) +static void prepare_cpu_entries(SCLPDevice *sclp, CPUEntry *entry, int *count) { + MachineState *ms = MACHINE(qdev_get_machine()); uint8_t features[SCCB_CPU_FEATURE_LEN] = { 0 }; int i; s390_get_feat_block(S390_FEAT_TYPE_SCLP_CPU, features); - for (i = 0; i < count; i++) { - entry[i].address = i; - entry[i].type = 0; - memcpy(entry[i].features, features, sizeof(entry[i].features)); + for (i = 0, *count = 0; i < ms->possible_cpus->len; i++) { + if (!ms->possible_cpus->cpus[i].cpu) { + continue; + } + entry[*count].address = ms->possible_cpus->cpus[i].arch_id; + entry[*count].type = 0; + memcpy(entry[*count].features, features, sizeof(features)); + (*count)++; } } @@ -53,17 +58,13 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) ReadInfo *read_info = (ReadInfo *) sccb; MachineState *machine = MACHINE(qdev_get_machine()); sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - CPUState *cpu; - int cpu_count = 0; + int cpu_count; int rnsize, rnmax; int slots = MIN(machine->ram_slots, s390_get_memslot_count()); IplParameterBlock *ipib = s390_ipl_get_iplb(); - CPU_FOREACH(cpu) { - cpu_count++; - } - /* CPU information */ + prepare_cpu_entries(sclp, read_info->entries, &cpu_count); read_info->entries_cpu = cpu_to_be16(cpu_count); read_info->offset_cpu = cpu_to_be16(offsetof(ReadInfo, entries)); read_info->highest_cpu = cpu_to_be16(max_cpus); @@ -76,8 +77,6 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT, read_info->conf_char_ext); - prepare_cpu_entries(sclp, read_info->entries, cpu_count); - read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO | SCLP_HAS_IOA_RECONFIG); @@ -333,13 +332,9 @@ static void unassign_storage(SCLPDevice *sclp, SCCB *sccb) static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb) { ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb; - CPUState *cpu; - int cpu_count = 0; - - CPU_FOREACH(cpu) { - cpu_count++; - } + int cpu_count; + prepare_cpu_entries(sclp, cpu_info->entries, &cpu_count); cpu_info->nr_configured = cpu_to_be16(cpu_count); cpu_info->offset_configured = cpu_to_be16(offsetof(ReadCpuInfo, entries)); cpu_info->nr_standby = cpu_to_be16(0); @@ -348,7 +343,6 @@ static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb) cpu_info->offset_standby = cpu_to_be16(cpu_info->offset_configured + cpu_info->nr_configured*sizeof(CPUEntry)); - prepare_cpu_entries(sclp, cpu_info->entries, cpu_count); sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); } diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index b1976fdd19..ff1bb1534c 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -487,7 +487,6 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EFAULT; } else { virtio_bus_get_vdev_config(&dev->bus, vdev->config); - /* XXX config space endianness */ cpu_physical_memory_write(ccw.cda, vdev->config, len); sch->curr_status.scsw.count = ccw.count - len; ret = 0; @@ -510,7 +509,6 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EFAULT; } else { len = hw_len; - /* XXX config space endianness */ memcpy(vdev->config, config, len); cpu_physical_memory_unmap(config, hw_len, 0, hw_len); virtio_bus_set_vdev_config(&dev->bus, vdev->config); @@ -1007,6 +1005,15 @@ static void virtio_ccw_crypto_realize(VirtioCcwDevice *ccw_dev, Error **errp) NULL); } +static void virtio_ccw_gpu_realize(VirtioCcwDevice *ccw_dev, Error **errp) +{ + VirtIOGPUCcw *dev = VIRTIO_GPU_CCW(ccw_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + /* DeviceState to VirtioCcwDevice. Note: used on datapath, * be careful and test performance if you change this. */ @@ -1616,6 +1623,45 @@ static const TypeInfo virtio_ccw_crypto = { .class_init = virtio_ccw_crypto_class_init, }; +static Property virtio_ccw_gpu_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, + VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, + VIRTIO_CCW_MAX_REV), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_ccw_gpu_instance_init(Object *obj) +{ + VirtIOGPUCcw *dev = VIRTIO_GPU_CCW(obj); + VirtioCcwDevice *ccw_dev = VIRTIO_CCW_DEVICE(obj); + + ccw_dev->force_revision_1 = true; + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_GPU); +} + +static void virtio_ccw_gpu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); + + k->realize = virtio_ccw_gpu_realize; + k->exit = virtio_ccw_exit; + dc->reset = virtio_ccw_reset; + dc->props = virtio_ccw_gpu_properties; + dc->hotpluggable = false; + set_bit(DEVICE_CATEGORY_DISPLAY, dc->categories); +} + +static const TypeInfo virtio_ccw_gpu = { + .name = TYPE_VIRTIO_GPU_CCW, + .parent = TYPE_VIRTIO_CCW_DEVICE, + .instance_size = sizeof(VirtIOGPUCcw), + .instance_init = virtio_ccw_gpu_instance_init, + .class_init = virtio_ccw_gpu_class_init, +}; + static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp) { VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; @@ -1815,6 +1861,7 @@ static void virtio_ccw_register(void) type_register_static(&vhost_vsock_ccw_info); #endif type_register_static(&virtio_ccw_crypto); + type_register_static(&virtio_ccw_gpu); } type_init(virtio_ccw_register) diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 41d4010378..541fdd2994 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -27,6 +27,7 @@ #ifdef CONFIG_VHOST_VSOCK #include "hw/virtio/vhost-vsock.h" #endif /* CONFIG_VHOST_VSOCK */ +#include "hw/virtio/virtio-gpu.h" #include "hw/s390x/s390_flic.h" #include "hw/s390x/css.h" @@ -223,4 +224,13 @@ typedef struct VHostVSockCCWState { #endif /* CONFIG_VHOST_VSOCK */ +#define TYPE_VIRTIO_GPU_CCW "virtio-gpu-ccw" +#define VIRTIO_GPU_CCW(obj) \ + OBJECT_CHECK(VirtIOGPUCcw, (obj), TYPE_VIRTIO_GPU_CCW) + +typedef struct VirtIOGPUCcw { + VirtioCcwDevice parent_obj; + VirtIOGPU vdev; +} VirtIOGPUCcw; + #endif diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h index 41a9d2862b..a9a90c2022 100644 --- a/include/hw/s390x/s390-virtio-ccw.h +++ b/include/hw/s390x/s390-virtio-ccw.h @@ -56,4 +56,6 @@ bool gs_allowed(void); */ bool css_migration_enabled(void); +void subsystem_reset(void); + #endif diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index a72d096081..847ff32f85 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -16,6 +16,7 @@ #include "hw/sysbus.h" #include "hw/qdev.h" +#include "target/s390x/cpu-qom.h" #define SCLP_CMD_CODE_MASK 0xffff00ff @@ -242,5 +243,6 @@ sclpMemoryHotplugDev *init_sclp_memory_hotplug_dev(void); sclpMemoryHotplugDev *get_sclp_memory_hotplug_dev(void); void sclp_service_interrupt(uint32_t sccb); void raise_irq_cpu_hotplug(void); +int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code); #endif diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 995a7beeb5..0dc767a753 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -388,10 +388,10 @@ struct CPUState { DECLARE_BITMAP(trace_dstate, CPU_TRACE_DSTATE_MAX_EVENTS); /* TODO Move common fields from CPUArchState here. */ - int cpu_index; /* used by alpha TCG */ - uint32_t halted; /* used by alpha, cris, ppc TCG */ + int cpu_index; + uint32_t halted; uint32_t can_do_io; - int32_t exception_index; /* used by m68k TCG */ + int32_t exception_index; /* shared by kvm, hax and hvf */ bool vcpu_dirty; diff --git a/pc-bios/s390-ccw/netboot.mak b/pc-bios/s390-ccw/netboot.mak index a9e1374e97..a25d238144 100644 --- a/pc-bios/s390-ccw/netboot.mak +++ b/pc-bios/s390-ccw/netboot.mak @@ -50,7 +50,7 @@ libc.a: $(LIBCOBJS) LIBNETOBJS := args.o dhcp.o dns.o icmpv6.o ipv6.o tcp.o udp.o bootp.o \ dhcpv6.o ethernet.o ipv4.o ndp.o tftp.o -LIBNETCFLAGS := $(QEMU_CFLAGS) $(LIBC_INC) $(LIBNET_INC) +LIBNETCFLAGS := $(QEMU_CFLAGS) -DDHCPARCH=0x1F $(LIBC_INC) $(LIBNET_INC) %.o : $(SLOF_DIR)/lib/libnet/%.c $(call quiet-command,$(CC) $(LIBNETCFLAGS) -c -o $@ $<,"CC","$(TARGET_DIR)$@") diff --git a/qapi-schema.json b/qapi-schema.json index cdff39a456..a3ba1c9a1c 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3153,6 +3153,22 @@ # } # ]} # +# For s390x-virtio-ccw machine type started with -smp 1,maxcpus=2 -cpu qemu +# (Since: 2.11): +# +# -> { "execute": "query-hotpluggable-cpus" } +# <- {"return": [ +# { +# "type": "qemu-s390-cpu", "vcpus-count": 1, +# "props": { "core-id": 1 } +# }, +# { +# "qom-path": "/machine/unattached/device[0]", +# "type": "qemu-s390-cpu", "vcpus-count": 1, +# "props": { "core-id": 0 } +# } +# ]} +# ## { 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'] } diff --git a/target/i386/arch_dump.c b/target/i386/arch_dump.c index e682904052..35b55fc200 100644 --- a/target/i386/arch_dump.c +++ b/target/i386/arch_dump.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/cpu-all.h" #include "sysemu/dump.h" #include "elf.h" #include "sysemu/memory_mapping.h" diff --git a/target/i386/arch_memory_mapping.c b/target/i386/arch_memory_mapping.c index 647cff2829..271cb5e41b 100644 --- a/target/i386/arch_memory_mapping.c +++ b/target/i386/arch_memory_mapping.c @@ -13,7 +13,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/cpu-all.h" #include "sysemu/memory_mapping.h" /* PAE Paging or IA-32e Paging */ diff --git a/target/i386/svm_helper.c b/target/i386/svm_helper.c index 59e8b5091c..f479239875 100644 --- a/target/i386/svm_helper.c +++ b/target/i386/svm_helper.c @@ -19,7 +19,6 @@ #include "qemu/osdep.h" #include "cpu.h" -#include "exec/cpu-all.h" #include "exec/helper-proto.h" #include "exec/exec-all.h" #include "exec/cpu_ldst.h" diff --git a/target/ppc/arch_dump.c b/target/ppc/arch_dump.c index 95b9ab6f29..351a65b22f 100644 --- a/target/ppc/arch_dump.c +++ b/target/ppc/arch_dump.c @@ -15,7 +15,6 @@ #include "qemu/osdep.h" #include "cpu.h" #include "elf.h" -#include "exec/cpu-all.h" #include "sysemu/dump.h" #include "sysemu/kvm.h" diff --git a/target/s390x/arch_dump.c b/target/s390x/arch_dump.c index 9b0bf92698..6f61ff95af 100644 --- a/target/s390x/arch_dump.c +++ b/target/s390x/arch_dump.c @@ -15,7 +15,6 @@ #include "cpu.h" #include "internal.h" #include "elf.h" -#include "exec/cpu-all.h" #include "sysemu/dump.h" diff --git a/target/s390x/cpu-qom.h b/target/s390x/cpu-qom.h index 4e936e7788..2e446fab51 100644 --- a/target/s390x/cpu-qom.h +++ b/target/s390x/cpu-qom.h @@ -21,7 +21,6 @@ #define QEMU_S390_CPU_QOM_H #include "qom/cpu.h" -#include "cpu_models.h" #define TYPE_S390_CPU "s390-cpu" @@ -32,6 +31,9 @@ #define S390_CPU_GET_CLASS(obj) \ OBJECT_GET_CLASS(S390CPUClass, (obj), TYPE_S390_CPU) +typedef struct S390CPUModel S390CPUModel; +typedef struct S390CPUDef S390CPUDef; + /** * S390CPUClass: * @parent_realize: The parent class' realize handler. @@ -52,7 +54,7 @@ typedef struct S390CPUClass { bool is_migration_safe; const char *desc; - int64_t next_cpu_id; + uint32_t next_core_id; DeviceRealize parent_realize; void (*parent_reset)(CPUState *cpu); @@ -62,5 +64,6 @@ typedef struct S390CPUClass { } S390CPUClass; typedef struct S390CPU S390CPU; +typedef struct CPUS390XState CPUS390XState; #endif diff --git a/target/s390x/cpu.c b/target/s390x/cpu.c index 74b3e4fd0d..34538c3ab9 100644 --- a/target/s390x/cpu.c +++ b/target/s390x/cpu.c @@ -36,6 +36,7 @@ #include "trace.h" #include "qapi/visitor.h" #include "exec/exec-all.h" +#include "hw/qdev-properties.h" #ifndef CONFIG_USER_ONLY #include "hw/hw.h" #include "sysemu/arch_init.h" @@ -189,34 +190,34 @@ static void s390_cpu_realizefn(DeviceState *dev, Error **errp) } #if !defined(CONFIG_USER_ONLY) - if (cpu->id >= max_cpus) { - error_setg(&err, "Unable to add CPU: %" PRIi64 - ", max allowed: %d", cpu->id, max_cpus - 1); + if (cpu->env.core_id >= max_cpus) { + error_setg(&err, "Unable to add CPU with core-id: %" PRIu32 + ", maximum core-id: %d", cpu->env.core_id, + max_cpus - 1); goto out; } +#else + /* implicitly set for linux-user only */ + cpu->env.core_id = scc->next_core_id; + scc->next_core_id++; #endif - if (cpu_exists(cpu->id)) { - error_setg(&err, "Unable to add CPU: %" PRIi64 - ", it already exists", cpu->id); - goto out; - } - if (cpu->id != scc->next_cpu_id) { - error_setg(&err, "Unable to add CPU: %" PRIi64 - ", The next available id is %" PRIi64, cpu->id, - scc->next_cpu_id); + + if (cpu_exists(cpu->env.core_id)) { + error_setg(&err, "Unable to add CPU with core-id: %" PRIu32 + ", it already exists", cpu->env.core_id); goto out; } + /* sync cs->cpu_index and env->core_id. The latter is needed for TCG. */ + cs->cpu_index = env->core_id; cpu_exec_realizefn(cs, &err); if (err != NULL) { goto out; } - scc->next_cpu_id++; #if !defined(CONFIG_USER_ONLY) qemu_register_reset(s390_cpu_machine_reset_cb, cpu); #endif - env->cpu_num = cpu->id; s390_cpu_gdb_init(cs); qemu_init_vcpu(cs); #if !defined(CONFIG_USER_ONLY) @@ -237,45 +238,6 @@ out: error_propagate(errp, err); } -static void s390x_cpu_get_id(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - S390CPU *cpu = S390_CPU(obj); - int64_t value = cpu->id; - - visit_type_int(v, name, &value, errp); -} - -static void s390x_cpu_set_id(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) -{ - S390CPU *cpu = S390_CPU(obj); - DeviceState *dev = DEVICE(obj); - const int64_t min = 0; - const int64_t max = UINT32_MAX; - Error *err = NULL; - int64_t value; - - if (dev->realized) { - error_setg(errp, "Attempt to set property '%s' on '%s' after " - "it was realized", name, object_get_typename(obj)); - return; - } - - visit_type_int(v, name, &value, &err); - if (err) { - error_propagate(errp, err); - return; - } - if (value < min || value > max) { - error_setg(errp, "Property %s.%s doesn't take value %" PRId64 - " (minimum: %" PRId64 ", maximum: %" PRId64 ")" , - object_get_typename(obj), name, value, min, max); - return; - } - cpu->id = value; -} - static void s390_cpu_initfn(Object *obj) { CPUState *cs = CPU(obj); @@ -289,8 +251,6 @@ static void s390_cpu_initfn(Object *obj) cs->env_ptr = env; cs->halted = 1; cs->exception_index = EXCP_HLT; - object_property_add(OBJECT(cpu), "id", "int64_t", s390x_cpu_get_id, - s390x_cpu_set_id, NULL, NULL, NULL); s390_cpu_model_register_props(obj); #if !defined(CONFIG_USER_ONLY) qemu_get_timedate(&tm, 0); @@ -306,13 +266,6 @@ static void s390_cpu_initfn(Object *obj) inited = true; s390x_translate_init(); } - -#if defined(CONFIG_USER_ONLY) - { - S390CPUClass *scc = S390_CPU_GET_CLASS(obj); - cpu->id = scc->next_cpu_id; - } -#endif } static void s390_cpu_finalize(Object *obj) @@ -494,15 +447,21 @@ static gchar *s390_gdb_arch_name(CPUState *cs) return g_strdup("s390:64-bit"); } +static Property s390x_cpu_properties[] = { + DEFINE_PROP_UINT32("core-id", S390CPU, env.core_id, 0), + DEFINE_PROP_END_OF_LIST() +}; + static void s390_cpu_class_init(ObjectClass *oc, void *data) { S390CPUClass *scc = S390_CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(scc); DeviceClass *dc = DEVICE_CLASS(oc); - scc->next_cpu_id = 0; scc->parent_realize = dc->realize; dc->realize = s390_cpu_realizefn; + dc->props = s390x_cpu_properties; + dc->user_creatable = true; scc->parent_reset = cc->reset; #if !defined(CONFIG_USER_ONLY) diff --git a/target/s390x/cpu.h b/target/s390x/cpu.h index 0bd97a5670..9b549dc491 100644 --- a/target/s390x/cpu.h +++ b/target/s390x/cpu.h @@ -25,6 +25,7 @@ #include "qemu-common.h" #include "cpu-qom.h" +#include "cpu_models.h" #define TARGET_LONG_BITS 64 @@ -80,7 +81,7 @@ typedef struct MchkQueue { uint16_t type; } MchkQueue; -typedef struct CPUS390XState { +struct CPUS390XState { uint64_t regs[16]; /* GP registers */ /* * The floating point registers are part of the vector registers. @@ -149,7 +150,7 @@ typedef struct CPUS390XState { CPU_COMMON - uint32_t cpu_num; + uint32_t core_id; /* PoP "CPU address", same as cpu_index */ uint64_t cpuid; uint64_t tod_offset; @@ -174,7 +175,7 @@ typedef struct CPUS390XState { /* currently processed sigp order */ uint8_t sigp_order; -} CPUS390XState; +}; static inline CPU_DoubleU *get_freg(CPUS390XState *cs, int nr) { @@ -193,7 +194,6 @@ struct S390CPU { /*< public >*/ CPUS390XState env; - int64_t id; S390CPUModel *model; /* needed for live migration */ void *irqstate; @@ -689,7 +689,7 @@ const char *s390_default_cpu_model_name(void); /* helper.c */ #define cpu_init(cpu_model) cpu_generic_init(TYPE_S390_CPU, cpu_model) -S390CPU *s390x_new_cpu(const char *cpu_model, int64_t id, Error **errp); +S390CPU *s390x_new_cpu(const char *typename, uint32_t core_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. */ @@ -721,8 +721,5 @@ int s390_cpu_virt_mem_rw(S390CPU *cpu, vaddr laddr, uint8_t ar, void *hostbuf, /* 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 18cbf91d9c..5169379db5 100644 --- a/target/s390x/cpu_models.c +++ b/target/s390x/cpu_models.c @@ -196,6 +196,9 @@ bool s390_has_feat(S390Feat feat) } } #endif + if (feat == S390_FEAT_ZPCI) { + return true; + } return 0; } return test_bit(feat, cpu->model->features); @@ -270,16 +273,11 @@ const S390CPUDef *s390_find_cpu_def(uint16_t type, uint8_t gen, uint8_t ec_ga, return last_compatible; } -struct S390PrintCpuListInfo { - FILE *f; - fprintf_function print; -}; - -static void print_cpu_model_list(ObjectClass *klass, void *opaque) +static void s390_print_cpu_model_list_entry(gpointer data, gpointer user_data) { - struct S390PrintCpuListInfo *info = opaque; - S390CPUClass *scc = S390_CPU_CLASS(klass); - char *name = g_strdup(object_class_get_name(klass)); + CPUListState *s = user_data; + const S390CPUClass *scc = S390_CPU_CLASS((ObjectClass *)data); + char *name = g_strdup(object_class_get_name((ObjectClass *)data)); const char *details = ""; if (scc->is_static) { @@ -290,21 +288,52 @@ static void print_cpu_model_list(ObjectClass *klass, void *opaque) /* strip off the -s390-cpu */ g_strrstr(name, "-" TYPE_S390_CPU)[0] = 0; - (*info->print)(info->f, "s390 %-15s %-35s %s\n", name, scc->desc, - details); + (*s->cpu_fprintf)(s->file, "s390 %-15s %-35s %s\n", name, scc->desc, + details); g_free(name); } +static gint s390_cpu_list_compare(gconstpointer a, gconstpointer b) +{ + const S390CPUClass *cc_a = S390_CPU_CLASS((ObjectClass *)a); + const S390CPUClass *cc_b = S390_CPU_CLASS((ObjectClass *)b); + const char *name_a = object_class_get_name((ObjectClass *)a); + const char *name_b = object_class_get_name((ObjectClass *)b); + + /* move qemu and host to the top of the list, qemu first, host second */ + if (name_a[0] == 'q') { + return -1; + } else if (name_b[0] == 'q') { + return 1; + } else if (name_a[0] == 'h') { + return -1; + } else if (name_b[0] == 'h') { + return 1; + } + + /* keep the same order we have in our table (sorted by release date) */ + if (cc_a->cpu_def != cc_b->cpu_def) { + return cc_a->cpu_def - cc_b->cpu_def; + } + + /* exact same definition - list base model first */ + return cc_a->is_static ? -1 : 1; +} + void s390_cpu_list(FILE *f, fprintf_function print) { - struct S390PrintCpuListInfo info = { - .f = f, - .print = print, + CPUListState s = { + .file = f, + .cpu_fprintf = print, }; S390FeatGroup group; S390Feat feat; + GSList *list; - object_class_foreach(print_cpu_model_list, TYPE_S390_CPU, false, &info); + list = object_class_get_list(TYPE_S390_CPU, false); + list = g_slist_sort(list, s390_cpu_list_compare); + g_slist_foreach(list, s390_print_cpu_model_list_entry, &s); + g_slist_free(list); (*print)(f, "\nRecognized feature flags:\n"); for (feat = 0; feat < S390_FEAT_MAX; feat++) { @@ -915,7 +944,7 @@ void s390_realize_cpu_model(CPUState *cs, Error **errp) cpu->env.cpuid = s390_cpuid_from_cpu_model(cpu->model); if (tcg_enabled()) { /* basic mode, write the cpu address into the first 4 bit of the ID */ - cpu->env.cpuid = deposit64(cpu->env.cpuid, 54, 4, cpu->env.cpu_num); + cpu->env.cpuid = deposit64(cpu->env.cpuid, 54, 4, cpu->env.core_id); } } diff --git a/target/s390x/cpu_models.h b/target/s390x/cpu_models.h index c0bee15d7a..4c6dee1871 100644 --- a/target/s390x/cpu_models.h +++ b/target/s390x/cpu_models.h @@ -17,7 +17,7 @@ #include "qom/cpu.h" /* static CPU definition */ -typedef struct S390CPUDef { +struct S390CPUDef { const char *name; /* name exposed to the user */ const char *desc; /* description exposed to the user */ uint8_t gen; /* hw generation identification */ @@ -37,10 +37,10 @@ typedef struct S390CPUDef { S390FeatBitmap full_feat; /* used to init full_feat from generated data */ S390FeatInit full_init; -} S390CPUDef; +}; /* CPU model based on a CPU definition */ -typedef struct S390CPUModel { +struct S390CPUModel { const S390CPUDef *def; S390FeatBitmap features; /* values copied from the "host" model, can change during migration */ @@ -48,7 +48,7 @@ typedef struct S390CPUModel { uint32_t cpu_id; /* CPU id */ uint8_t cpu_id_format; /* CPU id format bit */ uint8_t cpu_ver; /* CPU version, usually "ff" for kvm */ -} S390CPUModel; +}; /* * CPU ID diff --git a/target/s390x/diag.c b/target/s390x/diag.c index e6b5e6de37..82a623948d 100644 --- a/target/s390x/diag.c +++ b/target/s390x/diag.c @@ -20,6 +20,7 @@ #include "hw/watchdog/wdt_diag288.h" #include "sysemu/cpus.h" #include "hw/s390x/ipl.h" +#include "hw/s390x/s390-virtio-ccw.h" static int modified_clear_reset(S390CPU *cpu) { diff --git a/target/s390x/excp_helper.c b/target/s390x/excp_helper.c index 361f970db3..470cf8f5bc 100644 --- a/target/s390x/excp_helper.c +++ b/target/s390x/excp_helper.c @@ -59,8 +59,7 @@ int s390_cpu_handle_mmu_fault(CPUState *cs, vaddr address, { S390CPU *cpu = S390_CPU(cs); - cs->exception_index = EXCP_PGM; - cpu->env.int_pgm_code = PGM_ADDRESSING; + trigger_pgm_exception(&cpu->env, PGM_ADDRESSING, ILEN_AUTO); /* On real machines this value is dropped into LowMem. Since this is userland, simply put this someplace that cpu_loop can find it. */ cpu->env.__excp_addr = address; @@ -251,7 +250,7 @@ static void do_ext_interrupt(CPUS390XState *env) lowcore->ext_params2 = cpu_to_be64(q->param64); lowcore->external_old_psw.mask = cpu_to_be64(get_psw_mask(env)); lowcore->external_old_psw.addr = cpu_to_be64(env->psw.addr); - lowcore->cpu_addr = cpu_to_be16(env->cpu_num | VIRTIO_SUBCODE_64); + lowcore->cpu_addr = cpu_to_be16(env->core_id | VIRTIO_SUBCODE_64); mask = be64_to_cpu(lowcore->external_new_psw.mask); addr = be64_to_cpu(lowcore->external_new_psw.addr); diff --git a/target/s390x/helper.c b/target/s390x/helper.c index ba29504476..97adbcc86d 100644 --- a/target/s390x/helper.c +++ b/target/s390x/helper.c @@ -68,53 +68,12 @@ void s390x_cpu_timer(void *opaque) } #endif -S390CPU *cpu_s390x_create(const char *cpu_model, Error **errp) +S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, Error **errp) { - static bool features_parsed; - char *name, *features; - const char *typename; - ObjectClass *oc; - CPUClass *cc; - - name = g_strdup(cpu_model); - features = strchr(name, ','); - if (features) { - features[0] = 0; - features++; - } - - oc = cpu_class_by_name(TYPE_S390_CPU, name); - if (!oc) { - error_setg(errp, "Unknown CPU definition \'%s\'", name); - g_free(name); - return NULL; - } - typename = object_class_get_name(oc); - - if (!features_parsed) { - features_parsed = true; - cc = CPU_CLASS(oc); - cc->parse_features(typename, features, errp); - } - g_free(name); - - if (*errp) { - return NULL; - } - return S390_CPU(CPU(object_new(typename))); -} - -S390CPU *s390x_new_cpu(const char *cpu_model, int64_t id, Error **errp) -{ - S390CPU *cpu; + S390CPU *cpu = S390_CPU(object_new(typename)); Error *err = NULL; - cpu = cpu_s390x_create(cpu_model, &err); - if (err != NULL) { - goto out; - } - - object_property_set_int(OBJECT(cpu), id, "id", &err); + object_property_set_int(OBJECT(cpu), core_id, "core-id", &err); if (err != NULL) { goto out; } diff --git a/target/s390x/internal.h b/target/s390x/internal.h index b4d3583b24..bc8f83129a 100644 --- a/target/s390x/internal.h +++ b/target/s390x/internal.h @@ -337,7 +337,6 @@ 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); diff --git a/target/s390x/kvm.c b/target/s390x/kvm.c index ad7ce9fc70..720cb1d833 100644 --- a/target/s390x/kvm.c +++ b/target/s390x/kvm.c @@ -48,6 +48,7 @@ #include "hw/s390x/ebcdic.h" #include "exec/memattrs.h" #include "hw/s390x/s390-virtio-ccw.h" +#include "hw/s390x/s390-virtio-hcall.h" #ifndef DEBUG_KVM #define DEBUG_KVM 0 @@ -2423,23 +2424,25 @@ int kvm_arch_fixup_msi_route(struct kvm_irq_routing_entry *route, uint64_t address, uint32_t data, PCIDevice *dev) { S390PCIBusDevice *pbdev; - uint32_t idx = data >> ZPCI_MSI_VEC_BITS; uint32_t vec = data & ZPCI_MSI_VEC_MASK; - pbdev = s390_pci_find_dev_by_idx(s390_get_phb(), idx); - if (!pbdev) { - DPRINTF("add_msi_route no dev\n"); + if (!dev) { + DPRINTF("add_msi_route no pci device\n"); return -ENODEV; } - pbdev->routes.adapter.ind_offset = vec; + pbdev = s390_pci_find_dev_by_target(s390_get_phb(), DEVICE(dev)->id); + if (!pbdev) { + DPRINTF("add_msi_route no zpci device\n"); + return -ENODEV; + } route->type = KVM_IRQ_ROUTING_S390_ADAPTER; route->flags = 0; route->u.adapter.summary_addr = pbdev->routes.adapter.summary_addr; route->u.adapter.ind_addr = pbdev->routes.adapter.ind_addr; route->u.adapter.summary_offset = pbdev->routes.adapter.summary_offset; - route->u.adapter.ind_offset = pbdev->routes.adapter.ind_offset; + route->u.adapter.ind_offset = pbdev->routes.adapter.ind_offset + vec; route->u.adapter.adapter_id = pbdev->routes.adapter.adapter_id; return 0; } diff --git a/target/s390x/misc_helper.c b/target/s390x/misc_helper.c index 50cc046ca2..293fc8428a 100644 --- a/target/s390x/misc_helper.c +++ b/target/s390x/misc_helper.c @@ -34,6 +34,8 @@ #include "sysemu/cpus.h" #include "sysemu/sysemu.h" #include "hw/s390x/ebcdic.h" +#include "hw/s390x/s390-virtio-hcall.h" +#include "hw/s390x/sclp.h" #endif /* #define DEBUG_HELPER */ @@ -230,7 +232,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, /* XXX make different for different CPUs? */ ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); ebcdic_put(sysib.plant, "QEMU", 4); - stw_p(&sysib.cpu_addr, env->cpu_num); + stw_p(&sysib.cpu_addr, env->core_id); cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); } else if ((sel1 == 2) && (sel2 == 2)) { /* Basic Machine CPUs */ @@ -258,7 +260,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, /* XXX make different for different CPUs? */ ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); ebcdic_put(sysib.plant, "QEMU", 4); - stw_p(&sysib.cpu_addr, env->cpu_num); + stw_p(&sysib.cpu_addr, env->core_id); stw_p(&sysib.cpu_id, 0); cpu_physical_memory_write(a0, &sysib, sizeof(sysib)); } else if ((sel1 == 2) && (sel2 == 2)) { @@ -445,14 +447,17 @@ void HELPER(chsc)(CPUS390XState *env, uint64_t inst) #ifndef CONFIG_USER_ONLY void HELPER(per_check_exception)(CPUS390XState *env) { - CPUState *cs = CPU(s390_env_get_cpu(env)); + uint32_t ilen; if (env->per_perc_atmid) { - env->int_pgm_code = PGM_PER; - env->int_pgm_ilen = get_ilen(cpu_ldub_code(env, env->per_address)); - - cs->exception_index = EXCP_PGM; - cpu_loop_exit(cs); + /* + * FIXME: ILEN_AUTO is most probably the right thing to use. ilen + * always has to match the instruction referenced in the PSW. E.g. + * if a PER interrupt is triggered via EXECUTE, we have to use ilen + * of EXECUTE, while per_address contains the target of EXECUTE. + */ + ilen = get_ilen(cpu_ldub_code(env, env->per_address)); + program_interrupt(env, PGM_PER, ilen); } } diff --git a/target/s390x/translate.c b/target/s390x/translate.c index 909b12818d..5abd34fb34 100644 --- a/target/s390x/translate.c +++ b/target/s390x/translate.c @@ -3823,10 +3823,7 @@ static ExitStatus op_ssm(DisasContext *s, DisasOps *o) static ExitStatus op_stap(DisasContext *s, DisasOps *o) { check_privileged(s); - /* ??? Surely cpu address != cpu number. In any case the previous - version of this stored more than the required half-word, so it - is unlikely this has ever been tested. */ - tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, cpu_num)); + tcg_gen_ld32u_i64(o->out, cpu_env, offsetof(CPUS390XState, core_id)); return NO_EXIT; } diff --git a/tests/Makefile.include b/tests/Makefile.include index d680cda833..abc6707ef2 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -366,6 +366,7 @@ 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-s390x-y += tests/drive_del-test$(EXESUF) check-qtest-generic-y += tests/qom-test$(EXESUF) check-qtest-generic-y += tests/test-hmp$(EXESUF) @@ -766,7 +767,7 @@ tests/display-vga-test$(EXESUF): tests/display-vga-test.o tests/ipoctal232-test$(EXESUF): tests/ipoctal232-test.o tests/qom-test$(EXESUF): tests/qom-test.o tests/test-hmp$(EXESUF): tests/test-hmp.o -tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-pc-obj-y) +tests/drive_del-test$(EXESUF): tests/drive_del-test.o $(libqos-virtio-obj-y) tests/qdev-monitor-test$(EXESUF): tests/qdev-monitor-test.o $(libqos-pc-obj-y) tests/nvme-test$(EXESUF): tests/nvme-test.o tests/pvpanic-test$(EXESUF): tests/pvpanic-test.o diff --git a/tests/drive_del-test.c b/tests/drive_del-test.c index 2175139abb..c9ac997555 100644 --- a/tests/drive_del-test.c +++ b/tests/drive_del-test.c @@ -12,6 +12,7 @@ #include "qemu/osdep.h" #include "libqtest.h" +#include "libqos/virtio.h" static void drive_add(void) { @@ -65,14 +66,14 @@ static void test_after_failed_device_add(void) qtest_start("-drive if=none,id=drive0"); - /* Make device_add fail. If this leaks the virtio-blk-pci device then a + /* Make device_add fail. If this leaks the virtio-blk device then a * reference to drive0 will also be held (via qdev properties). */ response = qmp("{'execute': 'device_add'," " 'arguments': {" - " 'driver': 'virtio-blk-pci'," + " 'driver': 'virtio-blk-%s'," " 'drive': 'drive0'" - "}}"); + "}}", qvirtio_get_dev_type()); g_assert(response); error = qdict_get_qdict(response, "error"); g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, "GenericError"); @@ -82,7 +83,7 @@ static void test_after_failed_device_add(void) drive_del(); /* Try to re-add the drive. This fails with duplicate IDs if a leaked - * virtio-blk-pci exists that holds a reference to the old drive0. + * virtio-blk device exists that holds a reference to the old drive0. */ drive_add(); @@ -91,10 +92,14 @@ static void test_after_failed_device_add(void) static void test_drive_del_device_del(void) { + char *args; + /* Start with a drive used by a device that unplugs instantaneously */ - qtest_start("-drive if=none,id=drive0,file=null-co://,format=raw" - " -device virtio-scsi-pci" - " -device scsi-hd,drive=drive0,id=dev0"); + args = g_strdup_printf("-drive if=none,id=drive0,file=null-co://,format=raw" + " -device virtio-scsi-%s" + " -device scsi-hd,drive=drive0,id=dev0", + qvirtio_get_dev_type()); + qtest_start(args); /* * Delete the drive, and then the device @@ -104,6 +109,7 @@ static void test_drive_del_device_del(void) device_del(); qtest_end(); + g_free(args); } int main(int argc, char **argv) @@ -114,9 +120,10 @@ int main(int argc, char **argv) qtest_add_func("/drive_del/without-dev", test_drive_without_dev); - /* TODO I guess any arch with PCI would do */ + /* TODO I guess any arch with a hot-pluggable virtio bus would do */ if (!strcmp(arch, "i386") || !strcmp(arch, "x86_64") || - !strcmp(arch, "ppc") || !strcmp(arch, "ppc64")) { + !strcmp(arch, "ppc") || !strcmp(arch, "ppc64") || + !strcmp(arch, "s390x")) { qtest_add_func("/drive_del/after_failed_device_add", test_after_failed_device_add); qtest_add_func("/blockdev/drive_del_device_del", diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c index 9880a6964e..0879a621c8 100644 --- a/tests/libqos/virtio.c +++ b/tests/libqos/virtio.c @@ -339,3 +339,20 @@ void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx) /* vq->avail->used_event */ writew(vq->avail + 4 + (2 * vq->size), idx); } + +/* + * qvirtio_get_dev_type: + * Returns: the preferred virtio bus/device type for the current architecture. + */ +const char *qvirtio_get_dev_type(void) +{ + const char *arch = qtest_get_arch(); + + if (g_str_equal(arch, "arm") || g_str_equal(arch, "aarch64")) { + return "device"; /* for virtio-mmio */ + } else if (g_str_equal(arch, "s390x")) { + return "ccw"; + } else { + return "pci"; + } +} diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h index 8fbcd1869c..0a04740adf 100644 --- a/tests/libqos/virtio.h +++ b/tests/libqos/virtio.h @@ -143,4 +143,7 @@ void qvirtqueue_kick(QVirtioDevice *d, QVirtQueue *vq, uint32_t free_head); bool qvirtqueue_get_buf(QVirtQueue *vq, uint32_t *desc_idx); void qvirtqueue_set_used_event(QVirtQueue *vq, uint16_t idx); + +const char *qvirtio_get_dev_type(void); + #endif |