aboutsummaryrefslogtreecommitdiff
path: root/hw/s390x
diff options
context:
space:
mode:
Diffstat (limited to 'hw/s390x')
-rw-r--r--hw/s390x/event-facility.c81
-rw-r--r--hw/s390x/s390-virtio-ccw.c8
2 files changed, 75 insertions, 14 deletions
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index 79de3c7..feef6f7 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -31,6 +31,15 @@ struct SCLPEventFacility {
SCLPEventsBus sbus;
/* guest' receive mask */
unsigned int 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
+ * the architecture correctly, allowing all valid mask sizes. Needed for
+ * migration toward older versions.
+ */
+ bool allow_all_mask_sizes;
+ /* length of the receive mask */
+ uint16_t mask_length;
};
/* return true if any child has event pending set */
@@ -220,6 +229,17 @@ static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb,
return rc;
}
+/* copy up to src_len bytes and fill the rest of dst with zeroes */
+static void copy_mask(uint8_t *dst, uint8_t *src, uint16_t dst_len,
+ uint16_t src_len)
+{
+ int i;
+
+ for (i = 0; i < dst_len; i++) {
+ dst[i] = i < src_len ? src[i] : 0;
+ }
+}
+
static void read_event_data(SCLPEventFacility *ef, SCCB *sccb)
{
unsigned int sclp_active_selection_mask;
@@ -240,7 +260,9 @@ static void read_event_data(SCLPEventFacility *ef, SCCB *sccb)
sclp_active_selection_mask = sclp_cp_receive_mask;
break;
case SCLP_SELECTIVE_READ:
- sclp_active_selection_mask = be32_to_cpu(red->mask);
+ 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);
if (!sclp_cp_receive_mask ||
(sclp_active_selection_mask & ~sclp_cp_receive_mask)) {
sccb->h.response_code =
@@ -259,24 +281,14 @@ out:
return;
}
-/* copy up to dst_len bytes and fill the rest of dst with zeroes */
-static void copy_mask(uint8_t *dst, uint8_t *src, uint16_t dst_len,
- uint16_t src_len)
-{
- int i;
-
- for (i = 0; i < dst_len; i++) {
- dst[i] = i < src_len ? src[i] : 0;
- }
-}
-
static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb)
{
WriteEventMask *we_mask = (WriteEventMask *) sccb;
uint16_t mask_length = be16_to_cpu(we_mask->mask_length);
uint32_t tmp_mask;
- if (!mask_length || (mask_length > SCLP_EVENT_MASK_LEN_MAX)) {
+ if (!mask_length || (mask_length > SCLP_EVENT_MASK_LEN_MAX) ||
+ ((mask_length != 4) && !ef->allow_all_mask_sizes)) {
sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH);
goto out;
}
@@ -301,6 +313,7 @@ static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb)
mask_length, sizeof(tmp_mask));
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
+ ef->mask_length = mask_length;
out:
return;
@@ -356,6 +369,24 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
}
}
+static bool vmstate_event_facility_mask_length_needed(void *opaque)
+{
+ SCLPEventFacility *ef = opaque;
+
+ return ef->allow_all_mask_sizes;
+}
+
+static const VMStateDescription vmstate_event_facility_mask_length = {
+ .name = "vmstate-event-facility/mask_length",
+ .version_id = 0,
+ .minimum_version_id = 0,
+ .needed = vmstate_event_facility_mask_length_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT16(mask_length, SCLPEventFacility),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_event_facility = {
.name = "vmstate-event-facility",
.version_id = 0,
@@ -363,15 +394,39 @@ static const VMStateDescription vmstate_event_facility = {
.fields = (VMStateField[]) {
VMSTATE_UINT32(receive_mask, SCLPEventFacility),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (const VMStateDescription * []) {
+ &vmstate_event_facility_mask_length,
+ NULL
}
};
+static void sclp_event_set_allow_all_mask_sizes(Object *obj, bool value,
+ Error **errp)
+{
+ SCLPEventFacility *ef = (SCLPEventFacility *)obj;
+
+ ef->allow_all_mask_sizes = value;
+}
+
+static bool sclp_event_get_allow_all_mask_sizes(Object *obj, Error **e)
+{
+ SCLPEventFacility *ef = (SCLPEventFacility *)obj;
+
+ return ef->allow_all_mask_sizes;
+}
+
static void init_event_facility(Object *obj)
{
SCLPEventFacility *event_facility = EVENT_FACILITY(obj);
DeviceState *sdev = DEVICE(obj);
Object *new;
+ event_facility->mask_length = 4;
+ event_facility->allow_all_mask_sizes = true;
+ object_property_add_bool(obj, "allow_all_mask_sizes",
+ sclp_event_get_allow_all_mask_sizes,
+ sclp_event_set_allow_all_mask_sizes, NULL);
/* Spawn a new bus for SCLP events */
qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus),
TYPE_SCLP_EVENTS_BUS, sdev, NULL);
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index f822704..864145a 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -27,6 +27,7 @@
#include "s390-pci-bus.h"
#include "hw/s390x/storage-keys.h"
#include "hw/s390x/storage-attributes.h"
+#include "hw/s390x/event-facility.h"
#include "hw/compat.h"
#include "ipl.h"
#include "hw/s390x/s390-virtio-ccw.h"
@@ -668,7 +669,12 @@ bool css_migration_enabled(void)
type_init(ccw_machine_register_##suffix)
#define CCW_COMPAT_2_11 \
- HW_COMPAT_2_11
+ HW_COMPAT_2_11 \
+ {\
+ .driver = TYPE_SCLP_EVENT_FACILITY,\
+ .property = "allow_all_mask_sizes",\
+ .value = "off",\
+ },
#define CCW_COMPAT_2_10 \
HW_COMPAT_2_10