123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- // 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 <common.h>
- #include <log.h>
- #include <asm/io.h>
- #include <asm/xen/system.h>
- #include <xen/events.h>
- #include <xen/hvm.h>
- extern u32 console_evtchn;
- #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 (i == console_evtchn)
- continue;
- 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)
- debug("Default 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();
- }
|