diff --git a/configure b/configure index 21c4089c5c79be30cdb49d8dc91ab6263a27a7fa..d854936682abb15625ada25fd013cd225ce4cf31 100755 --- a/configure +++ b/configure @@ -5392,7 +5392,7 @@ case "$target_name" in echo "TARGET_ABI32=y" >> $config_target_mak ;; s390x) - gdb_xml_files="s390x-core64.xml s390-acr.xml s390-fpr.xml s390-vx.xml" + gdb_xml_files="s390x-core64.xml s390-acr.xml s390-fpr.xml s390-vx.xml s390-cr.xml" ;; tricore) ;; diff --git a/gdb-xml/s390-cr.xml b/gdb-xml/s390-cr.xml new file mode 100644 index 0000000000000000000000000000000000000000..5246beaab3ff8aebd54d617ca8d067930b1b378d --- /dev/null +++ b/gdb-xml/s390-cr.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c index b471e7a41e46c86148db9f44e810542da500b430..48714f96a35056c212afa71a0eea34f38ade4b81 100644 --- a/hw/intc/s390_flic_kvm.c +++ b/hw/intc/s390_flic_kvm.c @@ -228,6 +228,8 @@ static int kvm_s390_add_adapter_routes(S390FLICState *fs, routes->gsi[i] = ret; routes->adapter.ind_offset++; } + kvm_irqchip_commit_routes(kvm_state); + /* Restore passed-in structure to original state. */ routes->adapter.ind_offset = ind_offset; return 0; diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 5df450e00bb5b5dacc7260a01f169c08ff316d2d..c033612889ca3a20534ae354333c225cb5db7fed 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -261,6 +261,9 @@ static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1) ret.flags = tmp0.flags; ret.count = be16_to_cpu(tmp0.count); ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16); + if ((ret.cmd_code & 0x0f) == CCW_CMD_TIC) { + ret.cmd_code &= 0x0f; + } } return ret; } @@ -287,6 +290,10 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr) ((ccw.cmd_code & 0xf0) != 0)) { return -EINVAL; } + if (!sch->ccw_fmt_1 && (ccw.count == 0) && + (ccw.cmd_code != CCW_CMD_TIC)) { + return -EINVAL; + } if (ccw.flags & CCW_FLAG_SUSPEND) { return -EINPROGRESS; @@ -392,6 +399,8 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb) path = 0x80; if (!(s->ctrl & SCSW_ACTL_SUSP)) { + s->cstat = 0; + s->dstat = 0; /* Look at the orb and try to execute the channel program. */ assert(orb != NULL); /* resume does not pass an orb */ p->intparm = orb->intparm; diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 0c700effb114df30685c5d1c0efa19cc7fb66027..ef2a05160a9c772c9b9e481e73e33be77a43b05d 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -27,12 +27,12 @@ typedef struct SCLPEventsBus { struct SCLPEventFacility { SysBusDevice parent_obj; SCLPEventsBus sbus; + SCLPEvent quiesce_event; + SCLPEvent cpu_hotplug_event; /* guest' receive mask */ unsigned int receive_mask; }; -static SCLPEvent cpu_hotplug; - /* return true if any child has event pending set */ static bool event_pending(SCLPEventFacility *ef) { @@ -240,12 +240,13 @@ static void read_event_data(SCLPEventFacility *ef, SCCB *sccb) sclp_active_selection_mask = sclp_cp_receive_mask; break; case SCLP_SELECTIVE_READ: - if (!(sclp_cp_receive_mask & be32_to_cpu(red->mask))) { + sclp_active_selection_mask = be32_to_cpu(red->mask); + if (!sclp_cp_receive_mask || + (sclp_active_selection_mask & ~sclp_cp_receive_mask)) { sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK); goto out; } - sclp_active_selection_mask = be32_to_cpu(red->mask); break; default: sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION); @@ -286,8 +287,26 @@ out: #define TYPE_SCLP_EVENTS_BUS "s390-sclp-events-bus" +static void sclp_events_bus_realize(BusState *bus, Error **errp) +{ + BusChild *kid; + + /* TODO: recursive realization has to be done in common code */ + QTAILQ_FOREACH(kid, &bus->children, sibling) { + DeviceState *dev = kid->child; + + object_property_set_bool(OBJECT(dev), true, "realized", errp); + if (*errp) { + return; + } + } +} + static void sclp_events_bus_class_init(ObjectClass *klass, void *data) { + BusClass *bc = BUS_CLASS(klass); + + bc->realize = sclp_events_bus_realize; } static const TypeInfo sclp_events_bus_info = { @@ -324,26 +343,24 @@ static const VMStateDescription vmstate_event_facility = { } }; -static int init_event_facility(SCLPEventFacility *event_facility) +static void init_event_facility(Object *obj) { - DeviceState *sdev = DEVICE(event_facility); - DeviceState *quiesce; + SCLPEventFacility *event_facility = EVENT_FACILITY(obj); + DeviceState *sdev = DEVICE(obj); /* Spawn a new bus for SCLP events */ qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus), TYPE_SCLP_EVENTS_BUS, sdev, NULL); - quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce"); - if (!quiesce) { - return -1; - } - qdev_init_nofail(quiesce); - - object_initialize(&cpu_hotplug, sizeof(cpu_hotplug), TYPE_SCLP_CPU_HOTPLUG); - qdev_set_parent_bus(DEVICE(&cpu_hotplug), BUS(&event_facility->sbus)); - object_property_set_bool(OBJECT(&cpu_hotplug), true, "realized", NULL); - - return 0; + object_initialize(&event_facility->quiesce_event, sizeof(SCLPEvent), + TYPE_SCLP_QUIESCE); + qdev_set_parent_bus(DEVICE(&event_facility->quiesce_event), + &event_facility->sbus.qbus); + object_initialize(&event_facility->cpu_hotplug_event, sizeof(SCLPEvent), + TYPE_SCLP_CPU_HOTPLUG); + qdev_set_parent_bus(DEVICE(&event_facility->cpu_hotplug_event), + &event_facility->sbus.qbus); + /* the facility will automatically realize the devices via the bus */ } static void reset_event_facility(DeviceState *dev) @@ -362,7 +379,6 @@ static void init_event_facility_class(ObjectClass *klass, void *data) dc->reset = reset_event_facility; dc->vmsd = &vmstate_event_facility; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - k->init = init_event_facility; k->command_handler = command_handler; k->event_pending = event_pending; } @@ -370,6 +386,7 @@ static void init_event_facility_class(ObjectClass *klass, void *data) static const TypeInfo sclp_event_facility_info = { .name = TYPE_SCLP_EVENT_FACILITY, .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = init_event_facility, .instance_size = sizeof(SCLPEventFacility), .class_init = init_event_facility_class, .class_size = sizeof(SCLPEventFacilityClass), diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index e2a26e95b9608ae4d272c15b2b7ac9964b08d74e..27a83602071ed9d429513031580721adab740c53 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -100,57 +100,31 @@ static void virtio_ccw_register_hcalls(void) virtio_ccw_hcall_early_printk); } -static void ccw_init(MachineState *machine) +void s390_memory_init(ram_addr_t mem_size) { - ram_addr_t my_ram_size = machine->ram_size; MemoryRegion *sysmem = get_system_memory(); MemoryRegion *ram = g_new(MemoryRegion, 1); - sclpMemoryHotplugDev *mhd = init_sclp_memory_hotplug_dev(); + + /* allocate RAM for core */ + memory_region_init_ram(ram, NULL, "s390.ram", mem_size, &error_abort); + vmstate_register_ram_global(ram); + memory_region_add_subregion(sysmem, 0, ram); + + /* Initialize storage key device */ + s390_skeys_init(); +} + +static void ccw_init(MachineState *machine) +{ int ret; VirtualCssBus *css_bus; DeviceState *dev; - QemuOpts *opts = qemu_opts_find(qemu_find_opts("memory"), NULL); - ram_addr_t pad_size = 0; - ram_addr_t maxmem = qemu_opt_get_size(opts, "maxmem", my_ram_size); - ram_addr_t standby_mem_size = maxmem - my_ram_size; - uint64_t kvm_limit; - - /* The storage increment size is a multiple of 1M and is a power of 2. - * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer. - * The variable 'mhd->increment_size' is an exponent of 2 that can be - * used to calculate the size (in bytes) of an increment. */ - mhd->increment_size = 20; - while ((my_ram_size >> mhd->increment_size) > MAX_STORAGE_INCREMENTS) { - mhd->increment_size++; - } - while ((standby_mem_size >> mhd->increment_size) > MAX_STORAGE_INCREMENTS) { - mhd->increment_size++; - } - /* The core and standby memory areas need to be aligned with - * the increment size. In effect, this can cause the - * user-specified memory size to be rounded down to align - * with the nearest increment boundary. */ - standby_mem_size = standby_mem_size >> mhd->increment_size - << mhd->increment_size; - my_ram_size = my_ram_size >> mhd->increment_size - << mhd->increment_size; - - /* let's propagate the changed ram size into the global variable. */ - ram_size = my_ram_size; - machine->maxram_size = my_ram_size + standby_mem_size; - - ret = s390_set_memory_limit(machine->maxram_size, &kvm_limit); - if (ret == -E2BIG) { - hw_error("qemu: host supports a maximum of %" PRIu64 " GB", - kvm_limit >> 30); - } else if (ret) { - hw_error("qemu: setting the guest size failed"); - } + s390_sclp_init(); + s390_memory_init(machine->ram_size); /* get a BUS */ css_bus = virtual_css_bus_init(); - s390_sclp_init(); s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, machine->initrd_filename, "s390-ccw.img", true); s390_flic_init(); @@ -163,25 +137,6 @@ static void ccw_init(MachineState *machine) /* register hypercalls */ virtio_ccw_register_hcalls(); - /* allocate RAM for core */ - memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size, &error_abort); - vmstate_register_ram_global(ram); - memory_region_add_subregion(sysmem, 0, ram); - - /* If the size of ram is not on a MEM_SECTION_SIZE boundary, - calculate the pad size necessary to force this boundary. */ - if (standby_mem_size) { - if (my_ram_size % MEM_SECTION_SIZE) { - pad_size = MEM_SECTION_SIZE - my_ram_size % MEM_SECTION_SIZE; - } - my_ram_size += standby_mem_size + pad_size; - mhd->pad_size = pad_size; - mhd->standby_mem_size = standby_mem_size; - } - - /* Initialize storage key device */ - s390_skeys_init(); - /* init CPUs */ s390_init_cpus(machine->cpu_model); diff --git a/hw/s390x/s390-virtio.c b/hw/s390x/s390-virtio.c index 6cc6b5d5c45ca59df5c4d5e0754123f0f1631e94..e4000c92e1914d3c85b9a8049773b290e7381530 100644 --- a/hw/s390x/s390-virtio.c +++ b/hw/s390x/s390-virtio.c @@ -23,6 +23,7 @@ #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" @@ -260,30 +261,20 @@ int gtod_load(QEMUFile *f, void *opaque, int version_id) /* PC hardware initialisation */ static void s390_init(MachineState *machine) { - ram_addr_t my_ram_size = machine->ram_size; - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - int increment_size = 20; + ram_addr_t my_ram_size; void *virtio_region; hwaddr virtio_region_len; hwaddr virtio_region_start; - /* - * The storage increment size is a multiple of 1M and is a power of 2. - * The number of storage increments must be MAX_STORAGE_INCREMENTS or - * fewer. - */ - while ((my_ram_size >> increment_size) > MAX_STORAGE_INCREMENTS) { - increment_size++; + if (machine->ram_slots) { + error_report("Memory hotplug not supported by the selected machine."); + exit(EXIT_FAILURE); } - my_ram_size = my_ram_size >> increment_size << increment_size; - - /* let's propagate the changed ram size into the global variable. */ - ram_size = my_ram_size; + s390_sclp_init(); + my_ram_size = machine->ram_size; /* get a BUS */ s390_bus = s390_virtio_bus_init(&my_ram_size); - s390_sclp_init(); s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, machine->initrd_filename, ZIPL_FILENAME, false); s390_flic_init(); @@ -292,9 +283,7 @@ static void s390_init(MachineState *machine) s390_virtio_register_hcalls(); /* allocate RAM */ - memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size, &error_abort); - vmstate_register_ram_global(ram); - memory_region_add_subregion(sysmem, 0, ram); + s390_memory_init(my_ram_size); /* clear virtio region */ virtio_region_len = my_ram_size - ram_size; @@ -305,9 +294,6 @@ static void s390_init(MachineState *machine) cpu_physical_memory_unmap(virtio_region, virtio_region_len, 1, virtio_region_len); - /* Initialize storage key device */ - s390_skeys_init(); - /* init CPUs */ s390_init_cpus(machine->cpu_model); diff --git a/hw/s390x/s390-virtio.h b/hw/s390x/s390-virtio.h index cf687968b43fae6b03b56bf320ecdcb3342e1d89..f389aa1a6779e29edb523dc7efdba5314a5f79f8 100644 --- a/hw/s390x/s390-virtio.h +++ b/hw/s390x/s390-virtio.h @@ -27,4 +27,5 @@ void s390_init_ipl_dev(const char *kernel_filename, 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_memory_init(ram_addr_t mem_size); #endif diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c index b3a6c5e5a46afaaa8624e00dc7291010e9ee033c..fd277e1bf04e22110f6268570af7e0d3704ce99a 100644 --- a/hw/s390x/sclp.c +++ b/hw/s390x/sclp.c @@ -17,37 +17,27 @@ #include "exec/memory.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" -#include "qemu/config-file.h" +#include "hw/boards.h" #include "hw/s390x/sclp.h" #include "hw/s390x/event-facility.h" #include "hw/s390x/s390-pci-bus.h" -static inline SCLPEventFacility *get_event_facility(void) +static inline SCLPDevice *get_sclp_device(void) { - ObjectProperty *op = object_property_find(qdev_get_machine(), - TYPE_SCLP_EVENT_FACILITY, - NULL); - assert(op); - return op->opaque; + return SCLP(object_resolve_path_type("", TYPE_SCLP, NULL)); } /* Provide information about the configuration, CPUs and storage */ -static void read_SCP_info(SCCB *sccb) +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 i = 0; - int increment_size = 20; int rnsize, rnmax; - QemuOpts *opts = qemu_opts_find(qemu_find_opts("memory"), NULL); - int slots = qemu_opt_get_number(opts, "slots", 0); - int max_avail_slots = s390_get_memslot_count(kvm_state); - - if (slots > max_avail_slots) { - slots = max_avail_slots; - } + int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state)); CPU_FOREACH(cpu) { cpu_count++; @@ -66,23 +56,8 @@ static void read_SCP_info(SCCB *sccb) read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO | SCLP_HAS_PCI_RECONFIG); - /* - * The storage increment size is a multiple of 1M and is a power of 2. - * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer. - */ - while ((ram_size >> increment_size) > MAX_STORAGE_INCREMENTS) { - increment_size++; - } - rnmax = ram_size >> increment_size; - /* Memory Hotplug is only supported for the ccw machine type */ if (mhd) { - while ((mhd->standby_mem_size >> increment_size) > - MAX_STORAGE_INCREMENTS) { - increment_size++; - } - assert(increment_size == mhd->increment_size); - mhd->standby_subregion_size = MEM_SECTION_SIZE; /* Deduct the memory slot already used for core */ if (slots > 0) { @@ -108,13 +83,11 @@ static void read_SCP_info(SCCB *sccb) } mhd->padded_ram_size = ram_size + mhd->pad_size; mhd->rzm = 1 << mhd->increment_size; - rnmax = ((ram_size + mhd->standby_mem_size + mhd->pad_size) - >> mhd->increment_size); read_info->facilities |= cpu_to_be64(SCLP_FC_ASSIGN_ATTACH_READ_STOR); } - rnsize = 1 << (increment_size - 20); + rnsize = 1 << (sclp->increment_size - 20); if (rnsize <= 128) { read_info->rnsize = rnsize; } else { @@ -122,6 +95,7 @@ static void read_SCP_info(SCCB *sccb) read_info->rnsize2 = cpu_to_be32(rnsize); } + rnmax = machine->maxram_size >> sclp->increment_size; if (rnmax < 0x10000) { read_info->rnmax = cpu_to_be16(rnmax); } else { @@ -132,14 +106,17 @@ static void read_SCP_info(SCCB *sccb) sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); } -static void read_storage_element0_info(SCCB *sccb) +static void read_storage_element0_info(SCLPDevice *sclp, SCCB *sccb) { int i, assigned; int subincrement_id = SCLP_STARTING_SUBINCREMENT_ID; ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb; sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - assert(mhd); + if (!mhd) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + return; + } if ((ram_size >> mhd->increment_size) >= 0x10000) { sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); @@ -158,12 +135,15 @@ static void read_storage_element0_info(SCCB *sccb) sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); } -static void read_storage_element1_info(SCCB *sccb) +static void read_storage_element1_info(SCLPDevice *sclp, SCCB *sccb) { ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb; sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - assert(mhd); + if (!mhd) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + return; + } if ((mhd->standby_mem_size >> mhd->increment_size) >= 0x10000) { sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); @@ -179,13 +159,17 @@ static void read_storage_element1_info(SCCB *sccb) sccb->h.response_code = cpu_to_be16(SCLP_RC_STANDBY_READ_COMPLETION); } -static void attach_storage_element(SCCB *sccb, uint16_t element) +static void attach_storage_element(SCLPDevice *sclp, SCCB *sccb, + uint16_t element) { int i, assigned, subincrement_id; AttachStorageElement *attach_info = (AttachStorageElement *) sccb; sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - assert(mhd); + if (!mhd) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + return; + } if (element != 1) { sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); @@ -203,20 +187,26 @@ static void attach_storage_element(SCCB *sccb, uint16_t element) sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION); } -static void assign_storage(SCCB *sccb) +static void assign_storage(SCLPDevice *sclp, SCCB *sccb) { MemoryRegion *mr = NULL; uint64_t this_subregion_size; AssignStorage *assign_info = (AssignStorage *) sccb; sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - assert(mhd); - ram_addr_t assign_addr = (assign_info->rn - 1) * mhd->rzm; + ram_addr_t assign_addr; MemoryRegion *sysmem = get_system_memory(); + if (!mhd) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + return; + } + assign_addr = (assign_info->rn - 1) * mhd->rzm; + if ((assign_addr % MEM_SECTION_SIZE == 0) && (assign_addr >= mhd->padded_ram_size)) { /* Re-use existing memory region if found */ mr = memory_region_find(sysmem, assign_addr, 1).mr; + memory_region_unref(mr); if (!mr) { MemoryRegion *standby_ram = g_new(MemoryRegion, 1); @@ -242,6 +232,11 @@ static void assign_storage(SCCB *sccb) } memory_region_init_ram(standby_ram, NULL, id, this_subregion_size, &error_abort); + /* This is a hack to make memory hotunplug work again. Once we have + * subdevices, we have to unparent them when unassigning memory, + * instead of doing it via the ref count of the MemoryRegion. */ + object_ref(OBJECT(standby_ram)); + object_unparent(OBJECT(standby_ram)); vmstate_register_ram_global(standby_ram); memory_region_add_subregion(sysmem, offset, standby_ram); } @@ -252,15 +247,20 @@ static void assign_storage(SCCB *sccb) sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION); } -static void unassign_storage(SCCB *sccb) +static void unassign_storage(SCLPDevice *sclp, SCCB *sccb) { MemoryRegion *mr = NULL; AssignStorage *assign_info = (AssignStorage *) sccb; sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - assert(mhd); - ram_addr_t unassign_addr = (assign_info->rn - 1) * mhd->rzm; + ram_addr_t unassign_addr; MemoryRegion *sysmem = get_system_memory(); + if (!mhd) { + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); + return; + } + unassign_addr = (assign_info->rn - 1) * mhd->rzm; + /* if the addr is a multiple of 256 MB */ if ((unassign_addr % MEM_SECTION_SIZE == 0) && (unassign_addr >= mhd->padded_ram_size)) { @@ -269,6 +269,7 @@ static void unassign_storage(SCCB *sccb) /* find the specified memory region and destroy it */ mr = memory_region_find(sysmem, unassign_addr, 1).mr; + memory_region_unref(mr); if (mr) { int i; int is_removable = 1; @@ -287,8 +288,7 @@ static void unassign_storage(SCCB *sccb) } if (is_removable) { memory_region_del_subregion(sysmem, mr); - object_unparent(OBJECT(mr)); - g_free(mr); + object_unref(OBJECT(mr)); } } } @@ -296,7 +296,7 @@ static void unassign_storage(SCCB *sccb) } /* Provide information about the CPU */ -static void sclp_read_cpu_info(SCCB *sccb) +static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb) { ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb; CPUState *cpu; @@ -323,34 +323,35 @@ static void sclp_read_cpu_info(SCCB *sccb) sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); } -static void sclp_execute(SCCB *sccb, uint32_t code) +static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code) { - SCLPEventFacility *ef = get_event_facility(); + SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); + SCLPEventFacility *ef = sclp->event_facility; SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef); switch (code & SCLP_CMD_CODE_MASK) { case SCLP_CMDW_READ_SCP_INFO: case SCLP_CMDW_READ_SCP_INFO_FORCED: - read_SCP_info(sccb); + sclp_c->read_SCP_info(sclp, sccb); break; case SCLP_CMDW_READ_CPU_INFO: - sclp_read_cpu_info(sccb); + sclp_c->read_cpu_info(sclp, sccb); break; case SCLP_READ_STORAGE_ELEMENT_INFO: if (code & 0xff00) { - read_storage_element1_info(sccb); + sclp_c->read_storage_element1_info(sclp, sccb); } else { - read_storage_element0_info(sccb); + sclp_c->read_storage_element0_info(sclp, sccb); } break; case SCLP_ATTACH_STORAGE_ELEMENT: - attach_storage_element(sccb, (code & 0xff00) >> 8); + sclp_c->attach_storage_element(sclp, sccb, (code & 0xff00) >> 8); break; case SCLP_ASSIGN_STORAGE: - assign_storage(sccb); + sclp_c->assign_storage(sclp, sccb); break; case SCLP_UNASSIGN_STORAGE: - unassign_storage(sccb); + sclp_c->unassign_storage(sclp, sccb); break; case SCLP_CMDW_CONFIGURE_PCI: s390_pci_sclp_configure(1, sccb); @@ -366,6 +367,8 @@ static void sclp_execute(SCCB *sccb, uint32_t code) int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) { + SCLPDevice *sclp = get_sclp_device(); + SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); int r = 0; SCCB work_sccb; @@ -400,20 +403,20 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) goto out; } - sclp_execute((SCCB *)&work_sccb, code); + sclp_c->execute(sclp, (SCCB *)&work_sccb, code); cpu_physical_memory_write(sccb, &work_sccb, be16_to_cpu(work_sccb.h.length)); - sclp_service_interrupt(sccb); + sclp_c->service_interrupt(sclp, sccb); out: return r; } -void sclp_service_interrupt(uint32_t sccb) +static void service_interrupt(SCLPDevice *sclp, uint32_t sccb) { - SCLPEventFacility *ef = get_event_facility(); + SCLPEventFacility *ef = sclp->event_facility; SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef); uint32_t param = sccb & ~3; @@ -428,17 +431,148 @@ void sclp_service_interrupt(uint32_t sccb) s390_sclp_extint(param); } +void sclp_service_interrupt(uint32_t sccb) +{ + SCLPDevice *sclp = get_sclp_device(); + SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); + + sclp_c->service_interrupt(sclp, sccb); +} + /* qemu object creation and initialization functions */ void s390_sclp_init(void) { - DeviceState *dev = qdev_create(NULL, TYPE_SCLP_EVENT_FACILITY); + Object *new = object_new(TYPE_SCLP); - object_property_add_child(qdev_get_machine(), TYPE_SCLP_EVENT_FACILITY, - OBJECT(dev), NULL); - qdev_init_nofail(dev); + object_property_add_child(qdev_get_machine(), TYPE_SCLP, new, + NULL); + object_unref(OBJECT(new)); + qdev_init_nofail(DEVICE(new)); +} + +static void sclp_realize(DeviceState *dev, Error **errp) +{ + MachineState *machine = MACHINE(qdev_get_machine()); + SCLPDevice *sclp = SCLP(dev); + Error *l_err = NULL; + uint64_t hw_limit; + int ret; + + object_property_set_bool(OBJECT(sclp->event_facility), true, "realized", + &l_err); + if (l_err) { + goto error; + } + + ret = s390_set_memory_limit(machine->maxram_size, &hw_limit); + if (ret == -E2BIG) { + error_setg(&l_err, "qemu: host supports a maximum of %" PRIu64 " GB", + hw_limit >> 30); + goto error; + } else if (ret) { + error_setg(&l_err, "qemu: setting the guest size failed"); + goto error; + } + return; +error: + assert(l_err); + error_propagate(errp, l_err); +} + +static void sclp_memory_init(SCLPDevice *sclp) +{ + MachineState *machine = MACHINE(qdev_get_machine()); + ram_addr_t initial_mem = machine->ram_size; + ram_addr_t max_mem = machine->maxram_size; + ram_addr_t standby_mem = max_mem - initial_mem; + ram_addr_t pad_mem = 0; + int increment_size = 20; + + /* The storage increment size is a multiple of 1M and is a power of 2. + * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer. + * The variable 'increment_size' is an exponent of 2 that can be + * used to calculate the size (in bytes) of an increment. */ + while ((initial_mem >> increment_size) > MAX_STORAGE_INCREMENTS) { + increment_size++; + } + if (machine->ram_slots) { + while ((standby_mem >> increment_size) > MAX_STORAGE_INCREMENTS) { + increment_size++; + } + } + sclp->increment_size = increment_size; + + /* The core and standby memory areas need to be aligned with + * the increment size. In effect, this can cause the + * user-specified memory size to be rounded down to align + * with the nearest increment boundary. */ + initial_mem = initial_mem >> increment_size << increment_size; + standby_mem = standby_mem >> increment_size << increment_size; + + /* If the size of ram is not on a MEM_SECTION_SIZE boundary, + calculate the pad size necessary to force this boundary. */ + if (machine->ram_slots && standby_mem) { + sclpMemoryHotplugDev *mhd = init_sclp_memory_hotplug_dev(); + + if (initial_mem % MEM_SECTION_SIZE) { + pad_mem = MEM_SECTION_SIZE - initial_mem % MEM_SECTION_SIZE; + } + mhd->increment_size = increment_size; + mhd->pad_size = pad_mem; + mhd->standby_mem_size = standby_mem; + } + machine->ram_size = initial_mem; + machine->maxram_size = initial_mem + pad_mem + standby_mem; + /* let's propagate the changed ram size into the global variable. */ + ram_size = initial_mem; +} + +static void sclp_init(Object *obj) +{ + SCLPDevice *sclp = SCLP(obj); + Object *new; + + new = object_new(TYPE_SCLP_EVENT_FACILITY); + object_property_add_child(obj, TYPE_SCLP_EVENT_FACILITY, new, NULL); + /* qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS */ + qdev_set_parent_bus(DEVICE(new), sysbus_get_default()); + object_unref(new); + sclp->event_facility = EVENT_FACILITY(new); + + sclp_memory_init(sclp); } +static void sclp_class_init(ObjectClass *oc, void *data) +{ + SCLPDeviceClass *sc = SCLP_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->desc = "SCLP (Service-Call Logical Processor)"; + dc->realize = sclp_realize; + dc->hotpluggable = false; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + + sc->read_SCP_info = read_SCP_info; + sc->read_storage_element0_info = read_storage_element0_info; + sc->read_storage_element1_info = read_storage_element1_info; + sc->attach_storage_element = attach_storage_element; + sc->assign_storage = assign_storage; + sc->unassign_storage = unassign_storage; + sc->read_cpu_info = sclp_read_cpu_info; + sc->execute = sclp_execute; + sc->service_interrupt = service_interrupt; +} + +static TypeInfo sclp_info = { + .name = TYPE_SCLP, + .parent = TYPE_DEVICE, + .instance_init = sclp_init, + .instance_size = sizeof(SCLPDevice), + .class_init = sclp_class_init, + .class_size = sizeof(SCLPDeviceClass), +}; + sclpMemoryHotplugDev *init_sclp_memory_hotplug_dev(void) { DeviceState *dev; @@ -475,5 +609,6 @@ static TypeInfo sclp_memory_hotplug_dev_info = { static void register_types(void) { type_register_static(&sclp_memory_hotplug_dev_info); + type_register_static(&sclp_info); } type_init(register_types); diff --git a/hw/s390x/sclpcpu.c b/hw/s390x/sclpcpu.c index 2fe8b5aa40e872498411877bf02febfc1e3b092f..322eb31d958184a48048d021c040c8a5247e8b6e 100644 --- a/hw/s390x/sclpcpu.c +++ b/hw/s390x/sclpcpu.c @@ -25,13 +25,16 @@ typedef struct ConfigMgtData { uint8_t event_qualifier; } QEMU_PACKED ConfigMgtData; -static qemu_irq *irq_cpu_hotplug; /* Only used in this file */ - #define EVENT_QUAL_CPU_CHANGE 1 void raise_irq_cpu_hotplug(void) { - qemu_irq_raise(*irq_cpu_hotplug); + Object *obj = object_resolve_path_type("", TYPE_SCLP_CPU_HOTPLUG, NULL); + + SCLP_EVENT(obj)->event_pending = true; + + /* Trigger SCLP read operation */ + sclp_service_interrupt(0); } static unsigned int send_mask(void) @@ -70,36 +73,19 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, return 1; } -static void trigger_signal(void *opaque, int n, int level) -{ - SCLPEvent *event = opaque; - event->event_pending = true; - - /* Trigger SCLP read operation */ - sclp_service_interrupt(0); -} - -static int irq_cpu_hotplug_init(SCLPEvent *event) -{ - irq_cpu_hotplug = qemu_allocate_irqs(trigger_signal, event, 1); - return 0; -} - static void cpu_class_init(ObjectClass *oc, void *data) { SCLPEventClass *k = SCLP_EVENT_CLASS(oc); DeviceClass *dc = DEVICE_CLASS(oc); - k->init = irq_cpu_hotplug_init; k->get_send_mask = send_mask; k->get_receive_mask = receive_mask; k->read_event_data = read_event_data; - k->write_event_data = NULL; set_bit(DEVICE_CATEGORY_MISC, dc->categories); } static const TypeInfo sclp_cpu_info = { - .name = "sclp-cpu-hotplug", + .name = TYPE_SCLP_CPU_HOTPLUG, .parent = TYPE_SCLP_EVENT, .instance_size = sizeof(SCLPEvent), .class_init = cpu_class_init, diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index ffa555313561f91a88b34175039619714e1fcb6a..15b06e108bf244ba1d1e712e4714f4b1b8a4caca 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -66,7 +66,7 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, } static const VMStateDescription vmstate_sclpquiesce = { - .name = "sclpquiesce", + .name = TYPE_SCLP_QUIESCE, .version_id = 0, .minimum_version_id = 0, .fields = (VMStateField[]) { @@ -127,7 +127,7 @@ static void quiesce_class_init(ObjectClass *klass, void *data) } static const TypeInfo sclp_quiesce_info = { - .name = "sclpquiesce", + .name = TYPE_SCLP_QUIESCE, .parent = TYPE_SCLP_EVENT, .instance_size = sizeof(SCLPEvent), .class_init = quiesce_class_init, diff --git a/include/hw/s390x/event-facility.h b/include/hw/s390x/event-facility.h index 6a062b668af521f80e5e308bbc30e5a2a0d8a485..dd8881838c7905011acd14c0ff1dcb3cb1404bfa 100644 --- a/include/hw/s390x/event-facility.h +++ b/include/hw/s390x/event-facility.h @@ -47,6 +47,7 @@ OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT) #define TYPE_SCLP_CPU_HOTPLUG "sclp-cpu-hotplug" +#define TYPE_SCLP_QUIESCE "sclpquiesce" typedef struct WriteEventMask { SCCBHeader h; @@ -146,8 +147,10 @@ typedef struct WriteEventData { typedef struct ReadEventData { SCCBHeader h; - EventBufferHeader ebh; - uint32_t mask; + union { + uint32_t mask; + EventBufferHeader ebh; + }; } QEMU_PACKED ReadEventData; typedef struct SCLPEvent { @@ -186,11 +189,8 @@ typedef struct SCLPEventClass { OBJECT_GET_CLASS(SCLPEventFacilityClass, (obj), \ TYPE_SCLP_EVENT_FACILITY) -typedef struct SCLPEventFacility SCLPEventFacility; - typedef struct SCLPEventFacilityClass { - DeviceClass parent_class; - int (*init)(SCLPEventFacility *ef); + SysBusDeviceClass parent_class; void (*command_handler)(SCLPEventFacility *ef, SCCB *sccb, uint64_t code); bool (*event_pending)(SCLPEventFacility *ef); } SCLPEventFacilityClass; diff --git a/include/hw/s390x/sclp.h b/include/hw/s390x/sclp.h index e8a64e25b72ed27728459b8a94de45a59963749c..b0c71b5550ba0327d2640faffa604170dd08243e 100644 --- a/include/hw/s390x/sclp.h +++ b/include/hw/s390x/sclp.h @@ -163,6 +163,39 @@ typedef struct SCCB { char data[SCCB_DATA_LEN]; } QEMU_PACKED SCCB; +#define TYPE_SCLP "sclp" +#define SCLP(obj) OBJECT_CHECK(SCLPDevice, (obj), TYPE_SCLP) +#define SCLP_CLASS(oc) OBJECT_CLASS_CHECK(SCLPDeviceClass, (oc), TYPE_SCLP) +#define SCLP_GET_CLASS(obj) OBJECT_GET_CLASS(SCLPDeviceClass, (obj), TYPE_SCLP) + +typedef struct SCLPEventFacility SCLPEventFacility; + +typedef struct SCLPDevice { + /* private */ + DeviceState parent_obj; + SCLPEventFacility *event_facility; + int increment_size; + + /* public */ +} SCLPDevice; + +typedef struct SCLPDeviceClass { + /* private */ + DeviceClass parent_class; + void (*read_SCP_info)(SCLPDevice *sclp, SCCB *sccb); + void (*read_storage_element0_info)(SCLPDevice *sclp, SCCB *sccb); + void (*read_storage_element1_info)(SCLPDevice *sclp, SCCB *sccb); + void (*attach_storage_element)(SCLPDevice *sclp, SCCB *sccb, + uint16_t element); + void (*assign_storage)(SCLPDevice *sclp, SCCB *sccb); + void (*unassign_storage)(SCLPDevice *sclp, SCCB *sccb); + void (*read_cpu_info)(SCLPDevice *sclp, SCCB *sccb); + + /* public */ + void (*execute)(SCLPDevice *sclp, SCCB *sccb, uint32_t code); + void (*service_interrupt)(SCLPDevice *sclp, uint32_t sccb); +} SCLPDeviceClass; + typedef struct sclpMemoryHotplugDev sclpMemoryHotplugDev; #define TYPE_SCLP_MEMORY_HOTPLUG_DEV "sclp-memory-hotplug-dev" diff --git a/kvm-all.c b/kvm-all.c index 06e06f2b3fd681c0de1fb54c5c2d8062564a648c..c6f51287569cb7f8ea9ed9801745f03a470339cd 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -1293,7 +1293,6 @@ int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter) kroute.u.adapter.adapter_id = adapter->adapter_id; kvm_add_routing_entry(s, &kroute); - kvm_irqchip_commit_routes(s); return virq; } diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img index f64380a972f280d66a4df03f029e4e1d42da292d..0c540a10cf2a662889f5fbd08a7580395a7577d0 100644 Binary files a/pc-bios/s390-ccw.img and b/pc-bios/s390-ccw.img differ diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c index 584d4a2769a944b5d99fd5962cb665690d6cd1d1..d5fe4cea1d61c5f2db606341158502f728e4218d 100644 --- a/pc-bios/s390-ccw/main.c +++ b/pc-bios/s390-ccw/main.c @@ -38,40 +38,56 @@ void virtio_panic(const char *string) while (1) { } } +static bool find_dev(struct schib *schib, int dev_no) +{ + int i, r; + + for (i = 0; i < 0x10000; i++) { + blk_schid.sch_no = i; + r = stsch_err(blk_schid, schib); + if ((r == 3) || (r == -EIO)) { + break; + } + if (!schib->pmcw.dnv) { + continue; + } + if (!virtio_is_blk(blk_schid)) { + continue; + } + if ((dev_no < 0) || (schib->pmcw.dev == dev_no)) { + return true; + } + } + + return false; +} + static void virtio_setup(uint64_t dev_info) { struct schib schib; - int i; - int r; + int ssid; bool found = false; - bool check_devno = false; - uint16_t dev_no = -1; + uint16_t dev_no; + + /* + * We unconditionally enable mss support. In every sane configuration, + * this will succeed; and even if it doesn't, stsch_err() can deal + * with the consequences. + */ + enable_mss_facility(); if (dev_info != -1) { - check_devno = true; dev_no = dev_info & 0xffff; debug_print_int("device no. ", dev_no); blk_schid.ssid = (dev_info >> 16) & 0x3; - if (blk_schid.ssid != 0) { - debug_print_int("ssid ", blk_schid.ssid); - if (enable_mss_facility() != 0) { - virtio_panic("Failed to enable mss facility\n"); - } - } - } - - for (i = 0; i < 0x10000; i++) { - blk_schid.sch_no = i; - r = stsch_err(blk_schid, &schib); - if (r == 3) { - break; - } - if (schib.pmcw.dnv) { - if (!check_devno || (schib.pmcw.dev == dev_no)) { - if (virtio_is_blk(blk_schid)) { - found = true; - break; - } + debug_print_int("ssid ", blk_schid.ssid); + found = find_dev(&schib, dev_no); + } else { + for (ssid = 0; ssid < 0x3; ssid++) { + blk_schid.ssid = ssid; + found = find_dev(&schib, -1); + if (found) { + break; } } } diff --git a/target-s390x/gdbstub.c b/target-s390x/gdbstub.c index 31f204964ff3856a95123419e25bba920d893f26..0c39a3c69ff9fc6a35e10868d6315bfee27eef23 100644 --- a/target-s390x/gdbstub.c +++ b/target-s390x/gdbstub.c @@ -174,6 +174,39 @@ static int cpu_write_vreg(CPUS390XState *env, uint8_t *mem_buf, int n) } } +/* the values represent the positions in s390-cr.xml */ +#define S390_C0_REGNUM 0 +#define S390_C15_REGNUM 15 +/* total number of registers in s390-cr.xml */ +#define S390_NUM_C_REGS 16 + +#ifndef CONFIG_USER_ONLY +static int cpu_read_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n) +{ + switch (n) { + case S390_C0_REGNUM ... S390_C15_REGNUM: + return gdb_get_regl(mem_buf, env->cregs[n]); + default: + return 0; + } +} + +static int cpu_write_c_reg(CPUS390XState *env, uint8_t *mem_buf, int n) +{ + switch (n) { + case S390_C0_REGNUM ... S390_C15_REGNUM: + env->cregs[n] = ldtul_p(mem_buf); + if (tcg_enabled()) { + tlb_flush(ENV_GET_CPU(env), 1); + } + cpu_synchronize_post_init(ENV_GET_CPU(env)); + return 8; + default: + return 0; + } +} +#endif + void s390_cpu_gdb_init(CPUState *cs) { gdb_register_coprocessor(cs, cpu_read_ac_reg, @@ -187,4 +220,10 @@ void s390_cpu_gdb_init(CPUState *cs) gdb_register_coprocessor(cs, cpu_read_vreg, cpu_write_vreg, S390_NUM_VREGS, "s390-vx.xml", 0); + +#ifndef CONFIG_USER_ONLY + gdb_register_coprocessor(cs, cpu_read_c_reg, + cpu_write_c_reg, + S390_NUM_C_REGS, "s390-cr.xml", 0); +#endif }