aboutsummaryrefslogtreecommitdiff
path: root/hw/s390x
diff options
context:
space:
mode:
Diffstat (limited to 'hw/s390x')
-rw-r--r--hw/s390x/event-facility.c64
-rw-r--r--hw/s390x/ipl.c4
-rw-r--r--hw/s390x/s390-pci-inst.c8
-rw-r--r--hw/s390x/s390-virtio-ccw.c36
4 files changed, 92 insertions, 20 deletions
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index 9c24bc6f7c..ee5b83448b 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -26,11 +26,23 @@ typedef struct SCLPEventsBus {
BusState qbus;
} SCLPEventsBus;
+/* we need to save 32 bit chunks for compatibility */
+#ifdef HOST_WORDS_BIGENDIAN
+#define RECV_MASK_LOWER 1
+#define RECV_MASK_UPPER 0
+#else /* little endian host */
+#define RECV_MASK_LOWER 0
+#define RECV_MASK_UPPER 1
+#endif
+
struct SCLPEventFacility {
SysBusDevice parent_obj;
SCLPEventsBus sbus;
/* guest's receive mask */
- sccb_mask_t receive_mask;
+ union {
+ uint32_t receive_mask_pieces[2];
+ sccb_mask_t receive_mask;
+ };
/*
* when false, we keep the same broken, backwards compatible behaviour as
* before, allowing only masks of size exactly 4; when true, we implement
@@ -262,7 +274,7 @@ static void read_event_data(SCLPEventFacility *ef, SCCB *sccb)
case SCLP_SELECTIVE_READ:
copy_mask((uint8_t *)&sclp_active_selection_mask, (uint8_t *)&red->mask,
sizeof(sclp_active_selection_mask), ef->mask_length);
- sclp_active_selection_mask = be32_to_cpu(sclp_active_selection_mask);
+ sclp_active_selection_mask = be64_to_cpu(sclp_active_selection_mask);
if (!sclp_cp_receive_mask ||
(sclp_active_selection_mask & ~sclp_cp_receive_mask)) {
sccb->h.response_code =
@@ -294,21 +306,22 @@ static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb)
}
/*
- * Note: We currently only support masks up to 4 byte length;
- * the remainder is filled up with zeroes. Linux uses
- * a 4 byte mask length.
+ * Note: We currently only support masks up to 8 byte length;
+ * the remainder is filled up with zeroes. Older Linux
+ * kernels use a 4 byte mask length, newer ones can use both
+ * 8 or 4 depending on what is available on the host.
*/
/* keep track of the guest's capability masks */
copy_mask((uint8_t *)&tmp_mask, WEM_CP_RECEIVE_MASK(we_mask, mask_length),
sizeof(tmp_mask), mask_length);
- ef->receive_mask = be32_to_cpu(tmp_mask);
+ ef->receive_mask = be64_to_cpu(tmp_mask);
/* return the SCLP's capability masks to the guest */
- tmp_mask = cpu_to_be32(get_host_receive_mask(ef));
+ tmp_mask = cpu_to_be64(get_host_receive_mask(ef));
copy_mask(WEM_RECEIVE_MASK(we_mask, mask_length), (uint8_t *)&tmp_mask,
mask_length, sizeof(tmp_mask));
- tmp_mask = cpu_to_be32(get_host_send_mask(ef));
+ tmp_mask = cpu_to_be64(get_host_send_mask(ef));
copy_mask(WEM_SEND_MASK(we_mask, mask_length), (uint8_t *)&tmp_mask,
mask_length, sizeof(tmp_mask));
@@ -369,6 +382,13 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
}
}
+static bool vmstate_event_facility_mask64_needed(void *opaque)
+{
+ SCLPEventFacility *ef = opaque;
+
+ return (ef->receive_mask & 0xFFFFFFFF) != 0;
+}
+
static bool vmstate_event_facility_mask_length_needed(void *opaque)
{
SCLPEventFacility *ef = opaque;
@@ -376,6 +396,17 @@ static bool vmstate_event_facility_mask_length_needed(void *opaque)
return ef->allow_all_mask_sizes;
}
+static const VMStateDescription vmstate_event_facility_mask64 = {
+ .name = "vmstate-event-facility/mask64",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .needed = vmstate_event_facility_mask64_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(receive_mask_pieces[RECV_MASK_LOWER], SCLPEventFacility),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_event_facility_mask_length = {
.name = "vmstate-event-facility/mask_length",
.version_id = 0,
@@ -392,10 +423,11 @@ static const VMStateDescription vmstate_event_facility = {
.version_id = 0,
.minimum_version_id = 0,
.fields = (VMStateField[]) {
- VMSTATE_UINT32(receive_mask, SCLPEventFacility),
+ VMSTATE_UINT32(receive_mask_pieces[RECV_MASK_UPPER], SCLPEventFacility),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * []) {
+ &vmstate_event_facility_mask64,
&vmstate_event_facility_mask_length,
NULL
}
@@ -511,3 +543,17 @@ static void register_types(void)
}
type_init(register_types)
+
+BusState *sclp_get_event_facility_bus(void)
+{
+ Object *busobj;
+ SCLPEventsBus *sbus;
+
+ busobj = object_resolve_path_type("", TYPE_SCLP_EVENTS_BUS, NULL);
+ sbus = OBJECT_CHECK(SCLPEventsBus, busobj, TYPE_SCLP_EVENTS_BUS);
+ if (!sbus) {
+ return NULL;
+ }
+
+ return &sbus->qbus;
+}
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index fb554ab156..150f6c0582 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -373,6 +373,10 @@ int s390_ipl_set_loadparm(uint8_t *loadparm)
loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]];
}
+ if (i < 8) {
+ memset(loadparm + i, 0x40, 8 - i); /* fill with EBCDIC spaces */
+ }
+
g_free(lp);
return 0;
}
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index 3fcc330fe3..02a815fd31 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -155,8 +155,6 @@ int clp_service_call(S390CPU *cpu, uint8_t r2, uintptr_t ra)
S390pciState *s = s390_get_phb();
int i;
- cpu_synchronize_state(CPU(cpu));
-
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
return 0;
@@ -389,8 +387,6 @@ int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
uint32_t fh;
uint8_t pcias;
- cpu_synchronize_state(CPU(cpu));
-
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
return 0;
@@ -487,8 +483,6 @@ int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
uint32_t fh;
uint8_t pcias;
- cpu_synchronize_state(CPU(cpu));
-
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
return 0;
@@ -620,8 +614,6 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
S390IOTLBEntry entry;
hwaddr start, end;
- cpu_synchronize_state(CPU(cpu));
-
if (env->psw.mask & PSW_MASK_PSTATE) {
s390_program_interrupt(env, PGM_PRIVILEGED, 4, ra);
return 0;
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 435f7c99e7..100dfdc96d 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -288,6 +288,15 @@ static void s390_create_virtio_net(BusState *bus, const char *name)
}
}
+static void s390_create_sclpconsole(const char *type, Chardev *chardev)
+{
+ DeviceState *dev;
+
+ dev = qdev_create(sclp_get_event_facility_bus(), type);
+ qdev_prop_set_chr(dev, "chardev", chardev);
+ qdev_init_nofail(dev);
+}
+
static void ccw_init(MachineState *machine)
{
int ret;
@@ -346,6 +355,14 @@ static void ccw_init(MachineState *machine)
/* Create VirtIO network adapters */
s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw");
+ /* init consoles */
+ if (serial_hd(0)) {
+ s390_create_sclpconsole("sclpconsole", serial_hd(0));
+ }
+ if (serial_hd(1)) {
+ s390_create_sclpconsole("sclplmconsole", serial_hd(1));
+ }
+
/* Register savevm handler for guest TOD clock */
register_savevm_live(NULL, "todclock", 0, 1, &savevm_gtod, NULL);
}
@@ -470,10 +487,8 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
mc->block_default_type = IF_VIRTIO;
mc->no_cdrom = 1;
mc->no_floppy = 1;
- mc->no_serial = 1;
mc->no_parallel = 1;
mc->no_sdcard = 1;
- mc->use_sclp = 1;
mc->max_cpus = S390_MAX_CPUS;
mc->has_hotpluggable_cpus = true;
mc->get_hotplug_handler = s390_get_hotplug_handler;
@@ -671,6 +686,9 @@ bool css_migration_enabled(void)
} \
type_init(ccw_machine_register_##suffix)
+#define CCW_COMPAT_2_12 \
+ HW_COMPAT_2_12
+
#define CCW_COMPAT_2_11 \
HW_COMPAT_2_11 \
{\
@@ -756,14 +774,26 @@ bool css_migration_enabled(void)
.value = "0",\
},
+static void ccw_machine_2_13_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_2_13_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE(2_13, "2.13", true);
+
static void ccw_machine_2_12_instance_options(MachineState *machine)
{
+ ccw_machine_2_13_instance_options(machine);
}
static void ccw_machine_2_12_class_options(MachineClass *mc)
{
+ ccw_machine_2_13_class_options(mc);
+ SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_12);
}
-DEFINE_CCW_MACHINE(2_12, "2.12", true);
+DEFINE_CCW_MACHINE(2_12, "2.12", false);
static void ccw_machine_2_11_instance_options(MachineState *machine)
{