s390x fixes and improvements:
- various bugfixes (css/event-facility) - more efficient adapter interrupt routes setup - gdb enhancement - sclp got treated with a lot of remodelling/cleanup -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJV7aJjAAoJEN7Pa5PG8C+v1fgQALFLDq1zNaq4/mZkYLMqaFnt nRQsZLzecxHJAVKdFBc5QlCBSRCFjSRLeLeiULu8UkREFO+iZ1HhdnwlTB83cs/3 iHuz+NzJI1C++ATIzqGJpZSXZgYqftar7LKAANwpwjSkANOytrs/m7Y31UYl4zkT MgfAD0AYWITrOEyefMSXkPL4ddY0otzx7d9az16sIbarSlkItoNj/AVFVmKfPIFa 8cI54YNG582L4gWavC2HGNC95Fau8/oZhNzFAprerIOdCx0bqE5Pmlkohz6AJg+U e5PyVfIV+fnZtnFtII68HtTwFz0JcBgtga0xWiqlVU+ICrXvyADJDmqeTsU6QMMR sxTzHNtuSAvJ4JgwXz3nNq7nbUPDAo6SX/YwsTcKPWmFLG5ZctSAYxPBvNY27Mrw NdywJ8xif6yK8Fc53Dey0+ZYnNTaI6sd/EMPGpeP4B7PU6iZU3z8YOtevSYGib5B vonGo1YA+Z2DxM+WdT8rjSwgU/MRbRWdWSA4FBr/7K4dkG18d4Pi8Wng4BXlHz+w kUzXhANJ2QvIfVlPlm8EKudPDVPMeXGG0SGSIDeUKnh/vZQ56LCUTYTasTsx3+MU XbKJeDBbn+nB33KEOZB9weBL51BIjSB6iGEzVrKQSAsK85iUyqv7NzkrMPVYSB/e ZQV4lfk6pJTQ2LaBp1Fb =Ax4r -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20150907' into staging s390x fixes and improvements: - various bugfixes (css/event-facility) - more efficient adapter interrupt routes setup - gdb enhancement - sclp got treated with a lot of remodelling/cleanup # gpg: Signature made Mon 07 Sep 2015 15:42:43 BST using RSA key ID C6F02FAF # gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>" # gpg: aka "Cornelia Huck <cornelia.huck@de.ibm.com>" * remotes/cohuck/tags/s390x-20150907: (23 commits) s390/sclp: simplify calculation of rnmax s390/sclp: store the increment_size in the sclp device s390: unify allocation of initial memory s390: move memory calculation into the sclp device s390/sclp: ignore memory hotplug operations if it is disabled s390: disallow memory hotplug for the s390-virtio machine s390: no need to manually parse for slots and maxmem s390/sclp: move sclp_service_interrupt into the sclp device s390/sclp: move sclp_execute related functions into the SCLP class s390/sclp: introduce a root sclp device s390/sclp: temporarily fix unassignment/reassignment of memory subregions s390/sclp: replace sclp event types with proper defines s390/sclp: rework sclp event facility initialization + device realization sclp/s390: rework sclp cpu hotplug device notification s390x/gdb: support reading/writing of control registers s390x/kvm: make setting of in-kernel irq routes more efficient pc-bios/s390-ccw: rebuild image pc-bios/s390-ccw: Device detection in higher subchannel sets s390x/event-facility: fix location of receive mask s390x/css: start with cleared cstat/dstat ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
9d34158a5a
2
configure
vendored
2
configure
vendored
|
@ -5392,7 +5392,7 @@ case "$target_name" in
|
||||||
echo "TARGET_ABI32=y" >> $config_target_mak
|
echo "TARGET_ABI32=y" >> $config_target_mak
|
||||||
;;
|
;;
|
||||||
s390x)
|
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)
|
tricore)
|
||||||
;;
|
;;
|
||||||
|
|
26
gdb-xml/s390-cr.xml
Normal file
26
gdb-xml/s390-cr.xml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!-- Copyright 2015 IBM Corp.
|
||||||
|
|
||||||
|
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. -->
|
||||||
|
|
||||||
|
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||||
|
<feature name="org.gnu.gdb.s390.cr">
|
||||||
|
<reg name="cr0" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr1" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr2" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr3" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr4" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr5" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr6" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr7" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr8" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr9" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr10" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr11" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr12" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr13" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr14" bitsize="64" type="uint64" group="control"/>
|
||||||
|
<reg name="cr15" bitsize="64" type="uint64" group="control"/>
|
||||||
|
</feature>
|
|
@ -228,6 +228,8 @@ static int kvm_s390_add_adapter_routes(S390FLICState *fs,
|
||||||
routes->gsi[i] = ret;
|
routes->gsi[i] = ret;
|
||||||
routes->adapter.ind_offset++;
|
routes->adapter.ind_offset++;
|
||||||
}
|
}
|
||||||
|
kvm_irqchip_commit_routes(kvm_state);
|
||||||
|
|
||||||
/* Restore passed-in structure to original state. */
|
/* Restore passed-in structure to original state. */
|
||||||
routes->adapter.ind_offset = ind_offset;
|
routes->adapter.ind_offset = ind_offset;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -261,6 +261,9 @@ static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1)
|
||||||
ret.flags = tmp0.flags;
|
ret.flags = tmp0.flags;
|
||||||
ret.count = be16_to_cpu(tmp0.count);
|
ret.count = be16_to_cpu(tmp0.count);
|
||||||
ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16);
|
ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16);
|
||||||
|
if ((ret.cmd_code & 0x0f) == CCW_CMD_TIC) {
|
||||||
|
ret.cmd_code &= 0x0f;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -287,6 +290,10 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr)
|
||||||
((ccw.cmd_code & 0xf0) != 0)) {
|
((ccw.cmd_code & 0xf0) != 0)) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
if (!sch->ccw_fmt_1 && (ccw.count == 0) &&
|
||||||
|
(ccw.cmd_code != CCW_CMD_TIC)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
if (ccw.flags & CCW_FLAG_SUSPEND) {
|
if (ccw.flags & CCW_FLAG_SUSPEND) {
|
||||||
return -EINPROGRESS;
|
return -EINPROGRESS;
|
||||||
|
@ -392,6 +399,8 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
|
||||||
path = 0x80;
|
path = 0x80;
|
||||||
|
|
||||||
if (!(s->ctrl & SCSW_ACTL_SUSP)) {
|
if (!(s->ctrl & SCSW_ACTL_SUSP)) {
|
||||||
|
s->cstat = 0;
|
||||||
|
s->dstat = 0;
|
||||||
/* Look at the orb and try to execute the channel program. */
|
/* Look at the orb and try to execute the channel program. */
|
||||||
assert(orb != NULL); /* resume does not pass an orb */
|
assert(orb != NULL); /* resume does not pass an orb */
|
||||||
p->intparm = orb->intparm;
|
p->intparm = orb->intparm;
|
||||||
|
|
|
@ -27,12 +27,12 @@ typedef struct SCLPEventsBus {
|
||||||
struct SCLPEventFacility {
|
struct SCLPEventFacility {
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
SCLPEventsBus sbus;
|
SCLPEventsBus sbus;
|
||||||
|
SCLPEvent quiesce_event;
|
||||||
|
SCLPEvent cpu_hotplug_event;
|
||||||
/* guest' receive mask */
|
/* guest' receive mask */
|
||||||
unsigned int receive_mask;
|
unsigned int receive_mask;
|
||||||
};
|
};
|
||||||
|
|
||||||
static SCLPEvent cpu_hotplug;
|
|
||||||
|
|
||||||
/* return true if any child has event pending set */
|
/* return true if any child has event pending set */
|
||||||
static bool event_pending(SCLPEventFacility *ef)
|
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;
|
sclp_active_selection_mask = sclp_cp_receive_mask;
|
||||||
break;
|
break;
|
||||||
case SCLP_SELECTIVE_READ:
|
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 =
|
sccb->h.response_code =
|
||||||
cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
|
cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
sclp_active_selection_mask = be32_to_cpu(red->mask);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
|
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"
|
#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)
|
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 = {
|
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);
|
SCLPEventFacility *event_facility = EVENT_FACILITY(obj);
|
||||||
DeviceState *quiesce;
|
DeviceState *sdev = DEVICE(obj);
|
||||||
|
|
||||||
/* Spawn a new bus for SCLP events */
|
/* Spawn a new bus for SCLP events */
|
||||||
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
|
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
|
||||||
TYPE_SCLP_EVENTS_BUS, sdev, NULL);
|
TYPE_SCLP_EVENTS_BUS, sdev, NULL);
|
||||||
|
|
||||||
quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
|
object_initialize(&event_facility->quiesce_event, sizeof(SCLPEvent),
|
||||||
if (!quiesce) {
|
TYPE_SCLP_QUIESCE);
|
||||||
return -1;
|
qdev_set_parent_bus(DEVICE(&event_facility->quiesce_event),
|
||||||
}
|
&event_facility->sbus.qbus);
|
||||||
qdev_init_nofail(quiesce);
|
object_initialize(&event_facility->cpu_hotplug_event, sizeof(SCLPEvent),
|
||||||
|
TYPE_SCLP_CPU_HOTPLUG);
|
||||||
object_initialize(&cpu_hotplug, sizeof(cpu_hotplug), TYPE_SCLP_CPU_HOTPLUG);
|
qdev_set_parent_bus(DEVICE(&event_facility->cpu_hotplug_event),
|
||||||
qdev_set_parent_bus(DEVICE(&cpu_hotplug), BUS(&event_facility->sbus));
|
&event_facility->sbus.qbus);
|
||||||
object_property_set_bool(OBJECT(&cpu_hotplug), true, "realized", NULL);
|
/* the facility will automatically realize the devices via the bus */
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reset_event_facility(DeviceState *dev)
|
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->reset = reset_event_facility;
|
||||||
dc->vmsd = &vmstate_event_facility;
|
dc->vmsd = &vmstate_event_facility;
|
||||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||||
k->init = init_event_facility;
|
|
||||||
k->command_handler = command_handler;
|
k->command_handler = command_handler;
|
||||||
k->event_pending = event_pending;
|
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 = {
|
static const TypeInfo sclp_event_facility_info = {
|
||||||
.name = TYPE_SCLP_EVENT_FACILITY,
|
.name = TYPE_SCLP_EVENT_FACILITY,
|
||||||
.parent = TYPE_SYS_BUS_DEVICE,
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_init = init_event_facility,
|
||||||
.instance_size = sizeof(SCLPEventFacility),
|
.instance_size = sizeof(SCLPEventFacility),
|
||||||
.class_init = init_event_facility_class,
|
.class_init = init_event_facility_class,
|
||||||
.class_size = sizeof(SCLPEventFacilityClass),
|
.class_size = sizeof(SCLPEventFacilityClass),
|
||||||
|
|
|
@ -100,57 +100,31 @@ static void virtio_ccw_register_hcalls(void)
|
||||||
virtio_ccw_hcall_early_printk);
|
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 *sysmem = get_system_memory();
|
||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
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;
|
int ret;
|
||||||
VirtualCssBus *css_bus;
|
VirtualCssBus *css_bus;
|
||||||
DeviceState *dev;
|
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.
|
s390_sclp_init();
|
||||||
* The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer.
|
s390_memory_init(machine->ram_size);
|
||||||
* 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");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get a BUS */
|
/* get a BUS */
|
||||||
css_bus = virtual_css_bus_init();
|
css_bus = virtual_css_bus_init();
|
||||||
s390_sclp_init();
|
|
||||||
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
|
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
|
||||||
machine->initrd_filename, "s390-ccw.img", true);
|
machine->initrd_filename, "s390-ccw.img", true);
|
||||||
s390_flic_init();
|
s390_flic_init();
|
||||||
|
@ -163,25 +137,6 @@ static void ccw_init(MachineState *machine)
|
||||||
/* register hypercalls */
|
/* register hypercalls */
|
||||||
virtio_ccw_register_hcalls();
|
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 */
|
/* init CPUs */
|
||||||
s390_init_cpus(machine->cpu_model);
|
s390_init_cpus(machine->cpu_model);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
#include "qapi/qmp/qerror.h"
|
#include "qapi/qmp/qerror.h"
|
||||||
|
#include "qemu/error-report.h"
|
||||||
#include "sysemu/block-backend.h"
|
#include "sysemu/block-backend.h"
|
||||||
#include "sysemu/blockdev.h"
|
#include "sysemu/blockdev.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
|
@ -260,30 +261,20 @@ int gtod_load(QEMUFile *f, void *opaque, int version_id)
|
||||||
/* PC hardware initialisation */
|
/* PC hardware initialisation */
|
||||||
static void s390_init(MachineState *machine)
|
static void s390_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
ram_addr_t my_ram_size = machine->ram_size;
|
ram_addr_t my_ram_size;
|
||||||
MemoryRegion *sysmem = get_system_memory();
|
|
||||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
|
||||||
int increment_size = 20;
|
|
||||||
void *virtio_region;
|
void *virtio_region;
|
||||||
hwaddr virtio_region_len;
|
hwaddr virtio_region_len;
|
||||||
hwaddr virtio_region_start;
|
hwaddr virtio_region_start;
|
||||||
|
|
||||||
/*
|
if (machine->ram_slots) {
|
||||||
* The storage increment size is a multiple of 1M and is a power of 2.
|
error_report("Memory hotplug not supported by the selected machine.");
|
||||||
* The number of storage increments must be MAX_STORAGE_INCREMENTS or
|
exit(EXIT_FAILURE);
|
||||||
* fewer.
|
|
||||||
*/
|
|
||||||
while ((my_ram_size >> increment_size) > MAX_STORAGE_INCREMENTS) {
|
|
||||||
increment_size++;
|
|
||||||
}
|
}
|
||||||
my_ram_size = my_ram_size >> increment_size << increment_size;
|
s390_sclp_init();
|
||||||
|
my_ram_size = machine->ram_size;
|
||||||
/* let's propagate the changed ram size into the global variable. */
|
|
||||||
ram_size = my_ram_size;
|
|
||||||
|
|
||||||
/* get a BUS */
|
/* get a BUS */
|
||||||
s390_bus = s390_virtio_bus_init(&my_ram_size);
|
s390_bus = s390_virtio_bus_init(&my_ram_size);
|
||||||
s390_sclp_init();
|
|
||||||
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
|
s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline,
|
||||||
machine->initrd_filename, ZIPL_FILENAME, false);
|
machine->initrd_filename, ZIPL_FILENAME, false);
|
||||||
s390_flic_init();
|
s390_flic_init();
|
||||||
|
@ -292,9 +283,7 @@ static void s390_init(MachineState *machine)
|
||||||
s390_virtio_register_hcalls();
|
s390_virtio_register_hcalls();
|
||||||
|
|
||||||
/* allocate RAM */
|
/* allocate RAM */
|
||||||
memory_region_init_ram(ram, NULL, "s390.ram", my_ram_size, &error_abort);
|
s390_memory_init(my_ram_size);
|
||||||
vmstate_register_ram_global(ram);
|
|
||||||
memory_region_add_subregion(sysmem, 0, ram);
|
|
||||||
|
|
||||||
/* clear virtio region */
|
/* clear virtio region */
|
||||||
virtio_region_len = my_ram_size - ram_size;
|
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,
|
cpu_physical_memory_unmap(virtio_region, virtio_region_len, 1,
|
||||||
virtio_region_len);
|
virtio_region_len);
|
||||||
|
|
||||||
/* Initialize storage key device */
|
|
||||||
s390_skeys_init();
|
|
||||||
|
|
||||||
/* init CPUs */
|
/* init CPUs */
|
||||||
s390_init_cpus(machine->cpu_model);
|
s390_init_cpus(machine->cpu_model);
|
||||||
|
|
||||||
|
|
|
@ -27,4 +27,5 @@ void s390_init_ipl_dev(const char *kernel_filename,
|
||||||
bool enforce_bios);
|
bool enforce_bios);
|
||||||
void s390_create_virtio_net(BusState *bus, const char *name);
|
void s390_create_virtio_net(BusState *bus, const char *name);
|
||||||
void s390_nmi(NMIState *n, int cpu_index, Error **errp);
|
void s390_nmi(NMIState *n, int cpu_index, Error **errp);
|
||||||
|
void s390_memory_init(ram_addr_t mem_size);
|
||||||
#endif
|
#endif
|
||||||
|
|
267
hw/s390x/sclp.c
267
hw/s390x/sclp.c
|
@ -17,37 +17,27 @@
|
||||||
#include "exec/memory.h"
|
#include "exec/memory.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
#include "qemu/config-file.h"
|
#include "hw/boards.h"
|
||||||
#include "hw/s390x/sclp.h"
|
#include "hw/s390x/sclp.h"
|
||||||
#include "hw/s390x/event-facility.h"
|
#include "hw/s390x/event-facility.h"
|
||||||
#include "hw/s390x/s390-pci-bus.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(),
|
return SCLP(object_resolve_path_type("", TYPE_SCLP, NULL));
|
||||||
TYPE_SCLP_EVENT_FACILITY,
|
|
||||||
NULL);
|
|
||||||
assert(op);
|
|
||||||
return op->opaque;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Provide information about the configuration, CPUs and storage */
|
/* 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;
|
ReadInfo *read_info = (ReadInfo *) sccb;
|
||||||
|
MachineState *machine = MACHINE(qdev_get_machine());
|
||||||
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
|
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
|
||||||
CPUState *cpu;
|
CPUState *cpu;
|
||||||
int cpu_count = 0;
|
int cpu_count = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int increment_size = 20;
|
|
||||||
int rnsize, rnmax;
|
int rnsize, rnmax;
|
||||||
QemuOpts *opts = qemu_opts_find(qemu_find_opts("memory"), NULL);
|
int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state));
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
CPU_FOREACH(cpu) {
|
CPU_FOREACH(cpu) {
|
||||||
cpu_count++;
|
cpu_count++;
|
||||||
|
@ -66,23 +56,8 @@ static void read_SCP_info(SCCB *sccb)
|
||||||
read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO |
|
read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO |
|
||||||
SCLP_HAS_PCI_RECONFIG);
|
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 */
|
/* Memory Hotplug is only supported for the ccw machine type */
|
||||||
if (mhd) {
|
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;
|
mhd->standby_subregion_size = MEM_SECTION_SIZE;
|
||||||
/* Deduct the memory slot already used for core */
|
/* Deduct the memory slot already used for core */
|
||||||
if (slots > 0) {
|
if (slots > 0) {
|
||||||
|
@ -108,13 +83,11 @@ static void read_SCP_info(SCCB *sccb)
|
||||||
}
|
}
|
||||||
mhd->padded_ram_size = ram_size + mhd->pad_size;
|
mhd->padded_ram_size = ram_size + mhd->pad_size;
|
||||||
mhd->rzm = 1 << mhd->increment_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);
|
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) {
|
if (rnsize <= 128) {
|
||||||
read_info->rnsize = rnsize;
|
read_info->rnsize = rnsize;
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,6 +95,7 @@ static void read_SCP_info(SCCB *sccb)
|
||||||
read_info->rnsize2 = cpu_to_be32(rnsize);
|
read_info->rnsize2 = cpu_to_be32(rnsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rnmax = machine->maxram_size >> sclp->increment_size;
|
||||||
if (rnmax < 0x10000) {
|
if (rnmax < 0x10000) {
|
||||||
read_info->rnmax = cpu_to_be16(rnmax);
|
read_info->rnmax = cpu_to_be16(rnmax);
|
||||||
} else {
|
} else {
|
||||||
|
@ -132,14 +106,17 @@ static void read_SCP_info(SCCB *sccb)
|
||||||
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
|
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 i, assigned;
|
||||||
int subincrement_id = SCLP_STARTING_SUBINCREMENT_ID;
|
int subincrement_id = SCLP_STARTING_SUBINCREMENT_ID;
|
||||||
ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb;
|
ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb;
|
||||||
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
|
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) {
|
if ((ram_size >> mhd->increment_size) >= 0x10000) {
|
||||||
sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
|
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);
|
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;
|
ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb;
|
||||||
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
|
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) {
|
if ((mhd->standby_mem_size >> mhd->increment_size) >= 0x10000) {
|
||||||
sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
|
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);
|
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;
|
int i, assigned, subincrement_id;
|
||||||
AttachStorageElement *attach_info = (AttachStorageElement *) sccb;
|
AttachStorageElement *attach_info = (AttachStorageElement *) sccb;
|
||||||
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
|
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) {
|
if (element != 1) {
|
||||||
sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
|
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);
|
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;
|
MemoryRegion *mr = NULL;
|
||||||
uint64_t this_subregion_size;
|
uint64_t this_subregion_size;
|
||||||
AssignStorage *assign_info = (AssignStorage *) sccb;
|
AssignStorage *assign_info = (AssignStorage *) sccb;
|
||||||
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
|
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
|
||||||
assert(mhd);
|
ram_addr_t assign_addr;
|
||||||
ram_addr_t assign_addr = (assign_info->rn - 1) * mhd->rzm;
|
|
||||||
MemoryRegion *sysmem = get_system_memory();
|
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) &&
|
if ((assign_addr % MEM_SECTION_SIZE == 0) &&
|
||||||
(assign_addr >= mhd->padded_ram_size)) {
|
(assign_addr >= mhd->padded_ram_size)) {
|
||||||
/* Re-use existing memory region if found */
|
/* Re-use existing memory region if found */
|
||||||
mr = memory_region_find(sysmem, assign_addr, 1).mr;
|
mr = memory_region_find(sysmem, assign_addr, 1).mr;
|
||||||
|
memory_region_unref(mr);
|
||||||
if (!mr) {
|
if (!mr) {
|
||||||
|
|
||||||
MemoryRegion *standby_ram = g_new(MemoryRegion, 1);
|
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);
|
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);
|
vmstate_register_ram_global(standby_ram);
|
||||||
memory_region_add_subregion(sysmem, offset, 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);
|
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;
|
MemoryRegion *mr = NULL;
|
||||||
AssignStorage *assign_info = (AssignStorage *) sccb;
|
AssignStorage *assign_info = (AssignStorage *) sccb;
|
||||||
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
|
sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev();
|
||||||
assert(mhd);
|
ram_addr_t unassign_addr;
|
||||||
ram_addr_t unassign_addr = (assign_info->rn - 1) * mhd->rzm;
|
|
||||||
MemoryRegion *sysmem = get_system_memory();
|
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 the addr is a multiple of 256 MB */
|
||||||
if ((unassign_addr % MEM_SECTION_SIZE == 0) &&
|
if ((unassign_addr % MEM_SECTION_SIZE == 0) &&
|
||||||
(unassign_addr >= mhd->padded_ram_size)) {
|
(unassign_addr >= mhd->padded_ram_size)) {
|
||||||
|
@ -269,6 +269,7 @@ static void unassign_storage(SCCB *sccb)
|
||||||
|
|
||||||
/* find the specified memory region and destroy it */
|
/* find the specified memory region and destroy it */
|
||||||
mr = memory_region_find(sysmem, unassign_addr, 1).mr;
|
mr = memory_region_find(sysmem, unassign_addr, 1).mr;
|
||||||
|
memory_region_unref(mr);
|
||||||
if (mr) {
|
if (mr) {
|
||||||
int i;
|
int i;
|
||||||
int is_removable = 1;
|
int is_removable = 1;
|
||||||
|
@ -287,8 +288,7 @@ static void unassign_storage(SCCB *sccb)
|
||||||
}
|
}
|
||||||
if (is_removable) {
|
if (is_removable) {
|
||||||
memory_region_del_subregion(sysmem, mr);
|
memory_region_del_subregion(sysmem, mr);
|
||||||
object_unparent(OBJECT(mr));
|
object_unref(OBJECT(mr));
|
||||||
g_free(mr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,7 +296,7 @@ static void unassign_storage(SCCB *sccb)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Provide information about the CPU */
|
/* 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;
|
ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb;
|
||||||
CPUState *cpu;
|
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);
|
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);
|
SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
|
||||||
|
|
||||||
switch (code & SCLP_CMD_CODE_MASK) {
|
switch (code & SCLP_CMD_CODE_MASK) {
|
||||||
case SCLP_CMDW_READ_SCP_INFO:
|
case SCLP_CMDW_READ_SCP_INFO:
|
||||||
case SCLP_CMDW_READ_SCP_INFO_FORCED:
|
case SCLP_CMDW_READ_SCP_INFO_FORCED:
|
||||||
read_SCP_info(sccb);
|
sclp_c->read_SCP_info(sclp, sccb);
|
||||||
break;
|
break;
|
||||||
case SCLP_CMDW_READ_CPU_INFO:
|
case SCLP_CMDW_READ_CPU_INFO:
|
||||||
sclp_read_cpu_info(sccb);
|
sclp_c->read_cpu_info(sclp, sccb);
|
||||||
break;
|
break;
|
||||||
case SCLP_READ_STORAGE_ELEMENT_INFO:
|
case SCLP_READ_STORAGE_ELEMENT_INFO:
|
||||||
if (code & 0xff00) {
|
if (code & 0xff00) {
|
||||||
read_storage_element1_info(sccb);
|
sclp_c->read_storage_element1_info(sclp, sccb);
|
||||||
} else {
|
} else {
|
||||||
read_storage_element0_info(sccb);
|
sclp_c->read_storage_element0_info(sclp, sccb);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SCLP_ATTACH_STORAGE_ELEMENT:
|
case SCLP_ATTACH_STORAGE_ELEMENT:
|
||||||
attach_storage_element(sccb, (code & 0xff00) >> 8);
|
sclp_c->attach_storage_element(sclp, sccb, (code & 0xff00) >> 8);
|
||||||
break;
|
break;
|
||||||
case SCLP_ASSIGN_STORAGE:
|
case SCLP_ASSIGN_STORAGE:
|
||||||
assign_storage(sccb);
|
sclp_c->assign_storage(sclp, sccb);
|
||||||
break;
|
break;
|
||||||
case SCLP_UNASSIGN_STORAGE:
|
case SCLP_UNASSIGN_STORAGE:
|
||||||
unassign_storage(sccb);
|
sclp_c->unassign_storage(sclp, sccb);
|
||||||
break;
|
break;
|
||||||
case SCLP_CMDW_CONFIGURE_PCI:
|
case SCLP_CMDW_CONFIGURE_PCI:
|
||||||
s390_pci_sclp_configure(1, sccb);
|
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)
|
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;
|
int r = 0;
|
||||||
SCCB work_sccb;
|
SCCB work_sccb;
|
||||||
|
|
||||||
|
@ -400,20 +403,20 @@ int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
sclp_execute((SCCB *)&work_sccb, code);
|
sclp_c->execute(sclp, (SCCB *)&work_sccb, code);
|
||||||
|
|
||||||
cpu_physical_memory_write(sccb, &work_sccb,
|
cpu_physical_memory_write(sccb, &work_sccb,
|
||||||
be16_to_cpu(work_sccb.h.length));
|
be16_to_cpu(work_sccb.h.length));
|
||||||
|
|
||||||
sclp_service_interrupt(sccb);
|
sclp_c->service_interrupt(sclp, sccb);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return r;
|
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);
|
SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
|
||||||
|
|
||||||
uint32_t param = sccb & ~3;
|
uint32_t param = sccb & ~3;
|
||||||
|
@ -428,17 +431,148 @@ void sclp_service_interrupt(uint32_t sccb)
|
||||||
s390_sclp_extint(param);
|
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 */
|
/* qemu object creation and initialization functions */
|
||||||
|
|
||||||
void s390_sclp_init(void)
|
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_property_add_child(qdev_get_machine(), TYPE_SCLP, new,
|
||||||
OBJECT(dev), NULL);
|
NULL);
|
||||||
qdev_init_nofail(dev);
|
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)
|
sclpMemoryHotplugDev *init_sclp_memory_hotplug_dev(void)
|
||||||
{
|
{
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
|
@ -475,5 +609,6 @@ static TypeInfo sclp_memory_hotplug_dev_info = {
|
||||||
static void register_types(void)
|
static void register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&sclp_memory_hotplug_dev_info);
|
type_register_static(&sclp_memory_hotplug_dev_info);
|
||||||
|
type_register_static(&sclp_info);
|
||||||
}
|
}
|
||||||
type_init(register_types);
|
type_init(register_types);
|
||||||
|
|
|
@ -25,13 +25,16 @@ typedef struct ConfigMgtData {
|
||||||
uint8_t event_qualifier;
|
uint8_t event_qualifier;
|
||||||
} QEMU_PACKED ConfigMgtData;
|
} QEMU_PACKED ConfigMgtData;
|
||||||
|
|
||||||
static qemu_irq *irq_cpu_hotplug; /* Only used in this file */
|
|
||||||
|
|
||||||
#define EVENT_QUAL_CPU_CHANGE 1
|
#define EVENT_QUAL_CPU_CHANGE 1
|
||||||
|
|
||||||
void raise_irq_cpu_hotplug(void)
|
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)
|
static unsigned int send_mask(void)
|
||||||
|
@ -70,36 +73,19 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
|
||||||
return 1;
|
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)
|
static void cpu_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
SCLPEventClass *k = SCLP_EVENT_CLASS(oc);
|
SCLPEventClass *k = SCLP_EVENT_CLASS(oc);
|
||||||
DeviceClass *dc = DEVICE_CLASS(oc);
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||||
|
|
||||||
k->init = irq_cpu_hotplug_init;
|
|
||||||
k->get_send_mask = send_mask;
|
k->get_send_mask = send_mask;
|
||||||
k->get_receive_mask = receive_mask;
|
k->get_receive_mask = receive_mask;
|
||||||
k->read_event_data = read_event_data;
|
k->read_event_data = read_event_data;
|
||||||
k->write_event_data = NULL;
|
|
||||||
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo sclp_cpu_info = {
|
static const TypeInfo sclp_cpu_info = {
|
||||||
.name = "sclp-cpu-hotplug",
|
.name = TYPE_SCLP_CPU_HOTPLUG,
|
||||||
.parent = TYPE_SCLP_EVENT,
|
.parent = TYPE_SCLP_EVENT,
|
||||||
.instance_size = sizeof(SCLPEvent),
|
.instance_size = sizeof(SCLPEvent),
|
||||||
.class_init = cpu_class_init,
|
.class_init = cpu_class_init,
|
||||||
|
|
|
@ -66,7 +66,7 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
|
||||||
}
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_sclpquiesce = {
|
static const VMStateDescription vmstate_sclpquiesce = {
|
||||||
.name = "sclpquiesce",
|
.name = TYPE_SCLP_QUIESCE,
|
||||||
.version_id = 0,
|
.version_id = 0,
|
||||||
.minimum_version_id = 0,
|
.minimum_version_id = 0,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
|
@ -127,7 +127,7 @@ static void quiesce_class_init(ObjectClass *klass, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo sclp_quiesce_info = {
|
static const TypeInfo sclp_quiesce_info = {
|
||||||
.name = "sclpquiesce",
|
.name = TYPE_SCLP_QUIESCE,
|
||||||
.parent = TYPE_SCLP_EVENT,
|
.parent = TYPE_SCLP_EVENT,
|
||||||
.instance_size = sizeof(SCLPEvent),
|
.instance_size = sizeof(SCLPEvent),
|
||||||
.class_init = quiesce_class_init,
|
.class_init = quiesce_class_init,
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT)
|
OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT)
|
||||||
|
|
||||||
#define TYPE_SCLP_CPU_HOTPLUG "sclp-cpu-hotplug"
|
#define TYPE_SCLP_CPU_HOTPLUG "sclp-cpu-hotplug"
|
||||||
|
#define TYPE_SCLP_QUIESCE "sclpquiesce"
|
||||||
|
|
||||||
typedef struct WriteEventMask {
|
typedef struct WriteEventMask {
|
||||||
SCCBHeader h;
|
SCCBHeader h;
|
||||||
|
@ -146,8 +147,10 @@ typedef struct WriteEventData {
|
||||||
|
|
||||||
typedef struct ReadEventData {
|
typedef struct ReadEventData {
|
||||||
SCCBHeader h;
|
SCCBHeader h;
|
||||||
EventBufferHeader ebh;
|
union {
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
|
EventBufferHeader ebh;
|
||||||
|
};
|
||||||
} QEMU_PACKED ReadEventData;
|
} QEMU_PACKED ReadEventData;
|
||||||
|
|
||||||
typedef struct SCLPEvent {
|
typedef struct SCLPEvent {
|
||||||
|
@ -186,11 +189,8 @@ typedef struct SCLPEventClass {
|
||||||
OBJECT_GET_CLASS(SCLPEventFacilityClass, (obj), \
|
OBJECT_GET_CLASS(SCLPEventFacilityClass, (obj), \
|
||||||
TYPE_SCLP_EVENT_FACILITY)
|
TYPE_SCLP_EVENT_FACILITY)
|
||||||
|
|
||||||
typedef struct SCLPEventFacility SCLPEventFacility;
|
|
||||||
|
|
||||||
typedef struct SCLPEventFacilityClass {
|
typedef struct SCLPEventFacilityClass {
|
||||||
DeviceClass parent_class;
|
SysBusDeviceClass parent_class;
|
||||||
int (*init)(SCLPEventFacility *ef);
|
|
||||||
void (*command_handler)(SCLPEventFacility *ef, SCCB *sccb, uint64_t code);
|
void (*command_handler)(SCLPEventFacility *ef, SCCB *sccb, uint64_t code);
|
||||||
bool (*event_pending)(SCLPEventFacility *ef);
|
bool (*event_pending)(SCLPEventFacility *ef);
|
||||||
} SCLPEventFacilityClass;
|
} SCLPEventFacilityClass;
|
||||||
|
|
|
@ -163,6 +163,39 @@ typedef struct SCCB {
|
||||||
char data[SCCB_DATA_LEN];
|
char data[SCCB_DATA_LEN];
|
||||||
} QEMU_PACKED SCCB;
|
} 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;
|
typedef struct sclpMemoryHotplugDev sclpMemoryHotplugDev;
|
||||||
|
|
||||||
#define TYPE_SCLP_MEMORY_HOTPLUG_DEV "sclp-memory-hotplug-dev"
|
#define TYPE_SCLP_MEMORY_HOTPLUG_DEV "sclp-memory-hotplug-dev"
|
||||||
|
|
|
@ -1293,7 +1293,6 @@ int kvm_irqchip_add_adapter_route(KVMState *s, AdapterInfo *adapter)
|
||||||
kroute.u.adapter.adapter_id = adapter->adapter_id;
|
kroute.u.adapter.adapter_id = adapter->adapter_id;
|
||||||
|
|
||||||
kvm_add_routing_entry(s, &kroute);
|
kvm_add_routing_entry(s, &kroute);
|
||||||
kvm_irqchip_commit_routes(s);
|
|
||||||
|
|
||||||
return virq;
|
return virq;
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
|
@ -38,40 +38,56 @@ void virtio_panic(const char *string)
|
||||||
while (1) { }
|
while (1) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
static void virtio_setup(uint64_t dev_info)
|
static bool find_dev(struct schib *schib, int dev_no)
|
||||||
{
|
{
|
||||||
struct schib schib;
|
int i, r;
|
||||||
int i;
|
|
||||||
int r;
|
|
||||||
bool found = false;
|
|
||||||
bool check_devno = false;
|
|
||||||
uint16_t dev_no = -1;
|
|
||||||
|
|
||||||
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++) {
|
for (i = 0; i < 0x10000; i++) {
|
||||||
blk_schid.sch_no = i;
|
blk_schid.sch_no = i;
|
||||||
r = stsch_err(blk_schid, &schib);
|
r = stsch_err(blk_schid, schib);
|
||||||
if (r == 3) {
|
if ((r == 3) || (r == -EIO)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (schib.pmcw.dnv) {
|
if (!schib->pmcw.dnv) {
|
||||||
if (!check_devno || (schib.pmcw.dev == dev_no)) {
|
continue;
|
||||||
if (virtio_is_blk(blk_schid)) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
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 ssid;
|
||||||
|
bool found = false;
|
||||||
|
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) {
|
||||||
|
dev_no = dev_info & 0xffff;
|
||||||
|
debug_print_int("device no. ", dev_no);
|
||||||
|
blk_schid.ssid = (dev_info >> 16) & 0x3;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
void s390_cpu_gdb_init(CPUState *cs)
|
||||||
{
|
{
|
||||||
gdb_register_coprocessor(cs, cpu_read_ac_reg,
|
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,
|
gdb_register_coprocessor(cs, cpu_read_vreg,
|
||||||
cpu_write_vreg,
|
cpu_write_vreg,
|
||||||
S390_NUM_VREGS, "s390-vx.xml", 0);
|
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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue