1
1
/* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
2
2
****************************************************************************
3
3
* (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
4
* (C) 2005 - Grzegorz Milos - Intel Research Cambridge
4
5
****************************************************************************
7
8
* Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
9
* Changes: Grzegorz Milos (gm281@cam.ac.uk)
11
* Date: Jul 2003, changes Jun 2005
12
13
* Environment: Xen Minimal OS
13
* Description: Deal with events
14
* Description: Deals with events recieved on event channels
15
16
****************************************************************************
16
* $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
17
****************************************************************************
21
#include <hypervisor.h>
19
#include <mini-os/os.h>
20
#include <mini-os/mm.h>
21
#include <mini-os/hypervisor.h>
22
#include <mini-os/events.h>
23
#include <mini-os/lib.h>
27
/* this represents a event handler. Chaining or sharing is not allowed */
28
typedef struct _ev_action_t {
29
evtchn_handler_t handler;
25
34
static ev_action_t ev_actions[NR_EVS];
26
void default_handler(int ev, struct pt_regs *regs);
35
void default_handler(evtchn_port_t port, struct pt_regs *regs, void *data);
37
static unsigned long bound_ports[NR_EVS/(8*sizeof(unsigned long))];
39
void unbind_all_ports(void)
43
shared_info_t *s = HYPERVISOR_shared_info;
44
vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
47
for ( i = 0; i < NR_EVS; i++ )
49
if ( i == start_info.console.domU.evtchn ||
50
i == start_info.store_evtchn)
53
if ( test_and_clear_bit(i, bound_ports) )
55
struct evtchn_close close;
56
printk("port %d still bound!\n", i);
59
rc = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
61
printk("WARN: close_port %s failed rc=%d. ignored\n", i, rc);
65
vcpu_info->evtchn_upcall_pending = 0;
66
vcpu_info->evtchn_pending_sel = 0;
30
* demux events to different handlers
70
* Demux events to different handlers.
32
unsigned int do_event(int ev, struct pt_regs *regs)
72
int do_event(evtchn_port_t port, struct pt_regs *regs)
34
74
ev_action_t *action;
37
printk("Large event number %d\n", ev);
80
printk("WARN: do_event(): Port number too large: %d\n", port);
41
action = &ev_actions[ev];
84
action = &ev_actions[port];
43
ack_hypervisor_event(ev);
48
if (action->status & EVS_DISABLED)
51
87
/* call the handler */
52
action->handler(ev, regs);
62
unsigned int add_ev_action( int ev, void (*handler)(int, struct pt_regs *) )
64
if (ev_actions[ev].handler) {
65
printk ("event[%d] already handled by %p", ev, ev_actions[ev].handler);
69
ev_actions[ev].handler = handler;
73
unsigned int enable_ev_action( int ev )
75
if (!ev_actions[ev].handler) {
76
printk ("enable event[%d], no handler installed", ev);
79
ev_actions[ev].status &= ~EVS_DISABLED;
83
unsigned int disable_ev_action( int ev )
85
ev_actions[ev].status |= EVS_DISABLED;
90
* initially all events are without a handler and disabled
88
action->handler(port, regs, action->data);
94
evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler,
97
if ( ev_actions[port].handler != default_handler )
98
printk("WARN: Handler for port %d already registered, replacing\n",
101
ev_actions[port].data = data;
103
ev_actions[port].handler = handler;
104
set_bit(port, bound_ports);
109
void unbind_evtchn(evtchn_port_t port )
111
struct evtchn_close close;
114
if ( ev_actions[port].handler == default_handler )
115
printk("WARN: No handler for port %d when unbinding\n", port);
119
ev_actions[port].handler = default_handler;
121
ev_actions[port].data = NULL;
122
clear_bit(port, bound_ports);
125
rc = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
127
printk("WARN: close_port %s failed rc=%d. ignored\n", port, rc);
131
evtchn_port_t bind_virq(uint32_t virq, evtchn_handler_t handler, void *data)
133
evtchn_bind_virq_t op;
136
/* Try to bind the virq to a port */
138
op.vcpu = smp_processor_id();
140
if ( (rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &op)) != 0 )
142
printk("Failed to bind virtual IRQ %d with rc=%d\n", virq, rc);
145
bind_evtchn(op.port, handler, data);
149
evtchn_port_t bind_pirq(uint32_t pirq, int will_share,
150
evtchn_handler_t handler, void *data)
152
evtchn_bind_pirq_t op;
155
/* Try to bind the pirq to a port */
157
op.flags = will_share ? BIND_PIRQ__WILL_SHARE : 0;
159
if ( (rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &op)) != 0 )
161
printk("Failed to bind physical IRQ %d with rc=%d\n", pirq, rc);
164
bind_evtchn(op.port, handler, data);
168
#if defined(__x86_64__)
169
char irqstack[2 * STACK_SIZE];
173
int irqcount; /* offset 0 (used in x86_64.S) */
174
char *irqstackptr; /* 8 */
179
* Initially all events are without a handler and disabled
92
181
void init_events(void)
96
/* inintialise event handler */
184
#if defined(__x86_64__)
185
asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
186
wrmsrl(0xc0000101, &cpu0_pda); /* 0xc0000101 is MSR_GS_BASE */
187
cpu0_pda.irqcount = -1;
188
cpu0_pda.irqstackptr = (void*) (((unsigned long)irqstack + 2 * STACK_SIZE)
189
& ~(STACK_SIZE - 1));
191
/* initialize event handler */
97
192
for ( i = 0; i < NR_EVS; i++ )
99
ev_actions[i].status = EVS_DISABLED;
100
ev_actions[i].handler = NULL;
104
void default_handler(int ev, struct pt_regs *regs) {
105
printk("X[%d] ", ev);
194
ev_actions[i].handler = default_handler;
199
void fini_events(void)
201
/* Dealloc all events */
203
#if defined(__x86_64__)
204
wrmsrl(0xc0000101, NULL); /* 0xc0000101 is MSR_GS_BASE */
208
void default_handler(evtchn_port_t port, struct pt_regs *regs, void *ignore)
210
printk("[Port %d] - event received\n", port);
213
/* Create a port available to the pal for exchanging notifications.
214
Returns the result of the hypervisor call. */
216
/* Unfortunate confusion of terminology: the port is unbound as far
217
as Xen is concerned, but we automatically bind a handler to it
218
from inside mini-os. */
220
int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler,
221
void *data, evtchn_port_t *port)
225
evtchn_alloc_unbound_t op;
228
rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
231
printk("ERROR: alloc_unbound failed with rc=%d", rc);
234
*port = bind_evtchn(op.port, handler, data);
238
/* Connect to a port so as to allow the exchange of notifications with
239
the pal. Returns the result of the hypervisor call. */
241
int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port,
242
evtchn_handler_t handler, void *data,
243
evtchn_port_t *local_port)
247
evtchn_bind_interdomain_t op;
249
op.remote_port = remote_port;
250
rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, &op);
253
printk("ERROR: bind_interdomain failed with rc=%d", rc);
256
port = op.local_port;
257
*local_port = bind_evtchn(port, handler, data);
267
* indent-tabs-mode: nil