qemu-devel
[Top][All Lists]
Advanced

[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);
> >
> 





reply via email to

[Prev in Thread] Current Thread [Next in Thread]