~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to extras/mini-os/events.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 ****************************************************************************
5
6
 *
6
7
 *        File: events.c
7
8
 *      Author: Rolf Neugebauer (neugebar@dcs.gla.ac.uk)
8
 
 *     Changes: 
 
9
 *     Changes: Grzegorz Milos (gm281@cam.ac.uk)
9
10
 *              
10
 
 *        Date: Jul 2003
 
11
 *        Date: Jul 2003, changes Jun 2005
11
12
 * 
12
13
 * Environment: Xen Minimal OS
13
 
 * Description: Deal with events
 
14
 * Description: Deals with events recieved on event channels
14
15
 *
15
16
 ****************************************************************************
16
 
 * $Id: c-insert.c,v 1.7 2002/11/08 16:04:34 rn Exp $
17
 
 ****************************************************************************
18
17
 */
19
18
 
20
 
#include <os.h>
21
 
#include <hypervisor.h>
22
 
#include <events.h>
23
 
#include <lib.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>
 
24
 
 
25
#define NR_EVS 1024
 
26
 
 
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
    uint32_t count;
 
32
} ev_action_t;
24
33
 
25
34
static ev_action_t ev_actions[NR_EVS];
26
 
void default_handler(int ev, struct pt_regs *regs);
27
 
 
 
35
void default_handler(evtchn_port_t port, struct pt_regs *regs, void *data);
 
36
 
 
37
static unsigned long bound_ports[NR_EVS/(8*sizeof(unsigned long))];
 
38
 
 
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];
 
45
    int rc;
 
46
 
 
47
    for ( i = 0; i < NR_EVS; i++ )
 
48
    {
 
49
        if ( i == start_info.console.domU.evtchn ||
 
50
             i == start_info.store_evtchn)
 
51
            continue;
 
52
 
 
53
        if ( test_and_clear_bit(i, bound_ports) )
 
54
        {
 
55
            struct evtchn_close close;
 
56
            printk("port %d still bound!\n", i);
 
57
            mask_evtchn(i);
 
58
            close.port = i;
 
59
            rc = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
 
60
            if ( rc )
 
61
                printk("WARN: close_port %s failed rc=%d. ignored\n", i, rc);
 
62
            clear_evtchn(i);
 
63
        }
 
64
    }
 
65
    vcpu_info->evtchn_upcall_pending = 0;
 
66
    vcpu_info->evtchn_pending_sel = 0;
 
67
}
28
68
 
29
69
/*
30
 
 * demux events to different handlers
 
70
 * Demux events to different handlers.
31
71
 */
32
 
unsigned int do_event(int ev, struct pt_regs *regs)
 
72
int do_event(evtchn_port_t port, struct pt_regs *regs)
33
73
{
34
74
    ev_action_t  *action;
35
75
 
36
 
    if (ev >= NR_EVS) {
37
 
        printk("Large event number %d\n", ev);
38
 
        return 0;
 
76
    clear_evtchn(port);
 
77
 
 
78
    if ( port >= NR_EVS )
 
79
    {
 
80
        printk("WARN: do_event(): Port number too large: %d\n", port);
 
81
        return 1;
39
82
    }
40
83
 
41
 
    action = &ev_actions[ev];
 
84
    action = &ev_actions[port];
42
85
    action->count++;
43
 
    ack_hypervisor_event(ev);
44
86
 
45
 
    if (!action->handler)
46
 
        goto out;
47
 
    
48
 
    if (action->status & EVS_DISABLED)
49
 
        goto out;
50
 
    
51
87
    /* call the handler */
52
 
    action->handler(ev, regs);
53
 
    
54
 
 out:
55
 
    return 1;
56
 
 
57
 
}
58
 
 
59
 
/*
60
 
 * add a handler
61
 
 */
62
 
unsigned int add_ev_action( int ev, void (*handler)(int, struct pt_regs *) )
63
 
{
64
 
    if (ev_actions[ev].handler) {
65
 
        printk ("event[%d] already handled by %p", ev, ev_actions[ev].handler);
66
 
        return 0;
67
 
    }
68
 
 
69
 
    ev_actions[ev].handler = handler;
70
 
    return 1;
71
 
}
72
 
 
73
 
unsigned int enable_ev_action( int ev )
74
 
{
75
 
    if (!ev_actions[ev].handler) {
76
 
        printk ("enable event[%d], no handler installed", ev);
77
 
        return 0;
78
 
    }
79
 
    ev_actions[ev].status &= ~EVS_DISABLED;
80
 
    return 1;
81
 
}
82
 
 
83
 
unsigned int disable_ev_action( int ev )
84
 
{
85
 
    ev_actions[ev].status |= EVS_DISABLED;
86
 
    return 1;
87
 
}
88
 
 
89
 
/*
90
 
 * initially all events are without a handler and disabled
 
88
        action->handler(port, regs, action->data);
 
89
 
 
90
    return 1;
 
91
 
 
92
}
 
93
 
 
94
evtchn_port_t bind_evtchn(evtchn_port_t port, evtchn_handler_t handler,
 
95
                                                  void *data)
 
96
{
 
97
        if ( ev_actions[port].handler != default_handler )
 
98
        printk("WARN: Handler for port %d already registered, replacing\n",
 
99
               port);
 
100
 
 
101
        ev_actions[port].data = data;
 
102
        wmb();
 
103
        ev_actions[port].handler = handler;
 
104
        set_bit(port, bound_ports);
 
105
 
 
106
        return port;
 
107
}
 
108
 
 
109
void unbind_evtchn(evtchn_port_t port )
 
110
{
 
111
        struct evtchn_close close;
 
112
    int rc;
 
113
 
 
114
        if ( ev_actions[port].handler == default_handler )
 
115
                printk("WARN: No handler for port %d when unbinding\n", port);
 
116
        mask_evtchn(port);
 
117
        clear_evtchn(port);
 
118
 
 
119
        ev_actions[port].handler = default_handler;
 
120
        wmb();
 
121
        ev_actions[port].data = NULL;
 
122
        clear_bit(port, bound_ports);
 
123
 
 
124
        close.port = port;
 
125
        rc = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
 
126
    if ( rc )
 
127
        printk("WARN: close_port %s failed rc=%d. ignored\n", port, rc);
 
128
        
 
129
}
 
130
 
 
131
evtchn_port_t bind_virq(uint32_t virq, evtchn_handler_t handler, void *data)
 
132
{
 
133
        evtchn_bind_virq_t op;
 
134
    int rc;
 
135
 
 
136
        /* Try to bind the virq to a port */
 
137
        op.virq = virq;
 
138
        op.vcpu = smp_processor_id();
 
139
 
 
140
        if ( (rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq, &op)) != 0 )
 
141
        {
 
142
                printk("Failed to bind virtual IRQ %d with rc=%d\n", virq, rc);
 
143
                return -1;
 
144
    }
 
145
    bind_evtchn(op.port, handler, data);
 
146
        return op.port;
 
147
}
 
148
 
 
149
evtchn_port_t bind_pirq(uint32_t pirq, int will_share,
 
150
                        evtchn_handler_t handler, void *data)
 
151
{
 
152
        evtchn_bind_pirq_t op;
 
153
    int rc;
 
154
 
 
155
        /* Try to bind the pirq to a port */
 
156
        op.pirq = pirq;
 
157
        op.flags = will_share ? BIND_PIRQ__WILL_SHARE : 0;
 
158
 
 
159
        if ( (rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &op)) != 0 )
 
160
        {
 
161
                printk("Failed to bind physical IRQ %d with rc=%d\n", pirq, rc);
 
162
                return -1;
 
163
        }
 
164
        bind_evtchn(op.port, handler, data);
 
165
        return op.port;
 
166
}
 
167
 
 
168
#if defined(__x86_64__)
 
169
char irqstack[2 * STACK_SIZE];
 
170
 
 
171
static struct pda
 
172
{
 
173
    int irqcount;       /* offset 0 (used in x86_64.S) */
 
174
    char *irqstackptr;  /*        8 */
 
175
} cpu0_pda;
 
176
#endif
 
177
 
 
178
/*
 
179
 * Initially all events are without a handler and disabled
91
180
 */
92
181
void init_events(void)
93
182
{
94
183
    int i;
95
 
 
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));
 
190
#endif
 
191
    /* initialize event handler */
97
192
    for ( i = 0; i < NR_EVS; i++ )
98
 
    {
99
 
        ev_actions[i].status  = EVS_DISABLED;
100
 
        ev_actions[i].handler = NULL;
101
 
    }
102
 
}
103
 
 
104
 
void default_handler(int ev, struct pt_regs *regs) {
105
 
    printk("X[%d] ", ev);
106
 
}
 
193
        {
 
194
        ev_actions[i].handler = default_handler;
 
195
        mask_evtchn(i);
 
196
    }
 
197
}
 
198
 
 
199
void fini_events(void)
 
200
{
 
201
    /* Dealloc all events */
 
202
    unbind_all_ports();
 
203
#if defined(__x86_64__)
 
204
    wrmsrl(0xc0000101, NULL); /* 0xc0000101 is MSR_GS_BASE */
 
205
#endif
 
206
}
 
207
 
 
208
void default_handler(evtchn_port_t port, struct pt_regs *regs, void *ignore)
 
209
{
 
210
    printk("[Port %d] - event received\n", port);
 
211
}
 
212
 
 
213
/* Create a port available to the pal for exchanging notifications.
 
214
   Returns the result of the hypervisor call. */
 
215
 
 
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. */
 
219
 
 
220
int evtchn_alloc_unbound(domid_t pal, evtchn_handler_t handler,
 
221
                                                 void *data, evtchn_port_t *port)
 
222
{
 
223
    int rc;
 
224
 
 
225
    evtchn_alloc_unbound_t op;
 
226
    op.dom = DOMID_SELF;
 
227
    op.remote_dom = pal;
 
228
    rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound, &op);
 
229
    if ( rc )
 
230
    {
 
231
        printk("ERROR: alloc_unbound failed with rc=%d", rc);
 
232
                return rc;
 
233
    }
 
234
    *port = bind_evtchn(op.port, handler, data);
 
235
    return rc;
 
236
}
 
237
 
 
238
/* Connect to a port so as to allow the exchange of notifications with
 
239
   the pal. Returns the result of the hypervisor call. */
 
240
 
 
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)
 
244
{
 
245
    int rc;
 
246
    evtchn_port_t port;
 
247
    evtchn_bind_interdomain_t op;
 
248
    op.remote_dom = pal;
 
249
    op.remote_port = remote_port;
 
250
    rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain, &op);
 
251
    if ( rc )
 
252
    {
 
253
        printk("ERROR: bind_interdomain failed with rc=%d", rc);
 
254
                return rc;
 
255
    }
 
256
    port = op.local_port;
 
257
    *local_port = bind_evtchn(port, handler, data);
 
258
    return rc;
 
259
}
 
260
 
 
261
/*
 
262
 * Local variables:
 
263
 * mode: C
 
264
 * c-set-style: "BSD"
 
265
 * c-basic-offset: 4
 
266
 * tab-width: 4
 
267
 * indent-tabs-mode: nil
 
268
 * End:
 
269
 */