From 673fd82c507cf2a674ca6ec6d84d8d2854a6d78c Mon Sep 17 00:00:00 2001 From: Oleksandr Andrushchenko Date: Thu, 6 Aug 2020 12:42:49 +0300 Subject: [PATCH] xen: Port Xen event channel driver from mini-os 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 | 195 +++++++++++++++++++++++++++++++++++++++ drivers/xen/hypervisor.c | 6 +- include/xen.h | 2 +- include/xen/events.h | 42 +++++++++ 5 files changed, 242 insertions(+), 4 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..b4c84814c5 --- /dev/null +++ b/drivers/xen/events.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge + * (C) 2005 - Grzegorz Milos - Intel Research Cambridge + * (C) 2020 - EPAM Systems Inc. + * + * File: events.c [1] + * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk) + * Changes: Grzegorz Milos (gm281@cam.ac.uk) + * + * Date: Jul 2003, changes Jun 2005 + * + * Description: Deals with events received on event channels + * + * [1] - http://xenbits.xen.org/gitweb/?p=mini-os.git;a=summary + */ +#include +#include + +#include +#include + +#include +#include + +#define NR_EVS 1024 + +/** + * struct _ev_action - represents a event handler. + * + * Chaining or sharing is not allowed + */ +struct _ev_action { + void (*handler)(evtchn_port_t port, struct pt_regs *regs, void *data); + void *data; + u32 count; +}; + +static struct _ev_action 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; +} + +int do_event(evtchn_port_t port, struct pt_regs *regs) +{ + struct _ev_action *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, + void (*handler)(evtchn_port_t, struct pt_regs *, void *), + 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; +} + +/** + * unbind_evtchn() - Unbind event channel for selected 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); +} + +/** + * evtchn_alloc_unbound() - Create a port available to the pal for + * exchanging notifications. + * + * Unfortunate confusion of terminology: the port is unbound as far + * as Xen is concerned, but we automatically bind a handler to it. + * + * Return: The result of the hypervisor call. + */ +int evtchn_alloc_unbound(domid_t pal, + void (*handler)(evtchn_port_t, struct pt_regs *, void *), + 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; +} + +/** + * eventchn_poll() - Event channel polling function + * + * Check and process any pending events + */ +void eventchn_poll(void) +{ + do_hypervisor_callback(NULL); +} + +/** + * init_events() - Initialize event handler + * + * Initially all events are without a handler and disabled. + */ +void init_events(void) +{ + int i; + + debug("%s\n", __func__); + + for (i = 0; i < NR_EVS; i++) { + ev_actions[i].handler = default_handler; + mask_evtchn(i); + } +} + +/** + * fini_events() - Close all ports + * + * Mask and clear event channels. Close port using EVTCHNOP_close + * hypercall. + */ +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 108e9701d6..63fed6074f 100644 --- a/drivers/xen/hypervisor.c +++ b/drivers/xen/hypervisor.c @@ -20,6 +20,7 @@ #include #include +#include #include #define active_evtchns(cpu, sh, idx) \ @@ -163,9 +164,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); } } @@ -236,5 +235,6 @@ void xen_init(void) debug("%s\n", __func__); map_shared_info(NULL); + init_events(); } diff --git a/include/xen.h b/include/xen.h index abc3546dd2..64ed3f0654 100644 --- a/include/xen.h +++ b/include/xen.h @@ -8,7 +8,7 @@ /** * xen_init() - Xen initialization * - * Map Xen memory pages. + * Map Xen memory pages, initialize event handler. */ void xen_init(void); diff --git a/include/xen/events.h b/include/xen/events.h new file mode 100644 index 0000000000..82bd18b48c --- /dev/null +++ b/include/xen/events.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * (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@dcs.gla.ac.uk) + * Changes: Grzegorz Milos (gm281@cam.ac.uk) + * + * Date: Jul 2003, changes Jun 2005 + * + * Description: Deals with events on the event channels + */ +#ifndef _EVENTS_H_ +#define _EVENTS_H_ + +#include +#include + +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, + void (*handler)(evtchn_port_t, struct pt_regs *, void *), + void *data, evtchn_port_t *port); + +/* Send notification via event channel */ +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_ */