分类: LINUX
2010-01-27 10:19:56
static int evtchn_set_pending(struct vcpu *v, int port)
{
struct domain *d = v->domain; // 通过VCPU找到对应的dom
int vcpuid;
/*
* 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 ( test_and_set_bit(port, &shared_info(d, evtchn_pending)) ) // 设置dom的shared_info里面
return 1; // evtchn_pending数组中对于元素的对应位(根据port)为1
此evtchn的pending位都被置1。表明此evtchn需要/正在被某个VCPU处理。
if ( !test_bit (port, &shared_info(d, evtchn_mask)) &&
!test_and_set_bit(port / BITS_PER_EVTCHN_WORD(d),
&vcpu_info(v, evtchn_pending_sel)) )
如果此evtchn的mask位没有设置,则设置对应的VCPU的evtchn_pending_sel位(evtchn_pending_sel与evtchn_pending关联)。使该VCPU可以感知正在处理哪个event,即定位pending状态的evtchn。
{
同时,如果evtchn_pending_sel设置成功,则设置VCPU的evtchn_upcall_pending。表明本VCPU需要/正在处理event。
}
/* Check if some VCPU might be polling for this event. */
if ( likely(bitmap_empty(d->poll_mask, d->max_vcpus)) )
return 0;
/* Wake any interested (or potentially interested) pollers. */
for ( vcpuid = find_first_bit(d->poll_mask, d->max_vcpus);
vcpuid < d->max_vcpus;
vcpuid = find_next_bit(d->poll_mask, d->max_vcpus, vcpuid+1) )
{
v = d->vcpu[vcpuid];
if ( ((v->poll_evtchn <= 0) || (v->poll_evtchn == port)) &&
test_and_clear_bit(vcpuid, d->poll_mask) )
{
v->poll_evtchn = 0;
vcpu_unblock(v);
}
}
return 0;
}
#define shared_info(d, field) __shared_info(d, (d)->shared_info, field)
#define __shared_info(d, s, field) ((s)->field)
void vcpu_mark_events_pending(struct vcpu *v)
{
int already_pending = test_and_set_bit(
0, (unsigned long *)&vcpu_info(v, evtchn_upcall_pending));
if ( already_pending )
return;
if ( is_hvm_vcpu(v) )
hvm_assert_evtchn_irq(v);
else
vcpu_kick(v);
}
void mask_evtchn(int port)
{
shared_info_t *s = HYPERVISOR_shared_info; // 获得shared_info
synch_set_bit(port, s->evtchn_mask); // 设置里面的evtchn_mask
}
EXPORT_SYMBOL_GPL(mask_evtchn);
void unmask_evtchn(int port)
{
shared_info_t *s = HYPERVISOR_shared_info; // 获得shared_info
unsigned int cpu = smp_processor_id();
vcpu_info_t *vcpu_info = &s->vcpu_info[cpu]; // 获得当前的VCPU
BUG_ON(!irqs_disabled());
/* Slow path (hypercall) if this is a non-local port. */
if (unlikely(cpu != cpu_from_evtchn(port))) { // 如果本evtchn没有绑定到本VCPU
struct evtchn_unmask unmask = { .port = port };
VOID(HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask)); // hypercall处理
return;
}
synch_clear_bit(port, s->evtchn_mask); // 取消mask
/* Did we miss an interrupt 'edge'? Re-fire if so. */
if (synch_test_bit(port, s->evtchn_pending) && // 如果存在未决evtchn
!synch_test_and_set_bit(port / BITS_PER_LONG,
&vcpu_info->evtchn_pending_sel))
vcpu_info->evtchn_upcall_pending = 1; // 设置VCPU的evtchn_upcall_pending
}
EXPORT_SYMBOL_GPL(unmask_evtchn);
结构体:
struct evtchn_op {
uint32_t cmd; /* EVTCHNOP_* */
union {
struct evtchn_alloc_unbound alloc_unbound;
struct evtchn_bind_interdomain bind_interdomain;
struct evtchn_bind_virq bind_virq;
struct evtchn_bind_pirq bind_pirq;
struct evtchn_bind_ipi bind_ipi;
struct evtchn_close close;
struct evtchn_send send;
struct evtchn_status status;
struct evtchn_bind_vcpu bind_vcpu;
struct evtchn_unmask unmask;
} u;
};
typedef struct evtchn_op evtchn_op_t;
struct shared_info {
struct vcpu_info vcpu_info[XEN_LEGACY_MAX_VCPUS];
unsigned long evtchn_pending[sizeof(unsigned long) * 8]; // 32个long,有32*32=1024位
unsigned long evtchn_mask[sizeof(unsigned long) * 8];
uint32_t wc_version; /* Version counter: see vcpu_time_info_t. */
uint32_t wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
uint32_t wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */
struct arch_shared_info arch;
}
struct vcpu_info {
uint8_t evtchn_upcall_pending; // 针对所有evtchn的
uint8_t evtchn_upcall_mask; // 设置为1,则此VCPU将屏蔽所有的evtchn。
unsigned long evtchn_pending_sel; // 每一位对应evtchn_pinding中一组32个evtchn。设置方法
struct arch_vcpu_info arch;
struct vcpu_time_info time;
}; /* 64 bytes (x86) */
/*
* EVTCHNOP_alloc_unbound: Allocate a port in domain
* accepting interdomain bindings from domain
* is allocated in
* NOTES:
* 1. If the caller is unprivileged then
* 2.
*/
#define EVTCHNOP_alloc_unbound 6
struct evtchn_alloc_unbound {
/* IN parameters */
domid_t dom, remote_dom;
/* OUT parameters */
evtchn_port_t port; // 用于通信的port
};
typedef struct evtchn_alloc_unbound evtchn_alloc_unbound_t;
/*
* EVTCHNOP_bind_interdomain: Construct an interdomain event channel between
* the calling domain and
* a port that is unbound and marked as accepting bindings from the calling // 参考EVTCHNOP_alloc_unbound
* domain. A fresh port is allocated in the calling domain and returned as
*
* NOTES:
* 2.
*/
#define EVTCHNOP_bind_interdomain 0
struct evtchn_bind_interdomain {
/* IN parameters. */
domid_t remote_dom;
evtchn_port_t remote_port;
/* OUT parameters. */
evtchn_port_t local_port;
};
typedef struct evtchn_bind_interdomain evtchn_bind_interdomain_t;
/*
* EVTCHNOP_bind_virq: Bind a local event channel to VIRQ
* vcpu.
* NOTES:
* 1. Virtual IRQs are classified as per-vcpu or global. See the VIRQ list
* in xen.h for the classification of each VIRQ.
* 2. Global VIRQs must be allocated on VCPU0 but can subsequently be
* re-bound via EVTCHNOP_bind_vcpu.
* 3. Per-vcpu VIRQs may be bound to at most one event channel per vcpu.
* The allocated event channel is bound to the specified vcpu and the
* binding cannot be changed.
*/
#define EVTCHNOP_bind_virq 1
struct evtchn_bind_virq {
/* IN parameters. */
uint32_t virq;
uint32_t vcpu;
/* OUT parameters. */
evtchn_port_t port;
};
typedef struct evtchn_bind_virq evtchn_bind_virq_t;
/*
* EVTCHNOP_bind_pirq: Bind a local event channel to PIRQ
* NOTES:
* 1. A physical IRQ may be bound to at most one event channel per domain.
* 2. Only a sufficiently-privileged domain may bind to a physical IRQ.
*/
#define EVTCHNOP_bind_pirq 2
struct evtchn_bind_pirq {
/* IN parameters. */
uint32_t pirq;
#define BIND_PIRQ__WILL_SHARE 1
uint32_t flags; /* BIND_PIRQ__* */
/* OUT parameters. */
evtchn_port_t port;
};
typedef struct evtchn_bind_pirq evtchn_bind_pirq_t;
/*
* EVTCHNOP_bind_ipi: Bind a local event channel to receive events.
* NOTES:
* 1. The allocated event channel is bound to the specified vcpu. The binding
* may not be changed.
*/
#define EVTCHNOP_bind_ipi 7
struct evtchn_bind_ipi {
uint32_t vcpu;
/* OUT parameters. */
evtchn_port_t port;
};
typedef struct evtchn_bind_ipi evtchn_bind_ipi_t;
/*
* EVTCHNOP_close: Close a local event channel
* interdomain then the remote end is placed in the unbound state
* (EVTCHNSTAT_unbound), awaiting a new connection.
*/
#define EVTCHNOP_close 3
struct evtchn_close {
/* IN parameters. */
evtchn_port_t port;
};
typedef struct evtchn_close evtchn_close_t;
/*
* EVTCHNOP_send: Send an event to the remote end of the channel whose local
* endpoint is
*/
#define EVTCHNOP_send 4
struct evtchn_send {
/* IN parameters. */
evtchn_port_t port;
};
typedef struct evtchn_send evtchn_send_t;
/*
* EVTCHNOP_status: Get the current status of the communication channel which
* has an endpoint at
* NOTES:
* 1.
* 2. Only a sufficiently-privileged domain may obtain the status of an event
* channel for which
*/
#define EVTCHNOP_status 5
struct evtchn_status {
/* IN parameters */
domid_t dom;
evtchn_port_t port;
/* OUT parameters */
#define EVTCHNSTAT_closed 0 /* Channel is not in use. */
#define EVTCHNSTAT_unbound 1 /* Channel is waiting interdom connection.*/
#define EVTCHNSTAT_interdomain 2 /* Channel is connected to remote domain. */
#define EVTCHNSTAT_pirq 3 /* Channel is bound to a phys IRQ line. */
#define EVTCHNSTAT_virq 4 /* Channel is bound to a virtual IRQ line */
#define EVTCHNSTAT_ipi 5 /* Channel is bound to a virtual IPI line */
uint32_t status;
uint32_t vcpu; /* VCPU to which this channel is bound. */
union {
struct {
domid_t dom;
} unbound; /* EVTCHNSTAT_unbound */ // 如果是unbound状态,那么此port开放给哪个dom用
struct {
domid_t dom;
evtchn_port_t port;
} interdomain; /* EVTCHNSTAT_interdomain */ // 如果是interdomain状态,那么连接的远程dom和port?
uint32_t pirq; /* EVTCHNSTAT_pirq */
uint32_t virq; /* EVTCHNSTAT_virq */
} u;
};
typedef struct evtchn_status evtchn_status_t;
/*
* EVTCHNOP_bind_vcpu: Specify which vcpu a channel should notify when an
* event is pending.
* NOTES:
* 1. IPI-bound channels always notify the vcpu specified at bind time.
* This binding cannot be changed.
* 2. Per-VCPU VIRQ channels always notify the vcpu specified at bind time.
* This binding cannot be changed.
* 3. All other channels notify vcpu0 by default. This default is set when
* the channel is allocated (a port that is freed and subsequently reused
* has its binding reset to vcpu0).
*/
#define EVTCHNOP_bind_vcpu 8
struct evtchn_bind_vcpu {
/* IN parameters. */
evtchn_port_t port;
uint32_t vcpu;
};
typedef struct evtchn_bind_vcpu evtchn_bind_vcpu_t;
/*
* EVTCHNOP_unmask: Unmask the specified local event-channel port and deliver
* a notification to the appropriate VCPU if an event is pending.
*/
#define EVTCHNOP_unmask 9
struct evtchn_unmask {
/* IN parameters. */
evtchn_port_t port;
};
typedef struct evtchn_unmask evtchn_unmask_t;
/*
* EVTCHNOP_reset: Close all event channels associated with specified domain.
* NOTES:
* 1.
* 2. Only a sufficiently-privileged domain may specify other than DOMID_SELF.
*/
#define EVTCHNOP_reset 10
struct evtchn_reset {
/* IN parameters. */
domid_t dom;
};