* [Qemu-devel] [PATCH 0/4 v4] s390: sclp patch set
@ 2012-08-20 14:28 Jens Freimann
2012-08-20 14:28 ` [Qemu-devel] [PATCH 1/4] s390: sclp base support Jens Freimann
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Jens Freimann @ 2012-08-20 14:28 UTC (permalink / raw)
To: Alexander Graf
Cc: Heinz Graalfs, qemu-devel, Einar Lueck, Christian Borntraeger,
Jens Freimann, Cornelia Huck, Andreas Faerber
This patch-set improves the Service-Call Logical Processor support for s390.
changes v3->v4:
- Event Facility was moved to the main system bus and we now keep the
event_facility pointer within the current machine's global property-list
as opaque pointer
- removed locking
- some code refactoring in response to Alexander Graf's and Andreas Faerber's
review comments (variables/functions renamed, return codes changed)
Patch 1 adds/changes some base SCLP support. Patch 2 adds code
to support the SCLP commands Write Event Mask, Write Event Data, and
Read Event Data. Patch 3 and 4 add code to implement the commands for the
particular SCLP events Signal Quiesce (system_powerdown), and ASCII Console
data.
Heinz Graalfs (4):
s390: sclp base support
s390: sclp event support
s390: sclp signal quiesce support
s390: sclp ascii console support
hw/s390-virtio.c | 4 +
hw/s390x/Makefile.objs | 3 +
hw/s390x/event-facility.c | 398 ++++++++++++++++++++++++++++++++++++++++++++++
hw/s390x/event-facility.h | 96 +++++++++++
hw/s390x/sclp.c | 152 ++++++++++++++++++
hw/s390x/sclp.h | 118 ++++++++++++++
hw/s390x/sclpconsole.c | 306 +++++++++++++++++++++++++++++++++++
hw/s390x/sclpquiesce.c | 112 +++++++++++++
target-s390x/cpu.h | 14 +-
target-s390x/kvm.c | 5 +-
target-s390x/op_helper.c | 31 +---
11 files changed, 1197 insertions(+), 42 deletions(-)
create mode 100644 hw/s390x/event-facility.c
create mode 100644 hw/s390x/event-facility.h
create mode 100644 hw/s390x/sclp.c
create mode 100644 hw/s390x/sclp.h
create mode 100644 hw/s390x/sclpconsole.c
create mode 100644 hw/s390x/sclpquiesce.c
--
1.7.11.5
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 1/4] s390: sclp base support
2012-08-20 14:28 [Qemu-devel] [PATCH 0/4 v4] s390: sclp patch set Jens Freimann
@ 2012-08-20 14:28 ` Jens Freimann
2012-09-26 15:00 ` Alexander Graf
2012-08-20 14:28 ` [Qemu-devel] [PATCH 2/4] s390: sclp event support Jens Freimann
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Jens Freimann @ 2012-08-20 14:28 UTC (permalink / raw)
To: Alexander Graf
Cc: Heinz Graalfs, qemu-devel, Einar Lueck, Christian Borntraeger,
Jens Freimann, Cornelia Huck, Andreas Faerber
From: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
This adds a more generic infrastructure for handling Service-Call
requests on s390. Currently we only support a small subset of Read
SCP Info directly in target-s390x. This patch provides the base
infrastructure for supporting more commands and moves Read SCP
Info.
In the future we could add additional commands for hotplug, call
home and event handling.
Signed-off-by: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
---
hw/s390x/Makefile.objs | 1 +
hw/s390x/sclp.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++
hw/s390x/sclp.h | 76 +++++++++++++++++++++++++++++++++
target-s390x/cpu.h | 14 +------
target-s390x/kvm.c | 5 +--
target-s390x/op_helper.c | 31 +++-----------
6 files changed, 192 insertions(+), 42 deletions(-)
create mode 100644 hw/s390x/sclp.c
create mode 100644 hw/s390x/sclp.h
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index dcdcac8..1c14b96 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -1,3 +1,4 @@
obj-y = s390-virtio-bus.o s390-virtio.o
obj-y := $(addprefix ../,$(obj-y))
+obj-y += sclp.o
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
new file mode 100644
index 0000000..322a0e2
--- /dev/null
+++ b/hw/s390x/sclp.c
@@ -0,0 +1,107 @@
+/*
+ * SCLP Support
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Christian Borntraeger <borntraeger@de.ibm.com>
+ * Heinz Graalfs <graalfs@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "cpu.h"
+#include "kvm.h"
+
+#include "sclp.h"
+
+/* Provide information about the configuration, CPUs and storage */
+static void read_SCP_info(SCCB *sccb)
+{
+ ReadInfo *read_info = (ReadInfo *) sccb;
+ int shift = 0;
+
+ while ((ram_size >> (20 + shift)) > 65535) {
+ shift++;
+ }
+ read_info->rnmax = cpu_to_be16(ram_size >> (20 + shift));
+ read_info->rnsize = 1 << shift;
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
+}
+
+static void sclp_execute(SCCB *sccb, uint64_t code)
+{
+ switch (code) {
+ case SCLP_CMDW_READ_SCP_INFO:
+ case SCLP_CMDW_READ_SCP_INFO_FORCED:
+ read_SCP_info(sccb);
+ break;
+ default:
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
+ break;
+ }
+}
+
+int do_sclp_service_call(uint32_t sccb, uint64_t code)
+{
+ int r = 0;
+ SCCB work_sccb;
+
+ target_phys_addr_t sccb_len = sizeof(SCCB);
+
+ /*
+ * we want to work on a private copy of the sccb, to prevent guests
+ * from playing dirty tricks by modifying the memory content after
+ * the host has checked the values
+ */
+ cpu_physical_memory_read(sccb, &work_sccb, sccb_len);
+
+ /* Valid sccb sizes */
+ if (be16_to_cpu(work_sccb.h.length) < 8 ||
+ be16_to_cpu(work_sccb.h.length) > 4096) {
+ r = -PGM_SPECIFICATION;
+ goto out;
+ }
+
+ sclp_execute((SCCB *)&work_sccb, code);
+
+ cpu_physical_memory_write(sccb, &work_sccb,
+ be16_to_cpu(work_sccb.h.length));
+
+ sclp_service_interrupt(sccb);
+
+out:
+ return r;
+}
+
+void sclp_service_interrupt(uint32_t sccb)
+{
+ s390_sclp_extint(sccb & ~3);
+}
+
+/* qemu object creation and initialization functions */
+
+static void s390_sclp_device_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *dc = SYS_BUS_DEVICE_CLASS(klass);
+
+ dc->init = s390_sclp_dev_init;
+}
+
+static TypeInfo s390_sclp_device_info = {
+ .name = TYPE_DEVICE_S390_SCLP,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(S390SCLPDevice),
+ .class_init = s390_sclp_device_class_init,
+ .class_size = sizeof(S390SCLPDeviceClass),
+ .abstract = true,
+};
+
+static void s390_sclp_register_types(void)
+{
+ type_register_static(&s390_sclp_device_info);
+}
+
+type_init(s390_sclp_register_types)
diff --git a/hw/s390x/sclp.h b/hw/s390x/sclp.h
new file mode 100644
index 0000000..e9ad42b
--- /dev/null
+++ b/hw/s390x/sclp.h
@@ -0,0 +1,76 @@
+/*
+ * SCLP Support
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Christian Borntraeger <borntraeger@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef HW_S390_SCLP_H
+#define HW_S390_SCLP_H
+
+#include <hw/sysbus.h>
+#include <hw/qdev.h>
+
+/* SCLP command codes */
+#define SCLP_CMDW_READ_SCP_INFO 0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
+
+/* SCLP response codes */
+#define SCLP_RC_NORMAL_READ_COMPLETION 0x0010
+#define SCLP_RC_INVALID_SCLP_COMMAND 0x01f0
+
+/* Service Call Control Block (SCCB) and its elements */
+
+#define SCCB_SIZE 4096
+
+/*
+ * Normally packed structures are not the right thing to do, since all code
+ * must take care of endianess. We cant use ldl_phys and friends for two
+ * reasons, though:
+ * - some of the embedded structures below the SCCB can appear multiple times
+ * at different locations, so there is no fixed offset
+ * - we work on a private copy of the SCCB, since there are several length
+ * fields, that would cause a security nightmare if we allow the guest to
+ * alter the structure while we parse it. We cannot use ldl_p and friends
+ * either without doing pointer arithmetics
+ * So we have to double check that all users of sclp data structures use the
+ * right endianess wrappers.
+ */
+typedef struct SCCBHeader {
+ uint16_t length;
+ uint8_t function_code;
+ uint8_t control_mask[3];
+ uint16_t response_code;
+} QEMU_PACKED SCCBHeader;
+
+#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader))
+
+typedef struct ReadInfo {
+ SCCBHeader h;
+ uint16_t rnmax;
+ uint8_t rnsize;
+} QEMU_PACKED ReadInfo;
+
+typedef struct SCCB {
+ SCCBHeader h;
+ char data[SCCB_DATA_LEN];
+ } QEMU_PACKED SCCB;
+
+typedef struct S390SCLPDevice {
+ SysBusDevice busdev;
+} S390SCLPDevice;
+
+typedef struct S390SCLPDeviceClass {
+ DeviceClass qdev;
+ int (*init)(S390SCLPDevice *sdev);
+} S390SCLPDeviceClass;
+
+void sclp_service_interrupt(uint32_t sccb);
+
+#endif
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index 18ac6e3..efd2cda 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -294,6 +294,7 @@ void s390x_tod_timer(void *opaque);
void s390x_cpu_timer(void *opaque);
int s390_virtio_hypercall(CPUS390XState *env, uint64_t mem, uint64_t hypercall);
+int do_sclp_service_call(uint32_t sccb, uint64_t code);
#ifdef CONFIG_KVM
void kvm_s390_interrupt(CPUS390XState *env, int type, uint32_t code);
@@ -596,17 +597,6 @@ static inline const char *cc_name(int cc_op)
return cc_names[cc_op];
}
-/* SCLP PV interface defines */
-#define SCLP_CMDW_READ_SCP_INFO 0x00020001
-#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
-
-#define SCP_LENGTH 0x00
-#define SCP_FUNCTION_CODE 0x02
-#define SCP_CONTROL_MASK 0x03
-#define SCP_RESPONSE_CODE 0x06
-#define SCP_MEM_CODE 0x08
-#define SCP_INCREMENT 0x0a
-
typedef struct LowCore
{
/* prefix area: defined by architecture */
@@ -955,7 +945,7 @@ static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
target_ulong *raddr, int *flags);
-int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code);
+int sclp_service_call(uint32_t sccb, uint64_t code);
uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
uint64_t vr);
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 07edf93..bcb6b2e 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -60,9 +60,6 @@
#define SIGP_STORE_STATUS_ADDR 0x0e
#define SIGP_SET_ARCH 0x12
-#define SCLP_CMDW_READ_SCP_INFO 0x00020001
-#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
-
const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
KVM_CAP_LAST_INFO
};
@@ -272,7 +269,7 @@ static int kvm_sclp_service_call(CPUS390XState *env, struct kvm_run *run,
sccb = env->regs[ipbh0 & 0xf];
code = env->regs[(ipbh0 & 0xf0) >> 4];
- r = sclp_service_call(env, sccb, code);
+ r = sclp_service_call(sccb, code);
if (r < 0) {
enter_pgmcheck(env, -r);
}
diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
index abc35dd..e7bb980 100644
--- a/target-s390x/op_helper.c
+++ b/target-s390x/op_helper.c
@@ -2363,13 +2363,11 @@ static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
}
/*
+ * we handle here the part that belongs to the cpu, e.g. program checks
* ret < 0 indicates program check, ret = 0,1,2,3 -> cc
*/
-int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
+int sclp_service_call(uint32_t sccb, uint64_t code)
{
- int r = 0;
- int shift = 0;
-
#ifdef DEBUG_HELPER
printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
#endif
@@ -2382,27 +2380,8 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
return -PGM_SPECIFICATION;
}
- switch(code) {
- case SCLP_CMDW_READ_SCP_INFO:
- case SCLP_CMDW_READ_SCP_INFO_FORCED:
- while ((ram_size >> (20 + shift)) > 65535) {
- shift++;
- }
- stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
- stb_phys(sccb + SCP_INCREMENT, 1 << shift);
- stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
-
- s390_sclp_extint(sccb & ~3);
- break;
- default:
-#ifdef DEBUG_HELPER
- printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
-#endif
- r = 3;
- break;
- }
-
- return r;
+ /* the complex part is handled by external components */
+ return do_sclp_service_call(sccb, code);
}
/* SCLP service call */
@@ -2410,7 +2389,7 @@ uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
{
int r;
- r = sclp_service_call(env, r1, r2);
+ r = sclp_service_call(r1, r2);
if (r < 0) {
program_interrupt(env, -r, 4);
return 0;
--
1.7.11.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 2/4] s390: sclp event support
2012-08-20 14:28 [Qemu-devel] [PATCH 0/4 v4] s390: sclp patch set Jens Freimann
2012-08-20 14:28 ` [Qemu-devel] [PATCH 1/4] s390: sclp base support Jens Freimann
@ 2012-08-20 14:28 ` Jens Freimann
2012-08-20 14:28 ` [Qemu-devel] [PATCH 3/4] s390: sclp signal quiesce support Jens Freimann
2012-08-20 14:28 ` [Qemu-devel] [PATCH 4/4] s390: sclp ascii console support Jens Freimann
3 siblings, 0 replies; 10+ messages in thread
From: Jens Freimann @ 2012-08-20 14:28 UTC (permalink / raw)
To: Alexander Graf
Cc: Heinz Graalfs, qemu-devel, Einar Lueck, Christian Borntraeger,
Jens Freimann, Cornelia Huck, Andreas Faerber
From: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
Several SCLP features are considered to be events. Those events don't
provide SCLP commands on their own, instead they are all based on
Read Event Data, Write Event Data, Write Event Mask and the service
interrupt. Follow-on patches will provide SCLP's Signal Quiesce (via
system_powerdown) and the ASCII console.
Further down the road the sclp line mode console and configuration
change events (e.g. cpu hotplug) can be implemented.
Signed-off-by: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
---
hw/s390-virtio.c | 2 +
hw/s390x/Makefile.objs | 1 +
hw/s390x/event-facility.c | 391 ++++++++++++++++++++++++++++++++++++++++++++++
hw/s390x/event-facility.h | 96 ++++++++++++
hw/s390x/sclp.c | 49 +++++-
hw/s390x/sclp.h | 42 +++++
6 files changed, 579 insertions(+), 2 deletions(-)
create mode 100644 hw/s390x/event-facility.c
create mode 100644 hw/s390x/event-facility.h
diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
index 47eed35..820e7f6 100644
--- a/hw/s390-virtio.c
+++ b/hw/s390-virtio.c
@@ -32,6 +32,7 @@
#include "exec-memory.h"
#include "hw/s390-virtio-bus.h"
+#include "hw/s390x/sclp.h"
//#define DEBUG_S390
@@ -183,6 +184,7 @@ static void s390_init(ram_addr_t my_ram_size,
/* get a BUS */
s390_bus = s390_virtio_bus_init(&my_ram_size);
+ s390_sclp_init();
/* allocate RAM */
memory_region_init_ram(ram, "s390.ram", my_ram_size);
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index 1c14b96..b32fc52 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -2,3 +2,4 @@ obj-y = s390-virtio-bus.o s390-virtio.o
obj-y := $(addprefix ../,$(obj-y))
obj-y += sclp.o
+obj-y += event-facility.o
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
new file mode 100644
index 0000000..1108e2d
--- /dev/null
+++ b/hw/s390x/event-facility.c
@@ -0,0 +1,391 @@
+/*
+ * SCLP
+ * Event Facility
+ * handles SCLP event types
+ * - Signal Quiesce - system power down
+ * - ASCII Console Data - VT220 read and write
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Heinz Graalfs <graalfs@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "monitor.h"
+#include "sysemu.h"
+
+#include "sclp.h"
+#include "event-facility.h"
+
+typedef struct EventTypesBus {
+ BusState qbus;
+} EventTypesBus;
+
+struct SCLPEventFacility {
+ EventTypesBus sbus;
+ DeviceState *qdev;
+ /* guest' receive mask */
+ unsigned int receive_mask;
+};
+
+/* return true if any child has event pending set */
+static bool event_pending(SCLPEventFacility *ef)
+{
+ BusChild *kid;
+ SCLPEvent *event;
+ SCLPEventClass *event_class;
+
+ QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
+ event = DO_UPCAST(SCLPEvent, qdev, qdev);
+ event_class = SCLP_EVENT_GET_CLASS(event);
+ if (event->event_pending &&
+ event_class->get_send_mask() & ef->receive_mask) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static unsigned int get_host_send_mask(SCLPEventFacility *ef)
+{
+ unsigned int mask;
+ BusChild *kid;
+ SCLPEventClass *child;
+
+ mask = 0;
+
+ QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
+ child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev);
+ mask |= child->get_send_mask();
+ }
+ return mask;
+}
+
+static unsigned int get_host_receive_mask(SCLPEventFacility *ef)
+{
+ unsigned int mask;
+ BusChild *kid;
+ SCLPEventClass *child;
+
+ mask = 0;
+
+ QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
+ child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev);
+ mask |= child->get_receive_mask();
+ }
+ return mask;
+}
+
+static uint16_t write_event_length_check(SCCB *sccb)
+{
+ int slen;
+ unsigned elen = 0;
+ EventBufferHeader *event;
+ WriteEventData *wed = (WriteEventData *) sccb;
+
+ event = (EventBufferHeader *) &wed->ebh;
+ for (slen = sccb_data_len(sccb); slen > 0; slen -= elen) {
+ elen = be16_to_cpu(event->length);
+ if (elen < sizeof(*event) || elen > slen) {
+ return SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR;
+ }
+ event = (void *) event + elen;
+ }
+ if (slen) {
+ return SCLP_RC_INCONSISTENT_LENGTHS;
+ }
+ return SCLP_RC_NORMAL_COMPLETION;
+}
+
+static uint16_t handle_write_event_buf(SCLPEventFacility *ef,
+ EventBufferHeader *event_buf, SCCB *sccb)
+{
+ uint16_t rc;
+ BusChild *kid;
+ SCLPEvent *event;
+ SCLPEventClass *ec;
+
+ QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
+ event = (SCLPEvent *) qdev;
+ ec = SCLP_EVENT_GET_CLASS(event);
+
+ rc = SCLP_RC_INVALID_FUNCTION;
+ if (ec->write_event_data &&
+ ec->event_type() == event_buf->type) {
+ rc = ec->write_event_data(event, event_buf);
+ break;
+ }
+ }
+ return rc;
+}
+
+static uint16_t handle_sccb_write_events(SCLPEventFacility *ef, SCCB *sccb)
+{
+ uint16_t rc;
+ int slen;
+ unsigned elen = 0;
+ EventBufferHeader *event_buf;
+ WriteEventData *wed = (WriteEventData *) sccb;
+
+ event_buf = &wed->ebh;
+ rc = SCLP_RC_NORMAL_COMPLETION;
+
+ /* loop over all contained event buffers */
+ for (slen = sccb_data_len(sccb); slen > 0; slen -= elen) {
+ elen = be16_to_cpu(event_buf->length);
+
+ /* in case of a previous error mark all trailing buffers
+ * as not accepted */
+ if (rc != SCLP_RC_NORMAL_COMPLETION) {
+ event_buf->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
+ } else {
+ rc = handle_write_event_buf(ef, event_buf, sccb);
+ }
+ event_buf = (void *) event_buf + elen;
+ }
+ return rc;
+}
+
+static void write_event_data(SCLPEventFacility *ef, SCCB *sccb)
+{
+ if (sccb->h.function_code != SCLP_FC_NORMAL_WRITE) {
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
+ goto out;
+ }
+ if (be16_to_cpu(sccb->h.length) < 8) {
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
+ goto out;
+ }
+ /* first do a sanity check of the write events */
+ sccb->h.response_code = cpu_to_be16(write_event_length_check(sccb));
+
+ /* if no early error, then execute */
+ if (sccb->h.response_code == be16_to_cpu(SCLP_RC_NORMAL_COMPLETION)) {
+ sccb->h.response_code =
+ cpu_to_be16(handle_sccb_write_events(ef, sccb));
+ }
+
+out:
+ return;
+}
+
+static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb,
+ unsigned int mask)
+{
+ uint16_t rc;
+ int slen;
+ unsigned elen = 0;
+ BusChild *kid;
+ SCLPEvent *event;
+ SCLPEventClass *ec;
+ EventBufferHeader *event_buf;
+ ReadEventData *red = (ReadEventData *) sccb;
+
+ event_buf = &red->ebh;
+ event_buf->length = 0;
+ slen = sizeof(sccb->data);
+
+ rc = SCLP_RC_NO_EVENT_BUFFERS_STORED;
+
+ QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) {
+ DeviceState *qdev = kid->child;
+ event = (SCLPEvent *) qdev;
+ ec = SCLP_EVENT_GET_CLASS(event);
+
+ if (mask & ec->get_send_mask()) {
+ if (ec->read_event_data(event, event_buf, &slen)) {
+ rc = SCLP_RC_NORMAL_COMPLETION;
+ }
+ }
+ elen = be16_to_cpu(event_buf->length);
+ event_buf = (void *) event_buf + elen;
+ }
+
+ if (sccb->h.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) {
+ /* architecture suggests to reset variable-length-response bit */
+ sccb->h.control_mask[2] &= ~SCLP_VARIABLE_LENGTH_RESPONSE;
+ /* with a new length value */
+ sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
+ }
+ return rc;
+}
+
+static void read_event_data(SCLPEventFacility *ef, SCCB *sccb)
+{
+ unsigned int sclp_active_selection_mask;
+ unsigned int sclp_cp_receive_mask;
+
+ ReadEventData *red = (ReadEventData *) sccb;
+
+ if (be16_to_cpu(sccb->h.length) != SCCB_SIZE) {
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
+ goto out;
+ }
+
+ sclp_cp_receive_mask = ef->receive_mask;
+
+ /* get active selection mask */
+ switch (sccb->h.function_code) {
+ case SCLP_UNCONDITIONAL_READ:
+ sclp_active_selection_mask = sclp_cp_receive_mask;
+ break;
+ case SCLP_SELECTIVE_READ:
+ if (!(sclp_cp_receive_mask & be32_to_cpu(red->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);
+ goto out;
+ }
+ sccb->h.response_code = cpu_to_be16(
+ handle_sccb_read_events(ef, sccb, sclp_active_selection_mask));
+
+out:
+ return;
+}
+
+static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb)
+{
+ WriteEventMask *we_mask = (WriteEventMask *) sccb;
+
+ /* Attention: We assume that Linux uses 4-byte masks, what it actually
+ does. Architecture allows for masks of variable size, though */
+ if (be16_to_cpu(we_mask->mask_length) != 4) {
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH);
+ goto out;
+ }
+
+ /* keep track of the guest's capability masks */
+ ef->receive_mask = be32_to_cpu(we_mask->cp_receive_mask);
+
+ /* return the SCLP's capability masks to the guest */
+ we_mask->send_mask = cpu_to_be32(get_host_send_mask(ef));
+ we_mask->receive_mask = cpu_to_be32(get_host_receive_mask(ef));
+
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
+
+out:
+ return;
+}
+
+/* qemu object creation and initialization functions */
+
+#define TYPE_SCLP_EVENTS_BUS "s390-sclp-events-bus"
+
+static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
+{
+}
+
+static const TypeInfo s390_sclp_events_bus_info = {
+ .name = TYPE_SCLP_EVENTS_BUS,
+ .parent = TYPE_BUS,
+ .class_init = sclp_events_bus_class_init,
+};
+
+static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
+{
+ switch (code) {
+ case SCLP_CMD_READ_EVENT_DATA:
+ read_event_data(ef, sccb);
+ break;
+ case SCLP_CMD_WRITE_EVENT_DATA:
+ write_event_data(ef, sccb);
+ break;
+ case SCLP_CMD_WRITE_EVENT_MASK:
+ write_event_mask(ef, sccb);
+ break;
+ default:
+ sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
+ break;
+ }
+}
+
+static int init_event_facility(S390SCLPDevice *sdev)
+{
+ SCLPEventFacility *event_facility;
+
+ event_facility = g_malloc0(sizeof(SCLPEventFacility));
+ sdev->ef = event_facility;
+ sdev->sclp_command_handler = command_handler;
+ sdev->event_pending = event_pending;
+
+ /* Spawn a new sclp-events facility */
+ qbus_create_inplace(&event_facility->sbus.qbus,
+ TYPE_SCLP_EVENTS_BUS, (DeviceState *)sdev, NULL);
+ event_facility->sbus.qbus.allow_hotplug = 0;
+ event_facility->qdev = (DeviceState *) sdev;
+
+ return 0;
+}
+
+static void init_event_facility_class(ObjectClass *klass, void *data)
+{
+ S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass);
+
+ k->init = init_event_facility;
+}
+
+static TypeInfo s390_sclp_event_facility_info = {
+ .name = "s390-sclp-event-facility",
+ .parent = TYPE_DEVICE_S390_SCLP,
+ .instance_size = sizeof(S390SCLPDevice),
+ .class_init = init_event_facility_class,
+};
+
+static int event_qdev_init(DeviceState *qdev)
+{
+ SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
+ SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
+
+ return child->init(event);
+}
+
+static int event_qdev_exit(DeviceState *qdev)
+{
+ SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
+ SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
+ if (child->exit) {
+ child->exit(event);
+ }
+ return 0;
+}
+
+static void event_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->bus_type = TYPE_SCLP_EVENTS_BUS;
+ dc->unplug = qdev_simple_unplug_cb;
+ dc->init = event_qdev_init;
+ dc->exit = event_qdev_exit;
+}
+
+static TypeInfo s390_sclp_event_type_info = {
+ .name = TYPE_SCLP_EVENT,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(SCLPEvent),
+ .class_init = event_class_init,
+ .class_size = sizeof(SCLPEventClass),
+ .abstract = true,
+};
+
+static void register_types(void)
+{
+ type_register_static(&s390_sclp_events_bus_info);
+ type_register_static(&s390_sclp_event_facility_info);
+ type_register_static(&s390_sclp_event_type_info);
+}
+
+type_init(register_types)
diff --git a/hw/s390x/event-facility.h b/hw/s390x/event-facility.h
new file mode 100644
index 0000000..30af0a7
--- /dev/null
+++ b/hw/s390x/event-facility.h
@@ -0,0 +1,96 @@
+/*
+ * SCLP
+ * Event Facility definitions
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Heinz Graalfs <graalfs@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#ifndef HW_S390_SCLP_EVENT_FACILITY_H
+#define HW_S390_SCLP_EVENT_FACILITY_H
+
+#include <hw/qdev.h>
+#include "qemu-thread.h"
+
+/* SCLP event types */
+#define SCLP_EVENT_ASCII_CONSOLE_DATA 0x1a
+#define SCLP_EVENT_SIGNAL_QUIESCE 0x1d
+
+/* SCLP event masks */
+#define SCLP_EVENT_MASK_SIGNAL_QUIESCE 0x00000008
+#define SCLP_EVENT_MASK_MSG_ASCII 0x00000040
+
+#define SCLP_UNCONDITIONAL_READ 0x00
+#define SCLP_SELECTIVE_READ 0x01
+
+#define TYPE_SCLP_EVENT "s390-sclp-event-type"
+#define SCLP_EVENT(obj) \
+ OBJECT_CHECK(SCLPEvent, (obj), TYPE_SCLP_EVENT)
+#define SCLP_EVENT_CLASS(klass) \
+ OBJECT_CLASS_CHECK(SCLPEventClass, (klass), TYPE_SCLP_EVENT)
+#define SCLP_EVENT_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT)
+
+typedef struct WriteEventMask {
+ SCCBHeader h;
+ uint16_t _reserved;
+ uint16_t mask_length;
+ uint32_t cp_receive_mask;
+ uint32_t cp_send_mask;
+ uint32_t send_mask;
+ uint32_t receive_mask;
+} QEMU_PACKED WriteEventMask;
+
+typedef struct EventBufferHeader {
+ uint16_t length;
+ uint8_t type;
+ uint8_t flags;
+ uint16_t _reserved;
+} QEMU_PACKED EventBufferHeader;
+
+typedef struct WriteEventData {
+ SCCBHeader h;
+ EventBufferHeader ebh;
+} QEMU_PACKED WriteEventData;
+
+typedef struct ReadEventData {
+ SCCBHeader h;
+ EventBufferHeader ebh;
+ uint32_t mask;
+} QEMU_PACKED ReadEventData;
+
+typedef struct SCLPEvent {
+ DeviceState qdev;
+ bool event_pending;
+ uint32_t event_type;
+ char *name;
+} SCLPEvent;
+
+typedef struct SCLPEventClass {
+ DeviceClass parent_class;
+ int (*init)(SCLPEvent *event);
+ int (*exit)(SCLPEvent *event);
+
+ /* get SCLP's send mask */
+ unsigned int (*get_send_mask)(void);
+
+ /* get SCLP's receive mask */
+ unsigned int (*get_receive_mask)(void);
+
+ int (*read_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
+ int *slen);
+
+ int (*write_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr);
+
+ /* returns the supported event type */
+ int (*event_type)(void);
+
+} SCLPEventClass;
+
+#endif
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 322a0e2..09da5c4 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -17,6 +17,15 @@
#include "sclp.h"
+static inline S390SCLPDevice *get_event_facility(void)
+{
+ ObjectProperty *op = object_property_find(qdev_get_machine(),
+ "s390-sclp-event-facility",
+ NULL);
+ assert(op);
+ return op->opaque;
+}
+
/* Provide information about the configuration, CPUs and storage */
static void read_SCP_info(SCCB *sccb)
{
@@ -33,13 +42,15 @@ static void read_SCP_info(SCCB *sccb)
static void sclp_execute(SCCB *sccb, uint64_t code)
{
+ S390SCLPDevice *sdev = get_event_facility();
+
switch (code) {
case SCLP_CMDW_READ_SCP_INFO:
case SCLP_CMDW_READ_SCP_INFO_FORCED:
read_SCP_info(sccb);
break;
default:
- sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
+ sdev->sclp_command_handler(sdev->ef, sccb, code);
break;
}
}
@@ -78,11 +89,45 @@ out:
void sclp_service_interrupt(uint32_t sccb)
{
- s390_sclp_extint(sccb & ~3);
+ S390SCLPDevice *sdev = get_event_facility();
+ uint32_t param = sccb & ~3;
+
+ /* Indicate whether an event is still pending */
+ param |= sdev->event_pending(sdev->ef) ? 1 : 0;
+
+ if (!param) {
+ /* No need to send an interrupt, there's nothing to be notified about */
+ return;
+ }
+ s390_sclp_extint(param);
}
/* qemu object creation and initialization functions */
+void s390_sclp_init(void)
+{
+ DeviceState *dev = qdev_create(NULL, "s390-sclp-event-facility");
+
+ object_property_add_child(qdev_get_machine(), "s390-sclp-event-facility",
+ OBJECT(dev), NULL);
+ qdev_init_nofail(dev);
+}
+
+static int s390_sclp_dev_init(SysBusDevice *dev)
+{
+ int r;
+ S390SCLPDevice *sdev = (S390SCLPDevice *)dev;
+ S390SCLPDeviceClass *sclp = SCLP_S390_DEVICE_GET_CLASS(dev);
+
+ r = sclp->init(sdev);
+ if (!r) {
+ assert(sdev->event_pending);
+ assert(sdev->sclp_command_handler);
+ }
+
+ return r;
+}
+
static void s390_sclp_device_class_init(ObjectClass *klass, void *data)
{
SysBusDeviceClass *dc = SYS_BUS_DEVICE_CLASS(klass);
diff --git a/hw/s390x/sclp.h b/hw/s390x/sclp.h
index e9ad42b..40db291 100644
--- a/hw/s390x/sclp.h
+++ b/hw/s390x/sclp.h
@@ -20,15 +20,35 @@
/* SCLP command codes */
#define SCLP_CMDW_READ_SCP_INFO 0x00020001
#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
+#define SCLP_CMD_READ_EVENT_DATA 0x00770005
+#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005
+#define SCLP_CMD_READ_EVENT_DATA 0x00770005
+#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005
+#define SCLP_CMD_WRITE_EVENT_MASK 0x00780005
/* SCLP response codes */
#define SCLP_RC_NORMAL_READ_COMPLETION 0x0010
+#define SCLP_RC_NORMAL_COMPLETION 0x0020
#define SCLP_RC_INVALID_SCLP_COMMAND 0x01f0
+#define SCLP_RC_CONTAINED_EQUIPMENT_CHECK 0x0340
+#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH 0x0300
+#define SCLP_RC_INVALID_FUNCTION 0x40f0
+#define SCLP_RC_NO_EVENT_BUFFERS_STORED 0x60f0
+#define SCLP_RC_INVALID_SELECTION_MASK 0x70f0
+#define SCLP_RC_INCONSISTENT_LENGTHS 0x72f0
+#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR 0x73f0
+#define SCLP_RC_INVALID_MASK_LENGTH 0x74f0
+
/* Service Call Control Block (SCCB) and its elements */
#define SCCB_SIZE 4096
+#define SCLP_VARIABLE_LENGTH_RESPONSE 0x80
+#define SCLP_EVENT_BUFFER_ACCEPTED 0x80
+
+#define SCLP_FC_NORMAL_WRITE 0
+
/*
* Normally packed structures are not the right thing to do, since all code
* must take care of endianess. We cant use ldl_phys and friends for two
@@ -62,8 +82,29 @@ typedef struct SCCB {
char data[SCCB_DATA_LEN];
} QEMU_PACKED SCCB;
+static inline int sccb_data_len(SCCB *sccb)
+{
+ return be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
+}
+
+#define TYPE_DEVICE_S390_SCLP "s390-sclp-device"
+#define SCLP_S390_DEVICE(obj) \
+ OBJECT_CHECK(S390SCLPDevice, (obj), TYPE_DEVICE_S390_SCLP)
+#define SCLP_S390_DEVICE_CLASS(klass) \
+ OBJECT_CLASS_CHECK(S390SCLPDeviceClass, (klass), \
+ TYPE_DEVICE_S390_SCLP)
+#define SCLP_S390_DEVICE_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(S390SCLPDeviceClass, (obj), \
+ TYPE_DEVICE_S390_SCLP)
+
+typedef struct SCLPEventFacility SCLPEventFacility;
+
typedef struct S390SCLPDevice {
SysBusDevice busdev;
+ SCLPEventFacility *ef;
+ void (*sclp_command_handler)(SCLPEventFacility *ef, SCCB *sccb,
+ uint64_t code);
+ bool (*event_pending)(SCLPEventFacility *ef);
} S390SCLPDevice;
typedef struct S390SCLPDeviceClass {
@@ -71,6 +112,7 @@ typedef struct S390SCLPDeviceClass {
int (*init)(S390SCLPDevice *sdev);
} S390SCLPDeviceClass;
+void s390_sclp_init(void);
void sclp_service_interrupt(uint32_t sccb);
#endif
--
1.7.11.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 3/4] s390: sclp signal quiesce support
2012-08-20 14:28 [Qemu-devel] [PATCH 0/4 v4] s390: sclp patch set Jens Freimann
2012-08-20 14:28 ` [Qemu-devel] [PATCH 1/4] s390: sclp base support Jens Freimann
2012-08-20 14:28 ` [Qemu-devel] [PATCH 2/4] s390: sclp event support Jens Freimann
@ 2012-08-20 14:28 ` Jens Freimann
2012-08-20 14:28 ` [Qemu-devel] [PATCH 4/4] s390: sclp ascii console support Jens Freimann
3 siblings, 0 replies; 10+ messages in thread
From: Jens Freimann @ 2012-08-20 14:28 UTC (permalink / raw)
To: Alexander Graf
Cc: Heinz Graalfs, qemu-devel, Einar Lueck, Christian Borntraeger,
Jens Freimann, Cornelia Huck, Andreas Faerber
From: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
This implements the sclp signal quiesce event via the SCLP Event
Facility.
This allows to gracefully shutdown a guest by using system_powerdown.
It creates a service interrupt that will trigger a Read Event Data
command from the guest. This code will then add an event that is
interpreted by linux guests as ctrl-alt-del.
Signed-off-by: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
---
hw/s390x/Makefile.objs | 1 +
hw/s390x/event-facility.c | 7 +++
hw/s390x/sclpquiesce.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 120 insertions(+)
create mode 100644 hw/s390x/sclpquiesce.c
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index b32fc52..ed4e61a 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -3,3 +3,4 @@ obj-y = s390-virtio-bus.o s390-virtio.o
obj-y := $(addprefix ../,$(obj-y))
obj-y += sclp.o
obj-y += event-facility.o
+obj-y += sclpquiesce.o
diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c
index 1108e2d..9367660 100644
--- a/hw/s390x/event-facility.c
+++ b/hw/s390x/event-facility.c
@@ -315,6 +315,7 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code)
static int init_event_facility(S390SCLPDevice *sdev)
{
SCLPEventFacility *event_facility;
+ DeviceState *quiesce;
event_facility = g_malloc0(sizeof(SCLPEventFacility));
sdev->ef = event_facility;
@@ -327,6 +328,12 @@ static int init_event_facility(S390SCLPDevice *sdev)
event_facility->sbus.qbus.allow_hotplug = 0;
event_facility->qdev = (DeviceState *) sdev;
+ quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
+ if (!quiesce) {
+ return -1;
+ }
+ qdev_init_nofail(quiesce);
+
return 0;
}
diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c
new file mode 100644
index 0000000..69d6737
--- /dev/null
+++ b/hw/s390x/sclpquiesce.c
@@ -0,0 +1,112 @@
+/*
+ * SCLP event type
+ * Signal Quiesce - trigger system powerdown request
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Heinz Graalfs <graalfs@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+#include <hw/qdev.h>
+#include "sysemu.h"
+#include "sclp.h"
+#include "event-facility.h"
+
+typedef struct SignalQuiesce {
+ EventBufferHeader ebh;
+ uint16_t timeout;
+ uint8_t unit;
+} QEMU_PACKED SignalQuiesce;
+
+static int event_type(void)
+{
+ return SCLP_EVENT_SIGNAL_QUIESCE;
+}
+
+static unsigned int send_mask(void)
+{
+ return SCLP_EVENT_MASK_SIGNAL_QUIESCE;
+}
+
+static unsigned int receive_mask(void)
+{
+ return 0;
+}
+
+static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
+ int *slen)
+{
+ SignalQuiesce *sq = (SignalQuiesce *) evt_buf_hdr;
+
+ if (*slen < sizeof(SignalQuiesce)) {
+ return 0;
+ }
+
+ if (!event->event_pending) {
+ return 0;
+ }
+ event->event_pending = false;
+
+ sq->ebh.length = cpu_to_be16(sizeof(SignalQuiesce));
+ sq->ebh.type = SCLP_EVENT_SIGNAL_QUIESCE;
+ sq->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
+ /*
+ * system_powerdown does not have a timeout. Fortunately the
+ * timeout value is currently ignored by Linux, anyway
+ */
+ sq->timeout = cpu_to_be16(0);
+ sq->unit = cpu_to_be16(0);
+ *slen -= sizeof(SignalQuiesce);
+
+ return 1;
+}
+
+static void trigger_signal_quiesce(void *opaque, int n, int level)
+{
+ SCLPEvent *event = opaque;
+
+ event->event_pending = true;
+ /* trigger SCLP read operation */
+ sclp_service_interrupt(0);
+}
+
+static int quiesce_init(SCLPEvent *event)
+{
+ event->event_type = SCLP_EVENT_SIGNAL_QUIESCE;
+ qemu_system_powerdown = *qemu_allocate_irqs(trigger_signal_quiesce,
+ event, 1);
+
+ return 0;
+}
+
+static void quiesce_class_init(ObjectClass *klass, void *data)
+{
+ SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
+
+ k->init = quiesce_init;
+
+ k->get_send_mask = send_mask;
+ k->get_receive_mask = receive_mask;
+ k->event_type = event_type;
+ k->read_event_data = read_event_data;
+ k->write_event_data = NULL;
+}
+
+static TypeInfo sclp_quiesce_info = {
+ .name = "sclpquiesce",
+ .parent = TYPE_SCLP_EVENT,
+ .instance_size = sizeof(SCLPEvent),
+ .class_init = quiesce_class_init,
+ .class_size = sizeof(SCLPEventClass),
+};
+
+static void register_types(void)
+{
+ type_register_static(&sclp_quiesce_info);
+}
+
+type_init(register_types)
--
1.7.11.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [Qemu-devel] [PATCH 4/4] s390: sclp ascii console support
2012-08-20 14:28 [Qemu-devel] [PATCH 0/4 v4] s390: sclp patch set Jens Freimann
` (2 preceding siblings ...)
2012-08-20 14:28 ` [Qemu-devel] [PATCH 3/4] s390: sclp signal quiesce support Jens Freimann
@ 2012-08-20 14:28 ` Jens Freimann
3 siblings, 0 replies; 10+ messages in thread
From: Jens Freimann @ 2012-08-20 14:28 UTC (permalink / raw)
To: Alexander Graf
Cc: Heinz Graalfs, qemu-devel, Einar Lueck, Christian Borntraeger,
Jens Freimann, Cornelia Huck, Andreas Faerber
From: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
This code adds console support by implementing SCLP's ASCII Console
Data event. This is the same console as LPARs ASCII console or z/VMs
sysascii.
The console can be specified manually with something like
-chardev stdio,id=charconsole0 -device sclpconsole,chardev=charconsole0,id=console0
Newer kernels will autodetect that console and prefer that over virtio
console.
When data is received from the character layer it creates a service
interrupt to trigger a Read Event Data command from the guest that will
pick up the received character byte-stream.
When characters are echo'ed by the linux guest a Write Event Data occurs
which is forwarded by the Event Facility to the console that supports
a corresponding mask value.
Console resizing is not supported.
The character layer byte-stream is buffered using a fixed size iov
buffer.
Signed-off-by: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
---
hw/s390x/Makefile.objs | 2 +-
hw/s390x/sclpconsole.c | 306 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 307 insertions(+), 1 deletion(-)
create mode 100644 hw/s390x/sclpconsole.c
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index ed4e61a..096dfcd 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -3,4 +3,4 @@ obj-y = s390-virtio-bus.o s390-virtio.o
obj-y := $(addprefix ../,$(obj-y))
obj-y += sclp.o
obj-y += event-facility.o
-obj-y += sclpquiesce.o
+obj-y += sclpquiesce.o sclpconsole.o
diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c
new file mode 100644
index 0000000..0ec5623
--- /dev/null
+++ b/hw/s390x/sclpconsole.c
@@ -0,0 +1,306 @@
+/*
+ * SCLP event type
+ * Ascii Console Data (VT220 Console)
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ * Heinz Graalfs <graalfs@de.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at your
+ * option) any later version. See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <hw/qdev.h>
+#include "qemu-thread.h"
+
+#include "sclp.h"
+#include "event-facility.h"
+
+typedef struct ASCIIConsoleData {
+ EventBufferHeader ebh;
+ char data[0];
+} QEMU_PACKED ASCIIConsoleData;
+
+/* max size for ASCII data in 4K SCCB page */
+#define SIZE_BUFFER_VT220 4080
+
+typedef struct SCLPConsole {
+ SCLPEvent event;
+ CharDriverState *chr;
+ /* io vector */
+ uint8_t *iov; /* iov buffer pointer */
+ uint8_t *iov_sclp; /* pointer to SCLP read offset */
+ uint8_t *iov_bs; /* pointer byte stream read offset */
+ uint32_t iov_data_len; /* length of byte stream in buffer */
+ uint32_t iov_sclp_rest; /* length of byte stream not read via SCLP */
+ qemu_irq irq_read_vt220;
+} SCLPConsole;
+
+/* character layer call-back functions */
+
+/* Return number of bytes that fit into iov buffer */
+static int chr_can_read(void *opaque)
+{
+ int can_read;
+ SCLPConsole *scon = opaque;
+
+ can_read = SIZE_BUFFER_VT220 - scon->iov_data_len;
+
+ return can_read;
+}
+
+/* Receive n bytes from character layer, save in iov buffer,
+ * and set event pending */
+static void receive_from_chr_layer(SCLPConsole *scon, const uint8_t *buf,
+ int size)
+{
+ assert(scon->iov);
+
+ /* read data must fit into current buffer */
+ assert(size <= SIZE_BUFFER_VT220 - scon->iov_data_len);
+
+ /* put byte-stream from character layer into buffer */
+ memcpy(scon->iov_bs, buf, size);
+ scon->iov_data_len += size;
+ scon->iov_sclp_rest += size;
+ scon->iov_bs += size;
+ scon->event.event_pending = true;
+}
+
+/* Send data from a char device over to the guest */
+static void chr_read(void *opaque, const uint8_t *buf, int size)
+{
+ SCLPConsole *scon = opaque;
+
+ assert(scon);
+
+ receive_from_chr_layer(scon, buf, size);
+ /* trigger SCLP read operation */
+ qemu_irq_raise(scon->irq_read_vt220);
+}
+
+static void chr_event(void *opaque, int event)
+{
+ SCLPConsole *scon = opaque;
+
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ if (!scon->iov) {
+ scon->iov = g_malloc0(SIZE_BUFFER_VT220);
+ scon->iov_sclp = scon->iov;
+ scon->iov_bs = scon->iov;
+ scon->iov_data_len = 0;
+ scon->iov_sclp_rest = 0;
+ }
+ break;
+ case CHR_EVENT_CLOSED:
+ if (scon->iov) {
+ g_free(scon->iov);
+ scon->iov = NULL;
+ }
+ break;
+ }
+}
+
+/* functions to be called by event facility */
+
+static int event_type(void)
+{
+ return SCLP_EVENT_ASCII_CONSOLE_DATA;
+}
+
+static unsigned int send_mask(void)
+{
+ return SCLP_EVENT_MASK_MSG_ASCII;
+}
+
+static unsigned int receive_mask(void)
+{
+ return SCLP_EVENT_MASK_MSG_ASCII;
+}
+
+/* triggered by SCLP's read_event_data -
+ * copy console data byte-stream into provided (SCLP) buffer
+ */
+static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
+ int avail)
+{
+ SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event);
+
+ /* first byte is hex 0 saying an ascii string follows */
+ *buf++ = '\0';
+ avail--;
+ /* if all data fit into provided SCLP buffer */
+ if (avail >= cons->iov_sclp_rest) {
+ /* copy character byte-stream to SCLP buffer */
+ memcpy(buf, cons->iov_sclp, cons->iov_sclp_rest);
+ *size = cons->iov_sclp_rest + 1;
+ cons->iov_sclp = cons->iov;
+ cons->iov_bs = cons->iov;
+ cons->iov_data_len = 0;
+ cons->iov_sclp_rest = 0;
+ event->event_pending = false;
+ /* data provided and no more data pending */
+ } else {
+ /* if provided buffer is too small, just copy part */
+ memcpy(buf, cons->iov_sclp, avail);
+ *size = avail + 1;
+ cons->iov_sclp_rest -= avail;
+ cons->iov_sclp += avail;
+ /* more data pending */
+ }
+}
+
+static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
+ int *slen)
+{
+ int avail;
+ size_t src_len;
+ uint8_t *to;
+ ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
+
+ if (!event->event_pending) {
+ /* no data pending */
+ return 0;
+ }
+
+ to = (uint8_t *)&acd->data;
+ avail = *slen - sizeof(ASCIIConsoleData);
+ get_console_data(event, to, &src_len, avail);
+
+ acd->ebh.length = cpu_to_be16(sizeof(ASCIIConsoleData) + src_len);
+ acd->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
+ acd->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED;
+ *slen = avail - src_len;
+
+ return 1;
+}
+
+/* triggered by SCLP's write_event_data
+ * - write console data into character layer
+ * returns < 0 if an error occured
+ */
+static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
+ size_t len)
+{
+ ssize_t ret = 0;
+ const uint8_t *iov_offset;
+ SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+ if (!scon->chr) {
+ /* If there's no backend, we can just say we consumed all data. */
+ return len;
+ }
+
+ iov_offset = buf;
+ while (len > 0) {
+ ret = qemu_chr_fe_write(scon->chr, buf, len);
+ if (ret == 0) {
+ /* a pty doesn't seem to be connected - no error */
+ len = 0;
+ } else if (ret == -EAGAIN || (ret > 0 && ret < len)) {
+ len -= ret;
+ iov_offset += ret;
+ } else {
+ len = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
+{
+ int rc;
+ int length;
+ ssize_t written;
+ ASCIIConsoleData *acd = (ASCIIConsoleData *) evt_buf_hdr;
+
+ length = be16_to_cpu(evt_buf_hdr->length) - sizeof(EventBufferHeader);
+ written = write_console_data(event, (uint8_t *)acd->data, length);
+
+ rc = SCLP_RC_NORMAL_COMPLETION;
+ /* set event buffer accepted flag */
+ evt_buf_hdr->flags |= SCLP_EVENT_BUFFER_ACCEPTED;
+
+ /* written will be zero if a pty is not connected - don't treat as error */
+ if (written < 0) {
+ /* event buffer not accepted due to error in character layer */
+ evt_buf_hdr->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
+ rc = SCLP_RC_CONTAINED_EQUIPMENT_CHECK;
+ }
+
+ return rc;
+}
+
+static void trigger_ascii_console_data(void *env, int n, int level)
+{
+ sclp_service_interrupt(0);
+}
+
+/* qemu object creation and initialization functions */
+
+/* tell character layer our call-back functions */
+static int console_init(SCLPEvent *event)
+{
+ static bool console_available;
+
+ SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
+
+ if (console_available) {
+ error_report("Multiple VT220 operator consoles are not supported");
+ return -1;
+ }
+ console_available = true;
+ event->event_type = SCLP_EVENT_ASCII_CONSOLE_DATA;
+ if (scon->chr) {
+ qemu_chr_add_handlers(scon->chr, chr_can_read,
+ chr_read, chr_event, scon);
+ }
+ scon->irq_read_vt220 = *qemu_allocate_irqs(trigger_ascii_console_data,
+ NULL, 1);
+
+ return 0;
+}
+
+static int console_exit(SCLPEvent *event)
+{
+ return 0;
+}
+
+static Property console_properties[] = {
+ DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void console_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SCLPEventClass *ec = SCLP_EVENT_CLASS(klass);
+
+ dc->props = console_properties;
+ ec->init = console_init;
+ ec->exit = console_exit;
+ ec->get_send_mask = send_mask;
+ ec->get_receive_mask = receive_mask;
+ ec->event_type = event_type;
+ ec->read_event_data = read_event_data;
+ ec->write_event_data = write_event_data;
+}
+
+static TypeInfo sclp_console_info = {
+ .name = "sclpconsole",
+ .parent = TYPE_SCLP_EVENT,
+ .instance_size = sizeof(SCLPConsole),
+ .class_init = console_class_init,
+ .class_size = sizeof(SCLPEventClass),
+};
+
+static void register_types(void)
+{
+ type_register_static(&sclp_console_info);
+}
+
+type_init(register_types)
--
1.7.11.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH 1/4] s390: sclp base support
2012-08-20 14:28 ` [Qemu-devel] [PATCH 1/4] s390: sclp base support Jens Freimann
@ 2012-09-26 15:00 ` Alexander Graf
2012-09-26 16:06 ` Christian Borntraeger
0 siblings, 1 reply; 10+ messages in thread
From: Alexander Graf @ 2012-09-26 15:00 UTC (permalink / raw)
To: Jens Freimann
Cc: Heinz Graalfs, qemu-devel, Einar Lueck, Christian Borntraeger,
Cornelia Huck, Andreas Faerber
On 20.08.2012, at 16:28, Jens Freimann wrote:
> From: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
>
> This adds a more generic infrastructure for handling Service-Call
> requests on s390. Currently we only support a small subset of Read
> SCP Info directly in target-s390x. This patch provides the base
> infrastructure for supporting more commands and moves Read SCP
> Info.
> In the future we could add additional commands for hotplug, call
> home and event handling.
>
> Signed-off-by: Heinz Graalfs <graalfs@linux.vnet.ibm.com>
> Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
> Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
> ---
> hw/s390x/Makefile.objs | 1 +
> hw/s390x/sclp.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++
> hw/s390x/sclp.h | 76 +++++++++++++++++++++++++++++++++
> target-s390x/cpu.h | 14 +------
> target-s390x/kvm.c | 5 +--
> target-s390x/op_helper.c | 31 +++-----------
> 6 files changed, 192 insertions(+), 42 deletions(-)
> create mode 100644 hw/s390x/sclp.c
> create mode 100644 hw/s390x/sclp.h
>
> diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
> index dcdcac8..1c14b96 100644
> --- a/hw/s390x/Makefile.objs
> +++ b/hw/s390x/Makefile.objs
> @@ -1,3 +1,4 @@
> obj-y = s390-virtio-bus.o s390-virtio.o
>
> obj-y := $(addprefix ../,$(obj-y))
> +obj-y += sclp.o
> diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
> new file mode 100644
> index 0000000..322a0e2
> --- /dev/null
> +++ b/hw/s390x/sclp.c
> @@ -0,0 +1,107 @@
> +/*
> + * SCLP Support
> + *
> + * Copyright IBM, Corp. 2012
> + *
> + * Authors:
> + * Christian Borntraeger <borntraeger@de.ibm.com>
> + * Heinz Graalfs <graalfs@linux.vnet.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or (at your
> + * option) any later version. See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "cpu.h"
> +#include "kvm.h"
> +
> +#include "sclp.h"
> +
> +/* Provide information about the configuration, CPUs and storage */
> +static void read_SCP_info(SCCB *sccb)
> +{
> + ReadInfo *read_info = (ReadInfo *) sccb;
> + int shift = 0;
> +
> + while ((ram_size >> (20 + shift)) > 65535) {
> + shift++;
> + }
> + read_info->rnmax = cpu_to_be16(ram_size >> (20 + shift));
> + read_info->rnsize = 1 << shift;
Any reason we can't just always expose rnmax2 and rnsize2 instead? This way we're quite limited on the amount of RAM we can support, right?
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
> +}
> +
> +static void sclp_execute(SCCB *sccb, uint64_t code)
> +{
> + switch (code) {
> + case SCLP_CMDW_READ_SCP_INFO:
> + case SCLP_CMDW_READ_SCP_INFO_FORCED:
> + read_SCP_info(sccb);
> + break;
> + default:
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
> + break;
> + }
> +}
> +
> +int do_sclp_service_call(uint32_t sccb, uint64_t code)
> +{
> + int r = 0;
> + SCCB work_sccb;
> +
> + target_phys_addr_t sccb_len = sizeof(SCCB);
> +
> + /*
> + * we want to work on a private copy of the sccb, to prevent guests
> + * from playing dirty tricks by modifying the memory content after
> + * the host has checked the values
> + */
> + cpu_physical_memory_read(sccb, &work_sccb, sccb_len);
> +
> + /* Valid sccb sizes */
> + if (be16_to_cpu(work_sccb.h.length) < 8 ||
sizeof(SCCBHeader)
> + be16_to_cpu(work_sccb.h.length) > 4096) {
SCCB_SIZE
> + r = -PGM_SPECIFICATION;
> + goto out;
> + }
> +
> + sclp_execute((SCCB *)&work_sccb, code);
> +
> + cpu_physical_memory_write(sccb, &work_sccb,
> + be16_to_cpu(work_sccb.h.length));
> +
> + sclp_service_interrupt(sccb);
> +
> +out:
> + return r;
> +}
> +
> +void sclp_service_interrupt(uint32_t sccb)
> +{
> + s390_sclp_extint(sccb & ~3);
> +}
> +
> +/* qemu object creation and initialization functions */
> +
> +static void s390_sclp_device_class_init(ObjectClass *klass, void *data)
> +{
> + SysBusDeviceClass *dc = SYS_BUS_DEVICE_CLASS(klass);
> +
> + dc->init = s390_sclp_dev_init;
> +}
> +
> +static TypeInfo s390_sclp_device_info = {
> + .name = TYPE_DEVICE_S390_SCLP,
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(S390SCLPDevice),
> + .class_init = s390_sclp_device_class_init,
> + .class_size = sizeof(S390SCLPDeviceClass),
> + .abstract = true,
> +};
> +
> +static void s390_sclp_register_types(void)
> +{
> + type_register_static(&s390_sclp_device_info);
> +}
> +
> +type_init(s390_sclp_register_types)
> diff --git a/hw/s390x/sclp.h b/hw/s390x/sclp.h
> new file mode 100644
> index 0000000..e9ad42b
> --- /dev/null
> +++ b/hw/s390x/sclp.h
> @@ -0,0 +1,76 @@
> +/*
> + * SCLP Support
> + *
> + * Copyright IBM, Corp. 2012
> + *
> + * Authors:
> + * Christian Borntraeger <borntraeger@de.ibm.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or (at your
> + * option) any later version. See the COPYING file in the top-level directory.
> + *
> + */
> +
> +#ifndef HW_S390_SCLP_H
> +#define HW_S390_SCLP_H
> +
> +#include <hw/sysbus.h>
> +#include <hw/qdev.h>
> +
> +/* SCLP command codes */
> +#define SCLP_CMDW_READ_SCP_INFO 0x00020001
> +#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
> +
> +/* SCLP response codes */
> +#define SCLP_RC_NORMAL_READ_COMPLETION 0x0010
> +#define SCLP_RC_INVALID_SCLP_COMMAND 0x01f0
> +
> +/* Service Call Control Block (SCCB) and its elements */
> +
> +#define SCCB_SIZE 4096
> +
> +/*
> + * Normally packed structures are not the right thing to do, since all code
> + * must take care of endianess. We cant use ldl_phys and friends for two
> + * reasons, though:
> + * - some of the embedded structures below the SCCB can appear multiple times
> + * at different locations, so there is no fixed offset
> + * - we work on a private copy of the SCCB, since there are several length
> + * fields, that would cause a security nightmare if we allow the guest to
> + * alter the structure while we parse it. We cannot use ldl_p and friends
> + * either without doing pointer arithmetics
> + * So we have to double check that all users of sclp data structures use the
> + * right endianess wrappers.
> + */
> +typedef struct SCCBHeader {
> + uint16_t length;
> + uint8_t function_code;
> + uint8_t control_mask[3];
> + uint16_t response_code;
> +} QEMU_PACKED SCCBHeader;
> +
> +#define SCCB_DATA_LEN (SCCB_SIZE - sizeof(SCCBHeader))
> +
> +typedef struct ReadInfo {
> + SCCBHeader h;
> + uint16_t rnmax;
> + uint8_t rnsize;
> +} QEMU_PACKED ReadInfo;
> +
> +typedef struct SCCB {
> + SCCBHeader h;
> + char data[SCCB_DATA_LEN];
> + } QEMU_PACKED SCCB;
> +
> +typedef struct S390SCLPDevice {
> + SysBusDevice busdev;
> +} S390SCLPDevice;
> +
> +typedef struct S390SCLPDeviceClass {
> + DeviceClass qdev;
> + int (*init)(S390SCLPDevice *sdev);
> +} S390SCLPDeviceClass;
> +
> +void sclp_service_interrupt(uint32_t sccb);
> +
> +#endif
> diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
> index 18ac6e3..efd2cda 100644
> --- a/target-s390x/cpu.h
> +++ b/target-s390x/cpu.h
> @@ -294,6 +294,7 @@ void s390x_tod_timer(void *opaque);
> void s390x_cpu_timer(void *opaque);
>
> int s390_virtio_hypercall(CPUS390XState *env, uint64_t mem, uint64_t hypercall);
> +int do_sclp_service_call(uint32_t sccb, uint64_t code);
>
> #ifdef CONFIG_KVM
> void kvm_s390_interrupt(CPUS390XState *env, int type, uint32_t code);
> @@ -596,17 +597,6 @@ static inline const char *cc_name(int cc_op)
> return cc_names[cc_op];
> }
>
> -/* SCLP PV interface defines */
> -#define SCLP_CMDW_READ_SCP_INFO 0x00020001
> -#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
> -
> -#define SCP_LENGTH 0x00
> -#define SCP_FUNCTION_CODE 0x02
> -#define SCP_CONTROL_MASK 0x03
> -#define SCP_RESPONSE_CODE 0x06
> -#define SCP_MEM_CODE 0x08
> -#define SCP_INCREMENT 0x0a
> -
> typedef struct LowCore
> {
> /* prefix area: defined by architecture */
> @@ -955,7 +945,7 @@ static inline void ebcdic_put(uint8_t *p, const char *ascii, int len)
> void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
> int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
> target_ulong *raddr, int *flags);
> -int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code);
> +int sclp_service_call(uint32_t sccb, uint64_t code);
> uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst,
> uint64_t vr);
>
> diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
> index 07edf93..bcb6b2e 100644
> --- a/target-s390x/kvm.c
> +++ b/target-s390x/kvm.c
> @@ -60,9 +60,6 @@
> #define SIGP_STORE_STATUS_ADDR 0x0e
> #define SIGP_SET_ARCH 0x12
>
> -#define SCLP_CMDW_READ_SCP_INFO 0x00020001
> -#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
> -
> const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
> KVM_CAP_LAST_INFO
> };
> @@ -272,7 +269,7 @@ static int kvm_sclp_service_call(CPUS390XState *env, struct kvm_run *run,
> sccb = env->regs[ipbh0 & 0xf];
> code = env->regs[(ipbh0 & 0xf0) >> 4];
>
> - r = sclp_service_call(env, sccb, code);
> + r = sclp_service_call(sccb, code);
> if (r < 0) {
> enter_pgmcheck(env, -r);
> }
> diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
> index abc35dd..e7bb980 100644
> --- a/target-s390x/op_helper.c
> +++ b/target-s390x/op_helper.c
> @@ -2363,13 +2363,11 @@ static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
> }
>
> /*
> + * we handle here the part that belongs to the cpu, e.g. program checks
> * ret < 0 indicates program check, ret = 0,1,2,3 -> cc
> */
> -int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
> +int sclp_service_call(uint32_t sccb, uint64_t code)
Why not move the whole thing into sclp.c? The only thing remaining here are a few sanity checks that would just as well work in generic sclp handling code, right?
Alex
> {
> - int r = 0;
> - int shift = 0;
> -
> #ifdef DEBUG_HELPER
> printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code);
> #endif
> @@ -2382,27 +2380,8 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
> return -PGM_SPECIFICATION;
> }
>
> - switch(code) {
> - case SCLP_CMDW_READ_SCP_INFO:
> - case SCLP_CMDW_READ_SCP_INFO_FORCED:
> - while ((ram_size >> (20 + shift)) > 65535) {
> - shift++;
> - }
> - stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift));
> - stb_phys(sccb + SCP_INCREMENT, 1 << shift);
> - stw_phys(sccb + SCP_RESPONSE_CODE, 0x10);
> -
> - s390_sclp_extint(sccb & ~3);
> - break;
> - default:
> -#ifdef DEBUG_HELPER
> - printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
> -#endif
> - r = 3;
> - break;
> - }
> -
> - return r;
> + /* the complex part is handled by external components */
> + return do_sclp_service_call(sccb, code);
> }
>
> /* SCLP service call */
> @@ -2410,7 +2389,7 @@ uint32_t HELPER(servc)(uint32_t r1, uint64_t r2)
> {
> int r;
>
> - r = sclp_service_call(env, r1, r2);
> + r = sclp_service_call(r1, r2);
> if (r < 0) {
> program_interrupt(env, -r, 4);
> return 0;
> --
> 1.7.11.5
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH 1/4] s390: sclp base support
2012-09-26 15:00 ` Alexander Graf
@ 2012-09-26 16:06 ` Christian Borntraeger
2012-09-26 19:01 ` Alexander Graf
0 siblings, 1 reply; 10+ messages in thread
From: Christian Borntraeger @ 2012-09-26 16:06 UTC (permalink / raw)
To: Alexander Graf
Cc: Heinz Graalfs, qemu-devel, Einar Lueck, Jens Freimann,
Cornelia Huck, Andreas Faerber
On 26/09/12 17:00, Alexander Graf wrote:
>> +/* Provide information about the configuration, CPUs and storage */
>> +static void read_SCP_info(SCCB *sccb)
>> +{
>> + ReadInfo *read_info = (ReadInfo *) sccb;
>> + int shift = 0;
>> +
>> + while ((ram_size >> (20 + shift)) > 65535) {
>> + shift++;
>> + }
>> + read_info->rnmax = cpu_to_be16(ram_size >> (20 + shift));
>> + read_info->rnsize = 1 << shift;
>
> Any reason we can't just always expose rnmax2 and rnsize2 instead? This way we're quite limited on the amount of RAM we can support, right?
Well, we have 65535 * 256 * 1MB == 16TB which is ok for the next 2 or 3 years I guess.
There are actually some rules that decide about rnmax vs rnmax2 etc, and here
the non-2 are appropriate. This might change for systems > 16TB or systems with memory hotplug,
but I would prefer to use those for now. We will add the full logic in case we add memory
hotplug.
[...]
>> + if (be16_to_cpu(work_sccb.h.length) < 8 ||
>
> sizeof(SCCBHeader)
ok
>
>> + be16_to_cpu(work_sccb.h.length) > 4096) {
>
> SCCB_SIZE
ok
>> */
>> -int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>> +int sclp_service_call(uint32_t sccb, uint64_t code)
>
> Why not move the whole thing into sclp.c? The only thing remaining here are a few sanity checks that would just as well work in generic sclp handling code, right?
The idea was two-fold:
- to have one single place were we cross between target-s390x and hw (review feedback from the first series, originally we had all everything in sclp.c)
- to have the checks that the CPU can do over there and the complex things that look into the sccb in sclp.c
But we could certainly move that, your take
Christian
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH 1/4] s390: sclp base support
2012-09-26 16:06 ` Christian Borntraeger
@ 2012-09-26 19:01 ` Alexander Graf
2012-09-26 19:25 ` Christian Borntraeger
0 siblings, 1 reply; 10+ messages in thread
From: Alexander Graf @ 2012-09-26 19:01 UTC (permalink / raw)
To: Christian Borntraeger
Cc: Heinz Graalfs, qemu-devel, Einar Lueck, Jens Freimann,
Cornelia Huck, Andreas Faerber
On 26.09.2012, at 18:06, Christian Borntraeger wrote:
> On 26/09/12 17:00, Alexander Graf wrote:
>
>>> +/* Provide information about the configuration, CPUs and storage */
>>> +static void read_SCP_info(SCCB *sccb)
>>> +{
>>> + ReadInfo *read_info = (ReadInfo *) sccb;
>>> + int shift = 0;
>>> +
>>> + while ((ram_size >> (20 + shift)) > 65535) {
>>> + shift++;
>>> + }
>>> + read_info->rnmax = cpu_to_be16(ram_size >> (20 + shift));
>>> + read_info->rnsize = 1 << shift;
>>
>> Any reason we can't just always expose rnmax2 and rnsize2 instead? This way we're quite limited on the amount of RAM we can support, right?
>
> Well, we have 65535 * 256 * 1MB == 16TB which is ok for the next 2 or 3 years I guess.
> There are actually some rules that decide about rnmax vs rnmax2 etc, and here
> the non-2 are appropriate. This might change for systems > 16TB or systems with memory hotplug,
> but I would prefer to use those for now. We will add the full logic in case we add memory
> hotplug.
Fair enough :).
>
>
> [...]
>
>>> + if (be16_to_cpu(work_sccb.h.length) < 8 ||
>>
>> sizeof(SCCBHeader)
>
> ok
>
>
>>
>>> + be16_to_cpu(work_sccb.h.length) > 4096) {
>>
>> SCCB_SIZE
>
> ok
>
>
>>> */
>>> -int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>>> +int sclp_service_call(uint32_t sccb, uint64_t code)
>>
>> Why not move the whole thing into sclp.c? The only thing remaining here are a few sanity checks that would just as well work in generic sclp handling code, right?
>
> The idea was two-fold:
> - to have one single place were we cross between target-s390x and hw (review feedback from the first series, originally we had all everything in sclp.c)
> - to have the checks that the CPU can do over there and the complex things that look into the sccb in sclp.c
>
> But we could certainly move that, your take
I would still see both fulfilled by having the 2 condition checks in sclp.c. Why don't we need them for kvm? Does kvm check them in the kernel?
Alex
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH 1/4] s390: sclp base support
2012-09-26 19:01 ` Alexander Graf
@ 2012-09-26 19:25 ` Christian Borntraeger
2012-09-26 19:27 ` Alexander Graf
0 siblings, 1 reply; 10+ messages in thread
From: Christian Borntraeger @ 2012-09-26 19:25 UTC (permalink / raw)
To: Alexander Graf
Cc: Heinz Graalfs, qemu-devel, Einar Lueck, Jens Freimann,
Cornelia Huck, Andreas Faerber
On 26/09/12 21:01, Alexander Graf wrote:
>
> On 26.09.2012, at 18:06, Christian Borntraeger wrote:
>
>> On 26/09/12 17:00, Alexander Graf wrote:
>>
>>>> +/* Provide information about the configuration, CPUs and storage */
>>>> +static void read_SCP_info(SCCB *sccb)
>>>> +{
>>>> + ReadInfo *read_info = (ReadInfo *) sccb;
>>>> + int shift = 0;
>>>> +
>>>> + while ((ram_size >> (20 + shift)) > 65535) {
>>>> + shift++;
>>>> + }
>>>> + read_info->rnmax = cpu_to_be16(ram_size >> (20 + shift));
>>>> + read_info->rnsize = 1 << shift;
>>>
>>> Any reason we can't just always expose rnmax2 and rnsize2 instead? This way we're quite limited on the amount of RAM we can support, right?
>>
>> Well, we have 65535 * 256 * 1MB == 16TB which is ok for the next 2 or 3 years I guess.
>> There are actually some rules that decide about rnmax vs rnmax2 etc, and here
>> the non-2 are appropriate. This might change for systems > 16TB or systems with memory hotplug,
>> but I would prefer to use those for now. We will add the full logic in case we add memory
>> hotplug.
>
> Fair enough :).
>
>>
>>
>> [...]
>>
>>>> + if (be16_to_cpu(work_sccb.h.length) < 8 ||
>>>
>>> sizeof(SCCBHeader)
>>
>> ok
>>
>>
>>>
>>>> + be16_to_cpu(work_sccb.h.length) > 4096) {
>>>
>>> SCCB_SIZE
>>
>> ok
>>
>>
>>>> */
>>>> -int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>>>> +int sclp_service_call(uint32_t sccb, uint64_t code)
>>>
>>> Why not move the whole thing into sclp.c? The only thing remaining here are a few sanity checks that would just as well work in generic sclp handling code, right?
>>
>> The idea was two-fold:
>> - to have one single place were we cross between target-s390x and hw (review feedback from the first series, originally we had all everything in sclp.c)
>> - to have the checks that the CPU can do over there and the complex things that look into the sccb in sclp.c
>>
>> But we could certainly move that, your take
>
> I would still see both fulfilled by having the 2 condition checks in sclp.c. Why don't we need them for kvm? Does kvm check them in the kernel?
KVM needs the checks as well. Thats why kvm calls into sclp_service_call (like the tcg) and then evaluates the return value (like tcg). sclp_service_call is the only place that calls into hw/* code. If we move that code into sclp we have two places that call from target to hw/: kvm.c and op_helper.c (now misc_helper.c). But it really doesnt matter, so lets just move that code.
Christian
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [Qemu-devel] [PATCH 1/4] s390: sclp base support
2012-09-26 19:25 ` Christian Borntraeger
@ 2012-09-26 19:27 ` Alexander Graf
0 siblings, 0 replies; 10+ messages in thread
From: Alexander Graf @ 2012-09-26 19:27 UTC (permalink / raw)
To: Christian Borntraeger
Cc: Heinz Graalfs, qemu-devel, Einar Lueck, Jens Freimann,
Cornelia Huck, Andreas Faerber
On 26.09.2012, at 21:25, Christian Borntraeger wrote:
> On 26/09/12 21:01, Alexander Graf wrote:
>>
>> On 26.09.2012, at 18:06, Christian Borntraeger wrote:
>>
>>> On 26/09/12 17:00, Alexander Graf wrote:
>>>
>>>>> +/* Provide information about the configuration, CPUs and storage */
>>>>> +static void read_SCP_info(SCCB *sccb)
>>>>> +{
>>>>> + ReadInfo *read_info = (ReadInfo *) sccb;
>>>>> + int shift = 0;
>>>>> +
>>>>> + while ((ram_size >> (20 + shift)) > 65535) {
>>>>> + shift++;
>>>>> + }
>>>>> + read_info->rnmax = cpu_to_be16(ram_size >> (20 + shift));
>>>>> + read_info->rnsize = 1 << shift;
>>>>
>>>> Any reason we can't just always expose rnmax2 and rnsize2 instead? This way we're quite limited on the amount of RAM we can support, right?
>>>
>>> Well, we have 65535 * 256 * 1MB == 16TB which is ok for the next 2 or 3 years I guess.
>>> There are actually some rules that decide about rnmax vs rnmax2 etc, and here
>>> the non-2 are appropriate. This might change for systems > 16TB or systems with memory hotplug,
>>> but I would prefer to use those for now. We will add the full logic in case we add memory
>>> hotplug.
>>
>> Fair enough :).
>>
>>>
>>>
>>> [...]
>>>
>>>>> + if (be16_to_cpu(work_sccb.h.length) < 8 ||
>>>>
>>>> sizeof(SCCBHeader)
>>>
>>> ok
>>>
>>>
>>>>
>>>>> + be16_to_cpu(work_sccb.h.length) > 4096) {
>>>>
>>>> SCCB_SIZE
>>>
>>> ok
>>>
>>>
>>>>> */
>>>>> -int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
>>>>> +int sclp_service_call(uint32_t sccb, uint64_t code)
>>>>
>>>> Why not move the whole thing into sclp.c? The only thing remaining here are a few sanity checks that would just as well work in generic sclp handling code, right?
>>>
>>> The idea was two-fold:
>>> - to have one single place were we cross between target-s390x and hw (review feedback from the first series, originally we had all everything in sclp.c)
>>> - to have the checks that the CPU can do over there and the complex things that look into the sccb in sclp.c
>>>
>>> But we could certainly move that, your take
>>
>> I would still see both fulfilled by having the 2 condition checks in sclp.c. Why don't we need them for kvm? Does kvm check them in the kernel?
>
> KVM needs the checks as well. Thats why kvm calls into sclp_service_call (like the tcg) and then evaluates the return value (like tcg). sclp_service_call is the only place that calls into hw/* code. If we move that code into sclp we have two places that call from target to hw/: kvm.c and op_helper.c (now misc_helper.c). But it really doesnt matter, so lets just move that code.
Ah! Yes, please just call into sclp.c from kvm.c :).
Alex
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2012-09-26 19:28 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-08-20 14:28 [Qemu-devel] [PATCH 0/4 v4] s390: sclp patch set Jens Freimann
2012-08-20 14:28 ` [Qemu-devel] [PATCH 1/4] s390: sclp base support Jens Freimann
2012-09-26 15:00 ` Alexander Graf
2012-09-26 16:06 ` Christian Borntraeger
2012-09-26 19:01 ` Alexander Graf
2012-09-26 19:25 ` Christian Borntraeger
2012-09-26 19:27 ` Alexander Graf
2012-08-20 14:28 ` [Qemu-devel] [PATCH 2/4] s390: sclp event support Jens Freimann
2012-08-20 14:28 ` [Qemu-devel] [PATCH 3/4] s390: sclp signal quiesce support Jens Freimann
2012-08-20 14:28 ` [Qemu-devel] [PATCH 4/4] s390: sclp ascii console support Jens Freimann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).