ia64/xen-unstable

view extras/mini-os/events.c @ 18811:390ef36eb596

Remove Xen-private definitions from kexec public header.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Nov 19 13:13:39 2008 +0000 (2008-11-19)
parents 433d1b26fd51
children 08916e5135b3
line source
1 /* -*- Mode:C; c-basic-offset:4; tab-width:4 -*-
2 ****************************************************************************
3 * (C) 2003 - Rolf Neugebauer - Intel Research Cambridge
4 * (C) 2005 - Grzegorz Milos - Intel Research Cambridge
5 ****************************************************************************
6 *
7 * File: events.c
8 * Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
9 * Changes: Grzegorz Milos (gm281@cam.ac.uk)
10 *
11 * Date: Jul 2003, changes Jun 2005
12 *
13 * Environment: Xen Minimal OS
14 * Description: Deals with events recieved on event channels
15 *
16 ****************************************************************************
17 */
19 #include <os.h>
20 #include <mm.h>
21 #include <hypervisor.h>
22 #include <events.h>
23 #include <lib.h>
25 #define NR_EVS 1024
27 /* this represents a event handler. Chaining or sharing is not allowed */
28 typedef struct _ev_action_t {
29 evtchn_handler_t handler;
30 void *data;
31 u32 count;
32 } ev_action_t;
34 static ev_action_t ev_actions[NR_EVS];
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)
40 {
41 int i;
42 int cpu = 0;
43 shared_info_t *s = HYPERVISOR_shared_info;
44 vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
46 for (i = 0; i < NR_EVS; i++)
47 {
48 if (i == start_info.console.domU.evtchn ||
49 i == start_info.store_evtchn)
50 continue;
51 if (test_and_clear_bit(i, bound_ports))
52 {
53 struct evtchn_close close;
54 printk("port %d still bound!\n", i);
55 mask_evtchn(i);
56 close.port = i;
57 HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
58 clear_evtchn(i);
59 }
60 }
61 vcpu_info->evtchn_upcall_pending = 0;
62 vcpu_info->evtchn_pending_sel = 0;
63 }
65 /*
66 * Demux events to different handlers.
67 */
68 int do_event(evtchn_port_t port, struct pt_regs *regs)
69 {
70 ev_action_t *action;
72 clear_evtchn(port);
74 if (port >= NR_EVS) {
75 printk("Port number too large: %d\n", port);
76 return 1;
77 }
79 action = &ev_actions[port];
80 action->count++;
82 /* call the handler */
83 action->handler(port, regs, action->data);
85 return 1;
87 }
89 evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler,
90 void *data)
91 {
92 if(ev_actions[port].handler != default_handler)
93 printk("WARN: Handler for port %d already registered, replacing\n",
94 port);
96 ev_actions[port].data = data;
97 wmb();
98 ev_actions[port].handler = handler;
99 set_bit(port, bound_ports);
101 return port;
102 }
104 void unbind_evtchn(evtchn_port_t port )
105 {
106 struct evtchn_close close;
108 if (ev_actions[port].handler == default_handler)
109 printk("WARN: No handler for port %d when unbinding\n", port);
110 mask_evtchn(port);
111 clear_evtchn(port);
113 ev_actions[port].handler = default_handler;
114 wmb();
115 ev_actions[port].data = NULL;
116 clear_bit(port, bound_ports);
118 close.port = port;
119 HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
120 }
122 evtchn_port_t bind_virq(uint32_t virq, evtchn_handler_t handler, void *data)
123 {
124 evtchn_bind_virq_t op;
126 /* Try to bind the virq to a port */
127 op.virq = virq;
128 op.vcpu = smp_processor_id();
130 if ( HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &op) != 0 )
131 {
132 printk("Failed to bind virtual IRQ %d\n", virq);
133 return -1;
134 }
135 bind_evtchn(op.port, handler, data);
136 return op.port;
137 }
139 evtchn_port_t bind_pirq(uint32_t pirq, int will_share, evtchn_handler_t handler, void *data)
140 {
141 evtchn_bind_pirq_t op;
143 /* Try to bind the pirq to a port */
144 op.pirq = pirq;
145 op.flags = will_share ? BIND_PIRQ__WILL_SHARE : 0;
147 if ( HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &op) != 0 )
148 {
149 printk("Failed to bind physical IRQ %d\n", pirq);
150 return -1;
151 }
152 bind_evtchn(op.port, handler, data);
153 return op.port;
154 }
156 #if defined(__x86_64__)
157 char irqstack[2 * STACK_SIZE];
159 static struct pda
160 {
161 int irqcount; /* offset 0 (used in x86_64.S) */
162 char *irqstackptr; /* 8 */
163 } cpu0_pda;
164 #endif
166 /*
167 * Initially all events are without a handler and disabled
168 */
169 void init_events(void)
170 {
171 int i;
172 #if defined(__x86_64__)
173 asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0));
174 wrmsrl(0xc0000101, &cpu0_pda); /* 0xc0000101 is MSR_GS_BASE */
175 cpu0_pda.irqcount = -1;
176 cpu0_pda.irqstackptr = (void*) (((unsigned long)irqstack + 2 * STACK_SIZE) & ~(STACK_SIZE - 1));
177 #endif
178 /* initialize event handler */
179 for ( i = 0; i < NR_EVS; i++ )
180 {
181 ev_actions[i].handler = default_handler;
182 mask_evtchn(i);
183 }
184 }
186 void fini_events(void)
187 {
188 /* Dealloc all events */
189 unbind_all_ports();
190 #if defined(__x86_64__)
191 wrmsrl(0xc0000101, NULL); /* 0xc0000101 is MSR_GS_BASE */
192 #endif
193 }
195 void default_handler(evtchn_port_t port, struct pt_regs *regs, void *ignore)
196 {
197 printk("[Port %d] - event received\n", port);
198 }
200 /* Create a port available to the pal for exchanging notifications.
201 Returns the result of the hypervisor call. */
203 /* Unfortunate confusion of terminology: the port is unbound as far
204 as Xen is concerned, but we automatically bind a handler to it
205 from inside mini-os. */
207 int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler,
208 void *data, evtchn_port_t *port)
209 {
210 int err;
211 evtchn_alloc_unbound_t op;
212 op.dom = DOMID_SELF;
213 op.remote_dom = pal;
214 err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
215 if (err)
216 return err;
217 *port = bind_evtchn(op.port, handler, data);
218 return err;
219 }
221 /* Connect to a port so as to allow the exchange of notifications with
222 the pal. Returns the result of the hypervisor call. */
224 int evtchn_bind_interdomain(domid_t pal, evtchn_port_t remote_port,
225 evtchn_handler_t handler, void *data,
226 evtchn_port_t *local_port)
227 {
228 int err;
229 evtchn_port_t port;
230 evtchn_bind_interdomain_t op;
231 op.remote_dom = pal;
232 op.remote_port = remote_port;
233 err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, &op);
234 if (err)
235 return err;
236 port = op.local_port;
237 *local_port = bind_evtchn(port, handler, data);
238 return err;
239 }