qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v7 38/51] i386/xen: add monitor commands to test event inject


From: David Woodhouse
Subject: Re: [PATCH v7 38/51] i386/xen: add monitor commands to test event injection
Date: Tue, 17 Jan 2023 10:41:23 +0000
User-agent: Evolution 3.44.4-0ubuntu1

Hi Markus, thanks for the review.

On Tue, 2023-01-17 at 11:08 +0100, Markus Armbrster wrote:
> David Woodhouse <dwmw2@infradead.org> writes:
> > @@ -1059,3 +1063,137 @@ int xen_evtchn_send_op(struct evtchn_send *send)
> >      return ret;
> >  }
> >  
> > +static const char *type_names[] = {
> > +    "closed",
> > +    "unbound",
> > +    "interdomain",
> > +    "pirq",
> > +    "virq",
> > +    "ipi"
> > +};
> > +
> > +EvtchnInfoList *qmp_xen_event_list(Error **errp)
> > +{
> > +    XenEvtchnState *s = xen_evtchn_singleton;
> > +    EvtchnInfoList *head = NULL, **tail = &head;
> > +    void *shinfo, *pending, *mask;
> > +    int i;
> > +
> > +    if (!s) {
> > +        error_setg(errp, "Xen event channel emulation not enabled");
> > +        return NULL;
> > +    }
> > +
> > +    shinfo = xen_overlay_get_shinfo_ptr();
> > +    if (!shinfo) {
> > +        error_setg(errp, "Xen shared info page not allocated");
> > +        return NULL;
> > +    }
> 
> Suggest a blank line here.

Ack.


> > +    if (xen_is_long_mode()) {
> > +        pending = shinfo + offsetof(struct shared_info, evtchn_pending);
> > +        mask = shinfo + offsetof(struct shared_info, evtchn_mask);
> > +    } else {
> > +        pending = shinfo + offsetof(struct compat_shared_info, 
> > evtchn_pending);
> > +        mask = shinfo + offsetof(struct compat_shared_info, evtchn_mask);
> > +    }
> > +
> > +    QEMU_LOCK_GUARD(&s->port_lock);
> > +
> > +    for (i = 0; i < s->nr_ports; i++) {
> > +        XenEvtchnPort *p = &s->port_table[i];
> > +        EvtchnInfo *info;
> > +
> > +        if (p->type == EVTCHNSTAT_closed) {
> > +            continue;
> > +        }
> > +
> > +        info = g_new0(EvtchnInfo, 1);
> > +
> > +        info->port = i;
> > +        info->type = g_strdup(type_names[p->type]);
> 
> What ensures p->type is in bounds?

Because it's an internal data structure and it's never set to anything
else.

I did ponder a defensive 'else g_strdup_printf("unknown type %d")' and
IIRC even started typing it, but then stopped.

Although actually, that was before I was asked to convert to QMP, and
it wasn't as simple as g_strdup_printf(). It's probably easier now. I
can do it if you prefer, just for appearance's sake and paranoia?

> > +        if (p->type == EVTCHNSTAT_interdomain) {
> > +            info->remote_domain = g_strdup((p->type_val & 
> > PORT_INFO_TYPEVAL_REMOTE_QEMU) ?
> > +                                           "qemu" : "loopback");
> > +            info->target = p->type_val & 
> > PORT_INFO_TYPEVAL_REMOTE_PORT_MASK;
> > +        } else {
> > +            info->target = p->type_val;
> > +        }
> > +        info->vcpu = p->vcpu;
> > +        info->pending = test_bit(i, pending);
> > +        info->masked = test_bit(i, mask);
> > +
> > +        QAPI_LIST_APPEND(tail, info);
> > +    }
> > +
> > +    return head;
> > +}
> > +
> > +void qmp_xen_event_inject(uint32_t port, Error **errp)
> > +{
> > +    XenEvtchnState *s = xen_evtchn_singleton;
> > +
> > +    if (!s) {
> > +        error_setg(errp, "Xen event channel emulation not enabled");
> > +        return;
> > +    }
> > +
> > +    if (!valid_port(port)) {
> > +        error_setg(errp, "Invalid port %u", port);
> > +    }
> > +
> > +    QEMU_LOCK_GUARD(&s->port_lock);
> > +
> > +    if (set_port_pending(s, port)) {
> > +        error_setg(errp, "Failed to set port %u", port);
> > +        return;
> > +    }
> > +}
> > +
> > +void hmp_xen_event_list(Monitor *mon, const QDict *qdict)
> > +{
> > +    EvtchnInfoList *iter, *info_list;
> > +    Error *err = NULL;
> > +
> > +    info_list = qmp_xen_event_list(&err);
> > +    if (err) {
> > +        hmp_handle_error(mon, err);
> > +        return;
> > +    }
> > +
> > +    for (iter = info_list; iter; iter = iter->next) {
> > +        EvtchnInfo *info = iter->value;
> > +
> > +        monitor_printf(mon, "port %4lu: vcpu: %ld %s", info->port, 
> > info->vcpu,
> > +                       info->type);
> > +        if (strcmp(info->type, "ipi")) {
> > +            monitor_printf(mon,  "(");
> > +            if (info->remote_domain) {
> > +                monitor_printf(mon, "%s:", info->remote_domain);
> > +            }
> > +            monitor_printf(mon, "%ld)", info->target);
> > +        }
> > +        if (info->pending) {
> > +            monitor_printf(mon, " PENDING");
> > +        }
> > +        if (info->masked) {
> > +            monitor_printf(mon, " MASKED");
> > +        }
> > +        monitor_printf(mon, "\n");
> > +    }
> > +
> > +    qapi_free_EvtchnInfoList(info_list);
> > +}
> > +
> > +void hmp_xen_event_inject(Monitor *mon, const QDict *qdict)
> > +{
> > +    int port = qdict_get_int(qdict, "port");
> > +    Error *err = NULL;
> > +
> > +    qmp_xen_event_inject(port, &err);
> > +    if (err) {
> > +        hmp_handle_error(mon, err);
> > +    } else {
> > +        monitor_printf(mon, "Delivered port %d\n", port);
> > +    }
> > +}
> > +
> 
> In general, I prefer to keep HMP commands separate, say in
> i386-kvm-hmp-cmds.c.  Not sure it's worth the trouble here.
> 
> > diff --git a/hw/i386/kvm/xen_evtchn.h b/hw/i386/kvm/xen_evtchn.h
> > index 5d3e03553f..670f8b3f7d 100644
> > --- a/hw/i386/kvm/xen_evtchn.h
> > +++ b/hw/i386/kvm/xen_evtchn.h
> > @@ -16,6 +16,9 @@ void xen_evtchn_create(void);
> >  int xen_evtchn_soft_reset(void);
> >  int xen_evtchn_set_callback_param(uint64_t param);
> >  
> > +void hmp_xen_event_inject(Monitor *mon, const QDict *qdict);
> > +void hmp_xen_event_list(Monitor *mon, const QDict *qdict);
> > +
> 
> Have you considered include/monitor/hmp.h?
> 
> >  struct evtchn_status;
> >  struct evtchn_close;
> >  struct evtchn_unmask;
> > diff --git a/monitor/misc.c b/monitor/misc.c
> > index bf3f1c67ca..7d8c473ffb 100644
> > --- a/monitor/misc.c
> > +++ b/monitor/misc.c
> > @@ -82,6 +82,10 @@
> >  /* Make devices configuration available for use in hmp-commands*.hx 
> > templates */
> >  #include CONFIG_DEVICES
> >  
> > +#ifdef CONFIG_XEN_EMU
> > +#include "hw/i386/kvm/xen_evtchn.h"
> > +#endif
> > +
> 
> Uh... what for?
> 

For hmp_xen_event_{inject,list}, so I can drop this after I move those
declarations to include/monitor/hmp.h as you suggested. Thanks.

> >  /* file descriptors passed via SCM_RIGHTS */
> >  typedef struct mon_fd_t mon_fd_t;
> >  struct mon_fd_t {
> > diff --git a/qapi/misc.json b/qapi/misc.json
> > index 27ef5a2b20..6284f86a5b 100644
> > --- a/qapi/misc.json
> > +++ b/qapi/misc.json
> > @@ -584,3 +584,94 @@
> >  { 'event': 'VFU_CLIENT_HANGUP',
> >    'data': { 'vfu-id': 'str', 'vfu-qom-path': 'str',
> >              'dev-id': 'str', 'dev-qom-path': 'str' } }
> > +
> > +##
> > +# @EvtchnInfo:
> > +#
> > +# Information about a Xen event channel port
> > +#
> > +# @port: the port number
> > +#
> > +# @vcpu: target vCPU for this port
> > +#
> > +# @type: the port type
> > +#
> > +# @remote-domain: remote domain for interdomain ports
> > +#
> > +# @target: remote port ID, or virq/pirq number
> > +#
> > +# @pending: port is currently active pending delivery
> > +#
> > +# @masked: port is masked
> > +#
> > +# Since: x.xx
> 
> "Since: 8.0.0" (with any luck).  More of the same below.
> 
> > +##
> > +{ 'struct': 'EvtchnInfo',
> > +  'data': {'port': 'int',
> > +          'vcpu': 'int',
> > +          'type': 'str',
> 
> Could we make this a QAPI enum?

That would be good; I didn't spot that those existed. 

> > +          'remote-domain': 'str',
> > +          'target': 'int',
> > +          'pending': 'bool',
> > +          'masked': 'bool'}}
> > +
> > +
> > +##
> > +# @xen-event-list:
> > +#
> > +# Query the Xen event channels opened by the guest.
> > +#
> > +# Returns: list of open event channel ports.
> > +#
> > +# Since: x.xx
> > +#
> > +# Example:
> > +#
> > +# -> { "execute": "xen-event-list" }
> > +# <- { "return": [
> > +#         {
> > +#             "pending": false,
> > +#             "port": 1,
> > +#             "vcpu": 1,
> > +#             "remote-domain": "qemu",
> > +#             "masked": false,
> > +#             "type": "interdomain",
> > +#             "target": 1
> > +#         },
> > +#         {
> > +#             "pending": false,
> > +#             "port": 2,
> > +#             "vcpu": 0,
> > +#             "remote-domain": "",
> 
> Uh, "" is possible?  @remote-domain's doc string didn't prepare me for
> that.  What does it mean?
> 

It means "this is a type for which remote_domain isn't meaningful,
because it isn't an interdomain port at all. In an ideal world, the
remote_domain element wouldn't even exist but Dave didn't know how to
make it optional/absent and forgot to call attention to that in the
commit message."

> > +#             "masked": false,
> > +#             "type": "virq",
> > +#             "target": 0
> > +#         }
> > +#      ]
> > +#    }
> > +#
> > +##
> > +{ 'command': 'xen-event-list',
> > +  'returns': ['EvtchnInfo']
> > +}
> > +
> > +##
> > +# @xen-event-inject:
> > +#
> > +# Inject a Xen event channel port to the guest.
> 
> Would it be useful to explain what it means to "inject a Xen event
> channel port to the guest"?  I have no idea, but perhaps we believe
> interested in this command should be able to explain it in their sleep.

It's an interrupt. I'll just put '(interrupt)' after the word 'port'.

> > +#
> > +# @port: The port number
> > +#
> > +# Returns: - Nothing on success.
> > +#
> > +# Since: x.xx
> > +#
> > +# Example:
> > +#
> > +# -> { "execute": "xen-event-inject", "arguments": { "port": 1 } }
> > +# <- { "return": { } }
> > +#
> > +##
> > +{ 'command': 'xen-event-inject',
> > +  'data': { 'port': 'uint32' }
> > +}
> 
> Did you consider 'if': 'CONFIG_XEN'?

This is the "Xen emulation on not-Xen" code, so it isn't CONFIG_XEN.

It would have been CONFIG_XEN_EMU perhaps, but that's a target-specific
option.

> Hmm, it's target-dependent, so it would have to go into
> misc-target.json.  qmp_xen_event_inject() then needs target-dependent
> header qapi/qapi-commands-misc-target.h.  Fine if it's in a
> target-dependent .c anyway.  Else it could be more trouble than it's
> worth.

I'd already put empty stubs in to cover other targets, but it would be
good to drop those. Will play and send an incremental patch. Thanks.



Attachment: smime.p7s
Description: S/MIME cryptographic signature


reply via email to

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