1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
/*
* Event channel port operations.
*
* Copyright (c) 2003-2006, K A Fraser.
*
* This source code is licensed under the GNU General Public License,
* Version 2 or later. See the file COPYING for more details.
*/
#include "event_channel.h"
#include <xen/init.h>
#include <xen/lib.h>
#include <xen/errno.h>
#include <xen/sched.h>
#include <asm/guest_atomics.h>
static void cf_check evtchn_2l_set_pending(
struct vcpu *v, struct evtchn *evtchn)
{
struct domain *d = v->domain;
unsigned int port = evtchn->port;
/*
* The following bit operations must happen in strict order.
* NB. On x86, the atomic bit operations also act as memory barriers.
* There is therefore sufficiently strict ordering for this architecture --
* others may require explicit memory barriers.
*/
if ( guest_test_and_set_bit(d, port, &shared_info(d, evtchn_pending)) )
return;
if ( !guest_test_bit(d, port, &shared_info(d, evtchn_mask)) &&
!guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
&vcpu_info(v, evtchn_pending_sel)) )
{
vcpu_mark_events_pending(v);
}
evtchn_check_pollers(d, port);
}
static void cf_check evtchn_2l_clear_pending(
struct domain *d, struct evtchn *evtchn)
{
guest_clear_bit(d, evtchn->port, &shared_info(d, evtchn_pending));
}
static void cf_check evtchn_2l_unmask(
struct domain *d, struct evtchn *evtchn)
{
struct vcpu *v = d->vcpu[evtchn->notify_vcpu_id];
unsigned int port = evtchn->port;
/*
* These operations must happen in strict order. Based on
* evtchn_2l_set_pending() above.
*/
if ( guest_test_and_clear_bit(d, port, &shared_info(d, evtchn_mask)) &&
guest_test_bit(d, port, &shared_info(d, evtchn_pending)) &&
!guest_test_and_set_bit(d, port / BITS_PER_EVTCHN_WORD(d),
&vcpu_info(v, evtchn_pending_sel)) )
{
vcpu_mark_events_pending(v);
}
}
static bool cf_check evtchn_2l_is_pending(
const struct domain *d, const struct evtchn *evtchn)
{
evtchn_port_t port = evtchn->port;
unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
ASSERT(port < max_ports);
return (port < max_ports &&
guest_test_bit(d, port, &shared_info(d, evtchn_pending)));
}
static bool cf_check evtchn_2l_is_masked(
const struct domain *d, const struct evtchn *evtchn)
{
evtchn_port_t port = evtchn->port;
unsigned int max_ports = BITS_PER_EVTCHN_WORD(d) * BITS_PER_EVTCHN_WORD(d);
ASSERT(port < max_ports);
return (port >= max_ports ||
guest_test_bit(d, port, &shared_info(d, evtchn_mask)));
}
static void cf_check evtchn_2l_print_state(
struct domain *d, const struct evtchn *evtchn)
{
struct vcpu *v = d->vcpu[evtchn->notify_vcpu_id];
printk("%d", !!test_bit(evtchn->port / BITS_PER_EVTCHN_WORD(d),
&vcpu_info(v, evtchn_pending_sel)));
}
static const struct evtchn_port_ops evtchn_port_ops_2l =
{
.set_pending = evtchn_2l_set_pending,
.clear_pending = evtchn_2l_clear_pending,
.unmask = evtchn_2l_unmask,
.is_pending = evtchn_2l_is_pending,
.is_masked = evtchn_2l_is_masked,
.print_state = evtchn_2l_print_state,
};
void evtchn_2l_init(struct domain *d)
{
d->evtchn_port_ops = &evtchn_port_ops_2l;
}
/*
* Local variables:
* mode: C
* c-file-style: "BSD"
* c-basic-offset: 4
* tab-width: 4
* indent-tabs-mode: nil
* End:
*/
|