[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.
smime.p7s
Description: S/MIME cryptographic signature
- Re: [PATCH v7 26/51] hw/xen: Add xen_evtchn device for event channel emulation, (continued)
- Re: [PATCH v7 26/51] hw/xen: Add xen_evtchn device for event channel emulation, David Woodhouse, 2023/01/17
- Re: [PATCH v7 26/51] hw/xen: Add xen_evtchn device for event channel emulation, Paul Durrant, 2023/01/17
- Re: [PATCH v7 26/51] hw/xen: Add xen_evtchn device for event channel emulation, David Woodhouse, 2023/01/17
- Re: [PATCH v7 26/51] hw/xen: Add xen_evtchn device for event channel emulation, Paul Durrant, 2023/01/17
- Re: [PATCH v7 26/51] hw/xen: Add xen_evtchn device for event channel emulation, David Woodhouse, 2023/01/17
- Re: [PATCH v7 26/51] hw/xen: Add xen_evtchn device for event channel emulation, Paul Durrant, 2023/01/17
- Re: [PATCH v7 26/51] hw/xen: Add xen_evtchn device for event channel emulation, David Woodhouse, 2023/01/17
- [PATCH v7.1 26/51] hw/xen: Add xen_evtchn device for event channel emulation, David Woodhouse, 2023/01/17
[PATCH v7 38/51] i386/xen: add monitor commands to test event injection, David Woodhouse, 2023/01/16
[PATCH v7 06/51] i386/hvm: Set Xen vCPU ID in KVM, David Woodhouse, 2023/01/16
[PATCH v7 29/51] hw/xen: Implement EVTCHNOP_close, David Woodhouse, 2023/01/16
[PATCH v7 36/51] hw/xen: Implement EVTCHNOP_bind_vcpu, David Woodhouse, 2023/01/16
[PATCH v7 19/51] i386/xen: implement HYPERVISOR_vcpu_op, David Woodhouse, 2023/01/16
[PATCH v7 28/51] hw/xen: Implement EVTCHNOP_status, David Woodhouse, 2023/01/16
[PATCH v7 42/51] hw/xen: Add xen_gnttab device for grant table emulation, David Woodhouse, 2023/01/16
[PATCH v7 20/51] i386/xen: handle VCPUOP_register_vcpu_info, David Woodhouse, 2023/01/16
[PATCH v7 43/51] hw/xen: Support mapping grant frames, David Woodhouse, 2023/01/16