[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support
From: |
Heinz Graalfs |
Subject: |
Re: [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support |
Date: |
Wed, 13 Jun 2012 09:27:38 +0200 |
On Tue, 2012-06-12 at 13:52 +0200, Alexander Graf wrote:
> On 06/06/2012 02:05 PM, Jens Freimann wrote:
> > From: Heinz Graalfs<address@hidden>
> >
> > Adds console support (in vt220 mode).
> > In order to run qemu exploiting the SCLP's console functionality in vt220
> > mode
> > the user has to specify the following console related parameters:
> >
> > -chardev stdio,id=charconsole0 -device
> > sclpconsole,chardev=charconsole0,id=console0
> >
> > Signed-off-by: Heinz Graalfs<address@hidden>
> > Signed-off-by: Jens Freimann<address@hidden>
> > ---
> > hw/s390-event-facility.c | 209
> > ++++++++++++++++++++++++++++++++++++++++++++++
> > hw/s390-event-facility.h | 8 ++
> > hw/s390-sclp.c | 177 ++++++++++++++++++++++++++++++++++++++-
> > hw/s390-sclp.h | 22 ++++-
> > sysemu.h | 1 +
> > target-s390x/op_helper.c | 6 ++
> > vl.c | 41 +++++++++
> > 7 files changed, 460 insertions(+), 4 deletions(-)
> >
> > diff --git a/hw/s390-event-facility.c b/hw/s390-event-facility.c
> > index b8106a6..cfa5dd4 100644
> > --- a/hw/s390-event-facility.c
> > +++ b/hw/s390-event-facility.c
> > @@ -16,6 +16,11 @@
> > #include "s390-sclp.h"
> > #include "s390-event-facility.h"
> >
> > +qemu_irq sclp_read_vt220;
> > +
> > +static int size_buffer = 4096;
> > +static char *sclp_console_data_vt220;
>
> Globals?
>
ok, I'll look into this
> > +
> > struct SCLPDevice {
> > const char *name;
> > bool vm_running;
> > @@ -224,9 +229,213 @@ static TypeInfo sclp_quiesce_info = {
> > .class_init = sclpef_quiesce_class_init,
> > };
> >
> > +/* ----------- SCLP VT220 console ------------ */
> > +
> > +static void s390_signal_read_vt220(void *opaque, int n, int level)
> > +{
> > + sclp_enable_signal_read_vt220();
> > + sclp_service_interrupt(opaque, 0);
> > +}
> > +
> > +static void sclpef_set_console(SCLPEvent *event)
> > +{
> > + if (event->id == ID_VT220) {
> > + sclp_read_vt220 = *qemu_allocate_irqs(s390_signal_read_vt220,
> > + event->evt_fac->opaque, 1);
> > + }
> > +}
> > +
> > +void sclpef_write_console_vt220(SCLPDevice *sdev, char *buf)
> > +{
> > + DeviceState *dev;
> > + SCLPEventFacility *event_facility;
> > + static SCLPEvent *event;
> > + static SCLPEventClass *cons;
> > +
> > + event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> > +
> > + if (!cons) {
> > + QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> > + event = (SCLPEvent *) dev;
> > + if (event->id == ID_VT220) {
> > + cons = SCLP_EVENT_GET_CLASS(event);
> > + assert(cons->have_data);
> > + break;
> > + }
> > + }
> > + }
>
> I don't understand the above code. Why do you have to search for
> anything when you're in a call to process a write?
The loop occurs once to find the console.
OK, I'll add an entry to SCLPEvent structure and use that
(getting rid of the loop).
>
> > + if (cons) {
> > + cons->have_data(event, (const uint8_t *)buf, strlen(buf));
> > + }
> > +}
> > +
> > +char *sclpef_get_console_data_vt220(SCLPDevice *sdev)
> > +{
> > + DeviceState *dev;
> > + SCLPEventFacility *event_facility;
> > + SCLPEvent *event = NULL;
> > + static SCLPEventClass *cons;
> > +
> > + event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> > +
> > + if (!cons) {
> > + QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> > + event = (SCLPEvent *) dev;
> > + if (event->id == ID_VT220) {
> > + cons = SCLP_EVENT_GET_CLASS(event);
> > + assert(cons->get_data);
> > + break;
> > + }
> > + }
> > + }
>
> See above.
>
The loop occurs once to find the console.
OK, I'll add an entry to SCLPEvent structure and use that
(getting rid of the loop).
> > + if (cons) {
> > + return cons->get_data();
> > + }
> > + return NULL;
> > +}
> > +
> > +static char *console_data_vt220(void)
> > +{
> > + return sclp_console_data_vt220;
> > +}
> > +
> > +static ssize_t flush_buf(SCLPEvent *event, const uint8_t *buf, size_t len)
> > +{
> > + SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> > + ssize_t ret;
> > +
> > + if (!scon->chr) {
> > + /* If there's no backend, we can just say we consumed all data. */
> > + return len;
> > + }
> > +
> > + ret = qemu_chr_fe_write(scon->chr, buf, len);
> > +
> > + if (ret< 0) {
> > + /* see virtio-console comments */
> > + ret = 0;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static void guest_open(SCLPEvent *event)
> > +{
> > + SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> > +
> > + if (!scon->chr) {
> > + return;
> > + }
> > + qemu_chr_fe_open(scon->chr);
> > +}
> > +
> > +static void guest_close(SCLPEvent *event)
> > +{
> > + SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> > +
> > + if (!scon->chr) {
> > + return;
> > + }
> > + qemu_chr_fe_close(scon->chr);
> > +}
> > +
> > +static int chr_can_read(void *opaque)
> > +{
> > + return 1;
> > +}
> > +
> > +static void chr_read_vt220(void *opaque, const uint8_t *buf, int size)
> > +{
> > + char *offset;
> > +
> > + if (!sclp_console_data_vt220) {
> > + size_buffer = 2 * size;
>
> Why 2*?
>
OK, will change to exact size plus 1 for trailing 0
> > + sclp_console_data_vt220 = malloc(size_buffer);
>
> %s/malloc/g_malloc0/g
>
OK
> > + }
> > + if (size_buffer< size + 1) {
>
> This could use a comment.
>
OK
> > + free(sclp_console_data_vt220);
> > + size_buffer = 2 * size;
> > + sclp_console_data_vt220 = malloc(size_buffer);
> > + }
> > + offset = sclp_console_data_vt220;
> > + if (offset) {
> > + memcpy(offset, buf, size);
> > + offset += size;
> > + *offset = '\0';
>
> How do you know you're not out of bounds?
>
OK, size + 1
> > + qemu_irq_raise(sclp_read_vt220);
> > + } else {
> > + size_buffer = 0;
> > + }
> > +}
> > +
> > +static void chr_event(void *opaque, int event)
> > +{
> > + switch (event) {
> > + case CHR_EVENT_OPENED:
> > + if (!sclp_console_data_vt220) {
> > + sclp_console_data_vt220 = malloc(size_buffer);
> > + }
> > + break;
> > + case CHR_EVENT_CLOSED:
> > + break;
> > + }
> > +}
> > +
> > +static unsigned int send_mask_vt220(void)
> > +{
> > + return SCLP_EVENT_MASK_MSG_ASCII;
> > +}
> > +
> > +static unsigned int receive_mask_vt220(void)
> > +{
> > + return SCLP_EVENT_MASK_MSG_ASCII;
> > +}
> > +
> > +static int sclpconsole_initfn_vt220(SCLPEvent *event)
> > +{
> > + SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
> > +
> > + event->id = ID_VT220;
> > + sclpef_set_console(event);
> > + if (scon->chr) {
> > + qemu_chr_add_handlers(scon->chr, chr_can_read,
> > + chr_read_vt220, chr_event, scon);
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static Property sclpconsole_properties[] = {
> > + DEFINE_PROP_CHR("chardev", SCLPConsole, chr),
> > + DEFINE_PROP_END_OF_LIST(),
> > +};
> > +
> > +static void sclpconsole_class_init(ObjectClass *klass, void *data)
> > +{
> > + DeviceClass *dc = DEVICE_CLASS(klass);
> > + SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
> > +
> > + k->init = sclpconsole_initfn_vt220;
> > + k->have_data = flush_buf;
> > + k->guest_open = guest_open;
> > + k->guest_close = guest_close;
> > + k->get_send_mask = send_mask_vt220;
> > + k->get_receive_mask = receive_mask_vt220;
> > + k->get_data = console_data_vt220;
> > + dc->props = sclpconsole_properties;
> > +}
> > +
> > +static TypeInfo sclpconsole_info = {
> > + .name = "sclpconsole",
> > + .parent = TYPE_SCLP_EVENT,
> > + .instance_size = sizeof(SCLPConsole),
> > + .class_init = sclpconsole_class_init,
> > +};
> > +
> > static void sclpef_register_types(void)
> > {
> > type_register_static(&sclp_event_facility_type_info);
> > type_register_static(&sclp_quiesce_info);
> > + type_register_static(&sclpconsole_info);
> > }
> > type_init(sclpef_register_types)
> > diff --git a/hw/s390-event-facility.h b/hw/s390-event-facility.h
> > index 40d4049..d6bde7d 100644
> > --- a/hw/s390-event-facility.h
> > +++ b/hw/s390-event-facility.h
> > @@ -14,6 +14,7 @@
> > #include "qemu-common.h"
> >
> > #define ID_QUIESCE SCLP_EVENT_SIGNAL_QUIESCE
> > +#define ID_VT220 SCLP_EVENT_ASCII_CONSOLE_DATA
> >
> > #define TYPE_SCLP_EVENT "s390-sclp-event-type"
> > #define SCLP_EVENT(obj) \
> > @@ -34,6 +35,11 @@ typedef struct SCLPEventClass {
> > int (*exit)(SCLPEvent *event);
> > unsigned int (*get_send_mask)(void);
> > unsigned int (*get_receive_mask)(void);
> > + void (*guest_open)(SCLPEvent *event);
> > + void (*guest_close)(SCLPEvent *event);
> > + void (*guest_ready)(SCLPEvent *event);
> > + ssize_t (*have_data)(SCLPEvent *event, const uint8_t *buf, size_t len);
> > + char *(*get_data)(void);
> > } SCLPEventClass;
> >
> > struct SCLPEvent {
> > @@ -50,5 +56,7 @@ void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque);
> > void sclpef_set_masks(void);
> > unsigned int sclpef_send_mask(SCLPDevice *sdev);
> > unsigned int sclpef_receive_mask(SCLPDevice *sdev);
> > +void sclpef_write_console_vt220(SCLPDevice *sdev, char *buf);
> > +char *sclpef_get_console_data_vt220(SCLPDevice *sdev);
> >
> > #endif
> > diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
> > index 683a709..8f45773 100644
> > --- a/hw/s390-sclp.c
> > +++ b/hw/s390-sclp.c
> > @@ -11,6 +11,11 @@
> > #include "hw/s390-sclp.h"
> > #include "hw/s390-event-facility.h"
> >
> > +/* input buffer handling */
> > +#define INP_BUFFER_SIZE 4096
> > +static int sclp_curr_buf_size;
> > +static char *sclp_input_vt220;
> > +
> > /* Host capabilites */
> > static unsigned int sclp_send_mask;
> > static unsigned int sclp_receive_mask;
> > @@ -21,6 +26,7 @@ static unsigned int sclp_cp_receive_mask;
> >
> > static int quiesce;
> > static int event_pending;
> > +static int vt220;
>
> If anything, this is a machine variable, no? What is this supposed to
> express?
>
> >
> > int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
> > {
> > @@ -66,6 +72,7 @@ void sclp_enable_signal_quiesce(void)
> > {
> > quiesce = 1;
> > event_pending = 1;
> > + vt220 = 0;
> > }
> >
> > static void sclp_set_masks(void)
> > @@ -81,7 +88,112 @@ static void sclp_set_masks(void)
> >
> > sclp_send_mask = sclpef_send_mask(evt_fac->sdev);
> > sclp_receive_mask = sclpef_receive_mask(evt_fac->sdev);
> > - }
> > +}
> > +
> > +static int signal_vt220_event(struct sccb *sccb, int *slen)
> > +{
> > + char *p;
> > +
> > + if (!sclp_input_vt220 || !vt220) {
> > + return 0;
> > + }
> > +
> > + int l = strlen(sclp_input_vt220);
> > +
> > + if (*slen< sizeof(struct ascii_cons_data_command) + l + 1) {
> > + event_pending = 1;
> > + return 0;
> > + }
> > + p = (char *)&sccb->c.read.acd_cmd.data;
> > + /* first byte is hex 0 saying an ascii string follows */
> > + *p++ = '\0';
> > + memmove(p, sclp_input_vt220, l);
> > + *sclp_input_vt220 = '\0';
> > +
> > + sccb->c.read.acd_cmd.h.length =
> > + cpu_to_be16(sizeof(struct ascii_cons_data_command) + l + 1);
> > + sccb->c.read.acd_cmd.h.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
> > +
> > + vt220 = 0;
> > + *slen -= sizeof(struct ascii_cons_data_command) + l + 1;
> > + return 1;
> > +}
> > +
> > +static char *grow_buffer(int size)
> > +{
> > + char *p = (char *) malloc(size);
> > +
> > + if (!p) {
> > + sclp_curr_buf_size = 0;
> > + return NULL;
> > + }
> > + memset(p, '\0', size);
> > + sclp_curr_buf_size = size;
> > + return p;
> > +}
> > +
> > +static int sclp_write_vt220(struct event_buffer_header *event)
> > +{
> > + int l;
> > + char *msg;
> > + SCLPS390EventFacility *evt_fac;
> > + struct ascii_cons_data_command *ad =
> > + (struct ascii_cons_data_command *) event;
> > +
> > + assert(sclp_bus);
> > +
> > + l = event->length - sizeof(struct event_buffer_header);
> > + msg = (char *) malloc(l + 1);
> > + assert(msg);
> > + memset(msg, '\0', l + 1);
> > + memmove(msg, ad->data, l);
>
> Why the copy? Also, for such short lived data, you're probably better
> off using alloca.
>
OK, I'll look into this
> > +
> > + evt_fac = sclp_bus->event_facility;
> > + sclpef_write_console_vt220(evt_fac->sdev, msg);
> > +
> > + free(msg);
> > +
> > + return SCLP_RC_NORMAL_COMPLETION;
> > +}
> > +
> > +void sclp_enable_signal_read_vt220(void)
> > +{
> > + int len;
> > + char *input;
> > + SCLPS390EventFacility *evt_fac;
> > +
> > + if (!sclp_bus) {
> > + return;
> > + }
> > + evt_fac = sclp_bus->event_facility;
> > +
> > + assert(evt_fac);
> > +
> > + input = sclpef_get_console_data_vt220(evt_fac->sdev);
> > +
> > + if (!input) {
> > + return;
> > + }
> > +
> > + vt220 = 1;
> > + quiesce = 0;
> > + event_pending = 1;
> > + len = strlen((char *) input);
> > + if (sclp_input_vt220 == NULL) {
> > + /* get new buffer */
> > + sclp_input_vt220 = grow_buffer(2 * len + 1);
> > + } else {
> > + if (len>= sclp_curr_buf_size) {
> > + /* get larger buffer */
> > + char *p = grow_buffer(2 * len + 1);
> > + free(sclp_input_vt220);
> > + sclp_input_vt220 = p;
> > + }
> > + }
> > + if (sclp_input_vt220) {
> > + strcat(sclp_input_vt220, (char *)input);
> > + }
> > +}
> >
> > int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
> > {
> > @@ -99,7 +211,8 @@ int sclp_read_event_data(CPUS390XState *env, struct sccb
> > *sccb)
> > break;
> > case SCLP_SELECTIVE_READ:
> > if (!(sclp_cp_receive_mask& be32_to_cpu(sccb->c.read.mask))) {
> > - sccb->h.response_code =
> > cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
> > + sccb->h.response_code =
> > + cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
> > goto out;
> > }
> > sclp_active_selection_mask = be32_to_cpu(sccb->c.read.mask);
> > @@ -117,7 +230,12 @@ int sclp_read_event_data(CPUS390XState *env, struct
> > sccb *sccb)
> > sccb->h.response_code =
> > cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
> > }
> > }
> > -
> > + if (sclp_active_selection_mask& SCLP_EVENT_MASK_MSG_ASCII) {
> > + if (signal_vt220_event(sccb,&slen)) {
> > + sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
> > + sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
> > + }
> > + }
> > if (sccb->h.control_mask[2]& SCLP_VARIABLE_LENGTH_RESPONSE) {
> > sccb->h.control_mask[2]&= ~SCLP_VARIABLE_LENGTH_RESPONSE;
> > sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
> > @@ -127,6 +245,59 @@ out:
> > return 0;
> > }
> >
> > +int sclp_write_event_data(CPUS390XState *env, struct sccb *sccb)
> > +{
> > + struct event_buffer_header *event;
> > + int slen;
> > + unsigned elen = 0;
> > +
> > + 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 check the sum of all events */
> > + event =&sccb->c.event;
> > + for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
> > + slen> 0; slen -= elen) {
> > + elen = be16_to_cpu(event->length);
> > + if (elen< sizeof(*event) || elen> slen) {
> > + sccb->h.response_code =
> > + cpu_to_be16(SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR);
> > + goto out;
> > + }
> > + event = (void *) event + elen;
> > + }
> > + if (slen) {
> > + sccb->h.response_code = cpu_to_be16(SCLP_RC_INCONSISTENT_LENGTHS);
> > + goto out;
> > + }
> > +
> > + /* the execute */
> > + event =&sccb->c.event;
> > + for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
> > + slen> 0; slen -= elen) {
> > + elen = be16_to_cpu(event->length);
> > + switch (event->type) {
> > + case SCLP_EVENT_ASCII_CONSOLE_DATA:
> > + sccb->h.response_code = cpu_to_be16(sclp_write_vt220(event));
> > + break;
>
> This also screams for a generic dispatcher.
>
> > + default:
> > + sccb->h.response_code = SCLP_RC_INVALID_FUNCTION;
> > + break;
> > + }
> > + event = (void *) event + elen;
> > + }
> > + sccb->h.response_code = SCLP_RC_NORMAL_COMPLETION;
> > +
> > +out:
> > + return 0;
> > +}
> > +
> > int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb)
> > {
> > /* Attention: We assume that Linux uses 4-byte masks, what it actually
> > diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
> > index f61421b..c86bca8 100644
> > --- a/hw/s390-sclp.h
> > +++ b/hw/s390-sclp.h
> > @@ -7,6 +7,8 @@
> > /* 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_WRITE_EVENT_MASK 0x00780005
> >
> > /* SCLP response codes */
> > @@ -20,11 +22,12 @@
> > #define SCLP_RC_INVALID_MASK_LENGTH 0x74f0
> >
> > /* 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 0x40000000
> > +#define SCLP_EVENT_MASK_MSG_ASCII 0x00000040
> >
> > #define SCLP_UNCONDITIONAL_READ 0x00
> > #define SCLP_SELECTIVE_READ 0x01
> > @@ -44,6 +47,13 @@ struct write_event_mask {
> > uint32_t receive_mask;
> > } __attribute__((packed));
> >
> > +struct mdb_header {
> > + uint16_t length;
> > + uint16_t type;
> > + uint32_t tag;
> > + uint32_t revision_code;
> > +} __attribute__((packed));
> > +
> > struct event_buffer_header {
> > uint16_t length;
> > uint8_t type;
> > @@ -58,9 +68,15 @@ struct signal_quiesce {
> > uint8_t unit;
> > } __attribute__((packed));
> >
> > +struct ascii_cons_data_command {
> > + struct event_buffer_header h;
> > + char data[0];
> > +} __attribute__((packed));
> > +
> > struct read_event_data {
> > union {
> > struct signal_quiesce quiesce;
> > + struct ascii_cons_data_command acd_cmd;
> > uint32_t mask;
> > };
> > } __attribute__((packed));
> > @@ -84,15 +100,19 @@ struct sccb {
> > struct sccb_header h;
> > union {
> > struct read_info_sccb read_info;
> > + struct event_buffer_header event;
> > struct read_event_data read;
> > + struct ascii_cons_data_command acd_cmd;
> > struct write_event_mask we_mask;
> > char data[SCCB_DATA_LEN];
> > } c;
> > } __attribute__((packed));
> >
> > void sclp_enable_signal_quiesce(void);
> > +void sclp_enable_signal_read_vt220(void);
> > int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
> > int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb);
> > +int sclp_write_event_data(CPUS390XState *env, struct sccb *sccb);
> > int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb);
> > void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);
> >
> > diff --git a/sysemu.h b/sysemu.h
> > index bc2c788..b4d399c 100644
> > --- a/sysemu.h
> > +++ b/sysemu.h
> > @@ -62,6 +62,7 @@ int qemu_powerdown_requested(void);
> > void qemu_system_killed(int signal, pid_t pid);
> > void qemu_kill_report(void);
> > extern qemu_irq qemu_system_powerdown;
> > +extern qemu_irq sclp_read_vt220;
> > void qemu_system_reset(bool report);
> >
> > void qemu_add_exit_notifier(Notifier *notify);
> > diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
> > index 3e5eff4..4d49472 100644
> > --- a/target-s390x/op_helper.c
> > +++ b/target-s390x/op_helper.c
> > @@ -2391,6 +2391,12 @@ int sclp_service_call(CPUS390XState *env, uint32_t
> > sccb, uint64_t code)
> > case SCLP_CMDW_READ_SCP_INFO_FORCED:
> > r = sclp_read_info(env,&work_sccb);
> > break;
> > + case SCLP_CMD_READ_EVENT_DATA:
> > + r = sclp_read_event_data(env,&work_sccb);
> > + break;
> > + case SCLP_CMD_WRITE_EVENT_DATA:
> > + r = sclp_write_event_data(env,&work_sccb);
> > + break;
> > case SCLP_CMD_WRITE_EVENT_MASK:
> > r = sclp_write_event_mask(env,&work_sccb);
> > break;
> > diff --git a/vl.c b/vl.c
> > index 23ab3a3..aba7ab0 100644
> > --- a/vl.c
> > +++ b/vl.c
> > @@ -174,6 +174,7 @@ int main(int argc, char **argv)
> > #define DEFAULT_RAM_SIZE 128
> >
> > #define MAX_VIRTIO_CONSOLES 1
> > +#define MAX_SCLP_CONSOLES 1
> >
> > static const char *data_dir;
> > const char *bios_name = NULL;
> > @@ -201,6 +202,7 @@ int no_quit = 0;
> > CharDriverState *serial_hds[MAX_SERIAL_PORTS];
> > CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
> > CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
> > +CharDriverState *sclpcon_hds[MAX_SCLP_CONSOLES];
> > int win2k_install_hack = 0;
> > int usb_enabled = 0;
> > int singlestep = 0;
> > @@ -274,6 +276,8 @@ static int default_floppy = 1;
> > static int default_cdrom = 1;
> > static int default_sdcard = 1;
> > static int default_vga = 1;
> > +static int default_sclpcon = 1;
> > +static int default_loader = 1;
> >
> > static struct {
> > const char *driver;
> > @@ -295,6 +299,8 @@ static struct {
> > { .driver = "isa-cirrus-vga", .flag =&default_vga },
> > { .driver = "vmware-svga", .flag =&default_vga },
> > { .driver = "qxl-vga", .flag =&default_vga },
> > + { .driver = "s390-sclp", .flag =&default_sclpcon },
> > + { .driver = "s390-ipl", .flag =&default_loader },
> > };
> >
> > static void res_free(void)
> > @@ -1942,6 +1948,7 @@ struct device_config {
> > DEV_VIRTCON, /* -virtioconsole */
> > DEV_DEBUGCON, /* -debugcon */
> > DEV_GDB, /* -gdb, -s */
> > + DEV_SCLPCON, /* sclp console */
> > } type;
> > const char *cmdline;
> > Location loc;
> > @@ -2058,6 +2065,36 @@ static int virtcon_parse(const char *devname)
> > return 0;
> > }
> >
> > +static int sclpcon_parse(const char *devname)
> > +{
> > + QemuOptsList *device = qemu_find_opts("device");
> > + static int index;
> > + char label[32];
> > + QemuOpts *dev_opts;
> > +
> > + if (strcmp(devname, "none") == 0)
> > + return 0;
>
> Apart from that part not passing checkpatch, why do we have to
> reimplement this for every char device?
>
OK, I'll look into this if this is really needed
>
> Alex
>
> > + if (index == MAX_SCLP_CONSOLES) {
> > + fprintf(stderr, "qemu: too many sclp consoles\n");
> > + exit(1);
> > + }
> > +
> > + dev_opts = qemu_opts_create(device, NULL, 0);
> > + qemu_opt_set(dev_opts, "driver", "sclpconsole");
> > +
> > + snprintf(label, sizeof(label), "sclpcon%d", index);
> > + sclpcon_hds[index] = qemu_chr_new(label, devname, NULL);
> > + if (!sclpcon_hds[index]) {
> > + fprintf(stderr, "qemu: could not open sclp console '%s': %s\n",
> > + devname, strerror(errno));
> > + return -1;
> > + }
> > + qemu_opt_set(dev_opts, "chardev", label);
> > +
> > + index++;
> > + return 0;
> > +}
> > +
> > static int debugcon_parse(const char *devname)
> > {
> > QemuOpts *opts;
> > @@ -3304,6 +3341,8 @@ int main(int argc, char **argv, char **envp)
> > add_device_config(DEV_SERIAL, "mon:stdio");
> > } else if (default_virtcon&& default_monitor) {
> > add_device_config(DEV_VIRTCON, "mon:stdio");
> > + } else if (default_sclpcon&& default_monitor) {
> > + add_device_config(DEV_SCLPCON, "mon:stdio");
> > } else {
> > if (default_serial)
> > add_device_config(DEV_SERIAL, "stdio");
> > @@ -3491,6 +3530,8 @@ int main(int argc, char **argv, char **envp)
> > exit(1);
> > if (foreach_device_config(DEV_VIRTCON, virtcon_parse)< 0)
> > exit(1);
> > + if (foreach_device_config(DEV_SCLPCON, sclpcon_parse)< 0)
> > + exit(1);
> > if (foreach_device_config(DEV_DEBUGCON, debugcon_parse)< 0)
> > exit(1);
> >
>
[Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions, Jens Freimann, 2012/06/06