From patchwork Wed Jul 1 16:29:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nastya Vicodin X-Patchwork-Id: 240623 List-Id: U-Boot discussion From: vicooodin at gmail.com (Anastasiia Lukianenko) Date: Wed, 1 Jul 2020 19:29:48 +0300 Subject: [PATCH 06/17] xen: Port Xen event channel driver from mini-os In-Reply-To: <20200701162959.9814-1-vicooodin@gmail.com> References: <20200701162959.9814-1-vicooodin@gmail.com> Message-ID: <20200701162959.9814-7-vicooodin@gmail.com> From: Oleksandr Andrushchenko Make required updates to run on u-boot. Strip functionality not needed by U-boot. Signed-off-by: Oleksandr Andrushchenko Signed-off-by: Anastasiia Lukianenko --- drivers/xen/Makefile | 1 + drivers/xen/events.c | 177 +++++++++++++++++++++++++++++++++++++++ drivers/xen/hypervisor.c | 6 +- include/xen/events.h | 47 +++++++++++ 4 files changed, 228 insertions(+), 3 deletions(-) create mode 100644 drivers/xen/events.c create mode 100644 include/xen/events.h diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index 1211bf2386..0ad35edefb 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -3,3 +3,4 @@ # (C) Copyright 2020 EPAM Systems Inc. obj-y += hypervisor.o +obj-y += events.o diff --git a/drivers/xen/events.c b/drivers/xen/events.c new file mode 100644 index 0000000000..eddc6b6e29 --- /dev/null +++ b/drivers/xen/events.c @@ -0,0 +1,177 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- + **************************************************************************** + * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge + * (C) 2005 - Grzegorz Milos - Intel Research Cambridge + * (C) 2020 - EPAM Systems Inc. + **************************************************************************** + * + * File: events.c + * Author: Rolf Neugebauer (neugebar at dcs.gla.ac.uk) + * Changes: Grzegorz Milos (gm281 at cam.ac.uk) + * + * Date: Jul 2003, changes Jun 2005 + * + * Environment: Xen Minimal OS + * Description: Deals with events received on event channels + * + **************************************************************************** + */ +#include +#include + +#include +#include + +#include +#include + +#define NR_EVS 1024 + +/* this represents a event handler. Chaining or sharing is not allowed */ +typedef struct _ev_action_t { + evtchn_handler_t handler; + void *data; + u32 count; +} ev_action_t; + +static ev_action_t ev_actions[NR_EVS]; +void default_handler(evtchn_port_t port, struct pt_regs *regs, void *data); + +static unsigned long bound_ports[NR_EVS / (8 * sizeof(unsigned long))]; + +void unbind_all_ports(void) +{ + int i; + int cpu = 0; + struct shared_info *s = HYPERVISOR_shared_info; + struct vcpu_info *vcpu_info = &s->vcpu_info[cpu]; + + for (i = 0; i < NR_EVS; i++) { + if (test_and_clear_bit(i, bound_ports)) { + printf("port %d still bound!\n", i); + unbind_evtchn(i); + } + } + vcpu_info->evtchn_upcall_pending = 0; + vcpu_info->evtchn_pending_sel = 0; +} + +/* + * Demux events to different handlers. + */ +int do_event(evtchn_port_t port, struct pt_regs *regs) +{ + ev_action_t *action; + + clear_evtchn(port); + + if (port >= NR_EVS) { + printk("WARN: do_event(): Port number too large: %d\n", port); + return 1; + } + + action = &ev_actions[port]; + action->count++; + + /* call the handler */ + action->handler(port, regs, action->data); + + return 1; +} + +evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler, + void *data) +{ + if (ev_actions[port].handler != default_handler) + printf("WARN: Handler for port %d already registered, replacing\n", + port); + + ev_actions[port].data = data; + wmb(); + ev_actions[port].handler = handler; + synch_set_bit(port, bound_ports); + + return port; +} + +void unbind_evtchn(evtchn_port_t port) +{ + struct evtchn_close close; + int rc; + + if (ev_actions[port].handler == default_handler) + printf("WARN: No handler for port %d when unbinding\n", port); + mask_evtchn(port); + clear_evtchn(port); + + ev_actions[port].handler = default_handler; + wmb(); + ev_actions[port].data = NULL; + synch_clear_bit(port, bound_ports); + + close.port = port; + rc = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close); + if (rc) + printf("WARN: close_port %d failed rc=%d. ignored\n", port, rc); +} + +void default_handler(evtchn_port_t port, struct pt_regs *regs, void *ignore) +{ + debug("[Port %d] - event received\n", port); +} + +/* Create a port available to the pal for exchanging notifications. + * Returns the result of the hypervisor call. + */ + +/* Unfortunate confusion of terminology: the port is unbound as far + * as Xen is concerned, but we automatically bind a handler to it + * from inside mini-os. + */ +int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler, + void *data, evtchn_port_t *port) +{ + int rc; + + struct evtchn_alloc_unbound op; + + op.dom = DOMID_SELF; + op.remote_dom = pal; + rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op); + if (rc) { + printf("ERROR: alloc_unbound failed with rc=%d", rc); + return rc; + } + if (!handler) + handler = default_handler; + *port = bind_evtchn(op.port, handler, data); + return rc; +} + +void eventchn_poll(void) +{ + do_hypervisor_callback(NULL); +} + +/* + * Initially all events are without a handler and disabled + */ +void init_events(void) +{ + int i; + + debug("%s\n", __func__); + /* initialize event handler */ + for (i = 0; i < NR_EVS; i++) { + ev_actions[i].handler = default_handler; + mask_evtchn(i); + } +} + +void fini_events(void) +{ + debug("%s\n", __func__); + /* Dealloc all events */ + unbind_all_ports(); +} + diff --git a/drivers/xen/hypervisor.c b/drivers/xen/hypervisor.c index 5883285142..975e552242 100644 --- a/drivers/xen/hypervisor.c +++ b/drivers/xen/hypervisor.c @@ -37,6 +37,7 @@ #include #include +#include #include #define active_evtchns(cpu, sh, idx) \ @@ -198,9 +199,7 @@ void do_hypervisor_callback(struct pt_regs *regs) l2 &= ~(1UL << l2i); port = (l1i * (sizeof(unsigned long) * 8)) + l2i; - /* TODO: handle new event: do_event(port, regs); */ - /* Suppress -Wunused-but-set-variable */ - (void)(port); + do_event(port, regs); } } @@ -273,5 +272,6 @@ void xen_init(void) debug("%s\n", __func__); map_shared_info(NULL); + init_events(); } diff --git a/include/xen/events.h b/include/xen/events.h new file mode 100644 index 0000000000..63abdf426b --- /dev/null +++ b/include/xen/events.h @@ -0,0 +1,47 @@ +/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*- + **************************************************************************** + * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge + * (C) 2005 - Grzegorz Milos - Intel Reseach Cambridge + * (C) 2020 - EPAM Systems Inc. + **************************************************************************** + * + * File: events.h + * Author: Rolf Neugebauer (neugebar at dcs.gla.ac.uk) + * Changes: Grzegorz Milos (gm281 at cam.ac.uk) + * + * Date: Jul 2003, changes Jun 2005 + * + * Environment: Xen Minimal OS + * Description: Deals with events on the event channels + * + **************************************************************************** + */ + +#ifndef _EVENTS_H_ +#define _EVENTS_H_ + +#include +#include + +typedef void (*evtchn_handler_t)(evtchn_port_t, struct pt_regs *, void *); + +void init_events(void); +void fini_events(void); + +int do_event(evtchn_port_t port, struct pt_regs *regs); +void unbind_evtchn(evtchn_port_t port); +void unbind_all_ports(void); +int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler, + void *data, evtchn_port_t *port); + +static inline int notify_remote_via_evtchn(evtchn_port_t port) +{ + struct evtchn_send op; + + op.port = port; + return HYPERVISOR_event_channel_op(EVTCHNOP_send, &op); +} + +void eventchn_poll(void); + +#endif /* _EVENTS_H_ */