mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
Merge.
This commit is contained in:
commit
c1a792dbf3
12 files changed
+139
-275
No files matched your search
@@ -219,7 +219,6 @@ void unbind_virq_from_irq(int virq)
|
||||
spin_lock(&irq_mapping_update_lock);
|
||||
|
||||
if (--irq_bindcount[irq] == 0) {
|
||||
op.u.close.dom = DOMID_SELF;
|
||||
op.u.close.port = evtchn;
|
||||
BUG_ON(HYPERVISOR_event_channel_op(&op) != 0);
|
||||
|
||||
@@ -283,7 +282,6 @@ void unbind_ipi_from_irq(int ipi)
|
||||
spin_lock(&irq_mapping_update_lock);
|
||||
|
||||
if (--irq_bindcount[irq] == 0) {
|
||||
op.u.close.dom = DOMID_SELF;
|
||||
op.u.close.port = evtchn;
|
||||
BUG_ON(HYPERVISOR_event_channel_op(&op) != 0);
|
||||
|
||||
@@ -326,7 +324,6 @@ void unbind_evtchn_from_irq(unsigned int irq)
|
||||
spin_lock(&irq_mapping_update_lock);
|
||||
|
||||
if ((--irq_bindcount[irq] == 0) && (evtchn != -1)) {
|
||||
op.u.close.dom = DOMID_SELF;
|
||||
op.u.close.port = evtchn;
|
||||
BUG_ON(HYPERVISOR_event_channel_op(&op) != 0);
|
||||
|
||||
@@ -513,7 +510,10 @@ static inline void pirq_query_unmask(int pirq)
|
||||
static unsigned int startup_pirq(unsigned int irq)
|
||||
{
|
||||
evtchn_op_t op = { .cmd = EVTCHNOP_bind_pirq };
|
||||
int evtchn;
|
||||
int evtchn = irq_to_evtchn[irq];
|
||||
|
||||
if (VALID_EVTCHN(evtchn))
|
||||
goto out;
|
||||
|
||||
op.u.bind_pirq.pirq = irq;
|
||||
/* NB. We are happy to share unless we are probing. */
|
||||
@@ -532,6 +532,7 @@ static unsigned int startup_pirq(unsigned int irq)
|
||||
evtchn_to_irq[evtchn] = irq;
|
||||
irq_to_evtchn[irq] = evtchn;
|
||||
|
||||
out:
|
||||
unmask_evtchn(evtchn);
|
||||
pirq_unmask_notify(irq_to_pirq(irq));
|
||||
|
||||
@@ -548,7 +549,6 @@ static void shutdown_pirq(unsigned int irq)
|
||||
|
||||
mask_evtchn(evtchn);
|
||||
|
||||
op.u.close.dom = DOMID_SELF;
|
||||
op.u.close.port = evtchn;
|
||||
BUG_ON(HYPERVISOR_event_channel_op(&op) != 0);
|
||||
|
||||
|
||||
@@ -71,10 +71,8 @@ int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
|
||||
int err;
|
||||
evtchn_op_t op = {
|
||||
.cmd = EVTCHNOP_bind_interdomain,
|
||||
.u.bind_interdomain.dom1 = DOMID_SELF,
|
||||
.u.bind_interdomain.dom2 = blkif->domid,
|
||||
.u.bind_interdomain.port1 = 0,
|
||||
.u.bind_interdomain.port2 = evtchn };
|
||||
.u.bind_interdomain.remote_dom = blkif->domid,
|
||||
.u.bind_interdomain.remote_port = evtchn };
|
||||
|
||||
if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
|
||||
return -ENOMEM;
|
||||
@@ -92,7 +90,7 @@ int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
|
||||
return err;
|
||||
}
|
||||
|
||||
blkif->evtchn = op.u.bind_interdomain.port1;
|
||||
blkif->evtchn = op.u.bind_interdomain.local_port;
|
||||
|
||||
sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
|
||||
SHARED_RING_INIT(sring);
|
||||
|
||||
@@ -71,10 +71,8 @@ int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
|
||||
int err;
|
||||
evtchn_op_t op = {
|
||||
.cmd = EVTCHNOP_bind_interdomain,
|
||||
.u.bind_interdomain.dom1 = DOMID_SELF,
|
||||
.u.bind_interdomain.dom2 = blkif->domid,
|
||||
.u.bind_interdomain.port1 = 0,
|
||||
.u.bind_interdomain.port2 = evtchn };
|
||||
.u.bind_interdomain.remote_dom = blkif->domid,
|
||||
.u.bind_interdomain.remote_port = evtchn };
|
||||
|
||||
if ((blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL)
|
||||
return -ENOMEM;
|
||||
@@ -92,7 +90,7 @@ int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
|
||||
return err;
|
||||
}
|
||||
|
||||
blkif->evtchn = op.u.bind_interdomain.port1;
|
||||
blkif->evtchn = op.u.bind_interdomain.local_port;
|
||||
|
||||
sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
|
||||
SHARED_RING_INIT(sring);
|
||||
|
||||
@@ -223,7 +223,7 @@ static int evtchn_ioctl(struct inode *inode, struct file *file,
|
||||
if (copy_from_user(&bind, (void *)arg, sizeof(bind)))
|
||||
break;
|
||||
|
||||
op.cmd = EVTCHNOP_bind_virq;
|
||||
op.cmd = EVTCHNOP_bind_virq;
|
||||
op.u.bind_virq.virq = bind.virq;
|
||||
op.u.bind_virq.vcpu = 0;
|
||||
rc = HYPERVISOR_event_channel_op(&op);
|
||||
@@ -243,16 +243,14 @@ static int evtchn_ioctl(struct inode *inode, struct file *file,
|
||||
if (copy_from_user(&bind, (void *)arg, sizeof(bind)))
|
||||
break;
|
||||
|
||||
op.cmd = EVTCHNOP_bind_interdomain;
|
||||
op.u.bind_interdomain.dom1 = DOMID_SELF;
|
||||
op.u.bind_interdomain.dom2 = bind.remote_domain;
|
||||
op.u.bind_interdomain.port1 = 0;
|
||||
op.u.bind_interdomain.port2 = bind.remote_port;
|
||||
op.cmd = EVTCHNOP_bind_interdomain;
|
||||
op.u.bind_interdomain.remote_dom = bind.remote_domain;
|
||||
op.u.bind_interdomain.remote_port = bind.remote_port;
|
||||
rc = HYPERVISOR_event_channel_op(&op);
|
||||
if (rc != 0)
|
||||
break;
|
||||
|
||||
rc = op.u.bind_interdomain.port1;
|
||||
rc = op.u.bind_interdomain.local_port;
|
||||
port_user[rc] = u;
|
||||
unmask_evtchn(rc);
|
||||
break;
|
||||
@@ -265,7 +263,7 @@ static int evtchn_ioctl(struct inode *inode, struct file *file,
|
||||
if (copy_from_user(&bind, (void *)arg, sizeof(bind)))
|
||||
break;
|
||||
|
||||
op.cmd = EVTCHNOP_alloc_unbound;
|
||||
op.cmd = EVTCHNOP_alloc_unbound;
|
||||
op.u.alloc_unbound.dom = DOMID_SELF;
|
||||
op.u.alloc_unbound.remote_dom = bind.remote_domain;
|
||||
rc = HYPERVISOR_event_channel_op(&op);
|
||||
@@ -292,6 +290,11 @@ static int evtchn_ioctl(struct inode *inode, struct file *file,
|
||||
} else {
|
||||
port_user[unbind.port] = NULL;
|
||||
mask_evtchn(unbind.port);
|
||||
|
||||
op.cmd = EVTCHNOP_close;
|
||||
op.u.close.port = unbind.port;
|
||||
BUG_ON(HYPERVISOR_event_channel_op(&op));
|
||||
|
||||
rc = 0;
|
||||
}
|
||||
break;
|
||||
@@ -390,8 +393,7 @@ static int evtchn_release(struct inode *inode, struct file *filp)
|
||||
port_user[i] = NULL;
|
||||
mask_evtchn(i);
|
||||
|
||||
op.cmd = EVTCHNOP_close;
|
||||
op.u.close.dom = DOMID_SELF;
|
||||
op.cmd = EVTCHNOP_close;
|
||||
op.u.close.port = i;
|
||||
BUG_ON(HYPERVISOR_event_channel_op(&op));
|
||||
}
|
||||
|
||||
@@ -180,10 +180,8 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref,
|
||||
int err;
|
||||
evtchn_op_t op = {
|
||||
.cmd = EVTCHNOP_bind_interdomain,
|
||||
.u.bind_interdomain.dom1 = DOMID_SELF,
|
||||
.u.bind_interdomain.dom2 = netif->domid,
|
||||
.u.bind_interdomain.port1 = 0,
|
||||
.u.bind_interdomain.port2 = evtchn };
|
||||
.u.bind_interdomain.remote_dom = netif->domid,
|
||||
.u.bind_interdomain.remote_port = evtchn };
|
||||
|
||||
netif->comms_area = alloc_vm_area(2*PAGE_SIZE);
|
||||
if (netif->comms_area == NULL)
|
||||
@@ -202,7 +200,7 @@ int netif_map(netif_t *netif, unsigned long tx_ring_ref,
|
||||
return err;
|
||||
}
|
||||
|
||||
netif->evtchn = op.u.bind_interdomain.port1;
|
||||
netif->evtchn = op.u.bind_interdomain.local_port;
|
||||
|
||||
netif->irq = bind_evtchn_to_irqhandler(
|
||||
netif->evtchn, netif_be_int, 0, netif->dev->name, netif);
|
||||
|
||||
@@ -120,10 +120,8 @@ tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn)
|
||||
int err;
|
||||
evtchn_op_t op = {
|
||||
.cmd = EVTCHNOP_bind_interdomain,
|
||||
.u.bind_interdomain.dom1 = DOMID_SELF,
|
||||
.u.bind_interdomain.dom2 = tpmif->domid,
|
||||
.u.bind_interdomain.port1 = 0,
|
||||
.u.bind_interdomain.port2 = evtchn };
|
||||
.u.bind_interdomain.remote_dom = tpmif->domid,
|
||||
.u.bind_interdomain.remote_port = evtchn };
|
||||
|
||||
if ((tpmif->tx_area = alloc_vm_area(PAGE_SIZE)) == NULL)
|
||||
return -ENOMEM;
|
||||
@@ -141,7 +139,7 @@ tpmif_map(tpmif_t *tpmif, unsigned long shared_page, unsigned int evtchn)
|
||||
return err;
|
||||
}
|
||||
|
||||
tpmif->evtchn = op.u.bind_interdomain.port1;
|
||||
tpmif->evtchn = op.u.bind_interdomain.local_port;
|
||||
|
||||
tpmif->tx = (tpmif_tx_interface_t *)tpmif->tx_area->addr;
|
||||
|
||||
|
||||
@@ -123,9 +123,9 @@ static inline void clear_evtchn(int port)
|
||||
|
||||
static inline void notify_remote_via_evtchn(int port)
|
||||
{
|
||||
evtchn_op_t op = {
|
||||
.cmd = EVTCHNOP_send,
|
||||
.u.send.local_port = port };
|
||||
evtchn_op_t op;
|
||||
op.cmd = EVTCHNOP_send,
|
||||
op.u.send.port = port;
|
||||
(void)HYPERVISOR_event_channel_op(&op);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -2806,7 +2806,7 @@ int main(int argc, char **argv)
|
||||
|
||||
case QEMU_OPTION_p:
|
||||
{
|
||||
extern short ioreq_remote_port;
|
||||
extern u16 ioreq_remote_port;
|
||||
ioreq_remote_port = atoi(optarg);
|
||||
printf("port: %d\n", ioreq_remote_port);
|
||||
}
|
||||
|
||||
@@ -432,13 +432,13 @@ static PyObject *pyxc_evtchn_alloc_unbound(PyObject *self,
|
||||
{
|
||||
XcObject *xc = (XcObject *)self;
|
||||
|
||||
u32 dom = DOMID_SELF, remote_dom;
|
||||
u32 dom, remote_dom;
|
||||
int port;
|
||||
|
||||
static char *kwd_list[] = { "remote_dom", "dom", NULL };
|
||||
static char *kwd_list[] = { "dom", "remote_dom", NULL };
|
||||
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i|i", kwd_list,
|
||||
&remote_dom, &dom) )
|
||||
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwd_list,
|
||||
&dom, &remote_dom) )
|
||||
return NULL;
|
||||
|
||||
if ( (port = xc_evtchn_alloc_unbound(xc->xc_handle, dom, remote_dom)) < 0 )
|
||||
@@ -943,8 +943,9 @@ static PyMethodDef pyxc_methods[] = {
|
||||
{ "evtchn_alloc_unbound",
|
||||
(PyCFunction)pyxc_evtchn_alloc_unbound,
|
||||
METH_VARARGS | METH_KEYWORDS, "\n"
|
||||
"Allocate an unbound local port that will await a remote connection.\n"
|
||||
" dom [int]: Remote domain to accept connections from.\n\n"
|
||||
"Allocate an unbound port that will await a remote connection.\n"
|
||||
" dom [int]: Domain whose port space to allocate from.\n"
|
||||
" remote_dom [int]: Remote domain to accept connections from.\n\n"
|
||||
"Returns: [int] Unbound event-channel port.\n" },
|
||||
|
||||
{ "evtchn_status",
|
||||
|
||||
@@ -197,6 +197,7 @@ def recreate(xeninfo):
|
||||
log.info("Recreating domain %d with new UUID %s.", domid, uuid)
|
||||
|
||||
vm = XendDomainInfo(uuid, xeninfo, domid, True)
|
||||
vm.removeDom()
|
||||
vm.storeVmDetails()
|
||||
vm.storeDomDetails()
|
||||
|
||||
|
||||
+80
-193
@@ -70,7 +70,7 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
|
||||
{
|
||||
struct evtchn *chn;
|
||||
struct domain *d;
|
||||
int port = alloc->port;
|
||||
int port;
|
||||
domid_t dom = alloc->dom;
|
||||
long rc = 0;
|
||||
|
||||
@@ -84,176 +84,80 @@ static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
|
||||
/* Obtain, or ensure that we already have, a valid <port>. */
|
||||
if ( port == 0 )
|
||||
{
|
||||
if ( (port = get_free_port(d)) < 0 )
|
||||
ERROR_EXIT(port);
|
||||
}
|
||||
else if ( !port_is_valid(d, port) )
|
||||
ERROR_EXIT(-EINVAL);
|
||||
if ( (port = get_free_port(d)) < 0 )
|
||||
ERROR_EXIT(port);
|
||||
chn = evtchn_from_port(d, port);
|
||||
|
||||
/* Validate channel's current state. */
|
||||
switch ( chn->state )
|
||||
{
|
||||
case ECS_FREE:
|
||||
chn->state = ECS_UNBOUND;
|
||||
chn->u.unbound.remote_domid = alloc->remote_dom;
|
||||
break;
|
||||
chn->state = ECS_UNBOUND;
|
||||
chn->u.unbound.remote_domid = alloc->remote_dom;
|
||||
|
||||
case ECS_UNBOUND:
|
||||
if ( chn->u.unbound.remote_domid != alloc->remote_dom )
|
||||
ERROR_EXIT(-EINVAL);
|
||||
break;
|
||||
|
||||
default:
|
||||
ERROR_EXIT(-EINVAL);
|
||||
}
|
||||
alloc->port = port;
|
||||
|
||||
out:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
|
||||
put_domain(d);
|
||||
|
||||
alloc->port = port;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
|
||||
{
|
||||
struct evtchn *chn1, *chn2;
|
||||
struct domain *d1, *d2;
|
||||
int port1 = bind->port1, port2 = bind->port2;
|
||||
domid_t dom1 = bind->dom1, dom2 = bind->dom2;
|
||||
struct evtchn *lchn, *rchn;
|
||||
struct domain *ld = current->domain, *rd;
|
||||
int lport, rport = bind->remote_port;
|
||||
long rc = 0;
|
||||
|
||||
if ( !IS_PRIV(current->domain) && (dom1 != DOMID_SELF) )
|
||||
return -EPERM;
|
||||
|
||||
if ( dom1 == DOMID_SELF )
|
||||
dom1 = current->domain->domain_id;
|
||||
if ( dom2 == DOMID_SELF )
|
||||
dom2 = current->domain->domain_id;
|
||||
|
||||
if ( ((d1 = find_domain_by_id(dom1)) == NULL) ||
|
||||
((d2 = find_domain_by_id(dom2)) == NULL) )
|
||||
{
|
||||
if ( d1 != NULL )
|
||||
put_domain(d1);
|
||||
if ( (rd = find_domain_by_id(bind->remote_dom)) == NULL )
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
/* Avoid deadlock by first acquiring lock of domain with smaller id. */
|
||||
if ( d1 < d2 )
|
||||
if ( ld < rd )
|
||||
{
|
||||
spin_lock(&d1->evtchn_lock);
|
||||
spin_lock(&d2->evtchn_lock);
|
||||
spin_lock(&ld->evtchn_lock);
|
||||
spin_lock(&rd->evtchn_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( d1 != d2 )
|
||||
spin_lock(&d2->evtchn_lock);
|
||||
spin_lock(&d1->evtchn_lock);
|
||||
if ( ld != rd )
|
||||
spin_lock(&rd->evtchn_lock);
|
||||
spin_lock(&ld->evtchn_lock);
|
||||
}
|
||||
|
||||
/* Obtain, or ensure that we already have, a valid <port1>. */
|
||||
if ( port1 == 0 )
|
||||
{
|
||||
if ( (port1 = get_free_port(d1)) < 0 )
|
||||
ERROR_EXIT(port1);
|
||||
}
|
||||
else if ( !port_is_valid(d1, port1) )
|
||||
if ( (lport = get_free_port(ld)) < 0 )
|
||||
ERROR_EXIT(lport);
|
||||
lchn = evtchn_from_port(ld, lport);
|
||||
|
||||
if ( !port_is_valid(rd, rport) )
|
||||
ERROR_EXIT(-EINVAL);
|
||||
chn1 = evtchn_from_port(d1, port1);
|
||||
|
||||
/* Obtain, or ensure that we already have, a valid <port2>. */
|
||||
if ( port2 == 0 )
|
||||
{
|
||||
/* Make port1 non-free while we allocate port2 (in case dom1==dom2). */
|
||||
u16 state = chn1->state;
|
||||
chn1->state = ECS_INTERDOMAIN;
|
||||
port2 = get_free_port(d2);
|
||||
chn1->state = state;
|
||||
if ( port2 < 0 )
|
||||
ERROR_EXIT(port2);
|
||||
}
|
||||
else if ( !port_is_valid(d2, port2) )
|
||||
rchn = evtchn_from_port(rd, rport);
|
||||
if ( (rchn->state != ECS_UNBOUND) ||
|
||||
(rchn->u.unbound.remote_domid != ld->domain_id) )
|
||||
ERROR_EXIT(-EINVAL);
|
||||
chn2 = evtchn_from_port(d2, port2);
|
||||
|
||||
/* Validate <dom1,port1>'s current state. */
|
||||
switch ( chn1->state )
|
||||
{
|
||||
case ECS_FREE:
|
||||
break;
|
||||
|
||||
case ECS_UNBOUND:
|
||||
if ( chn1->u.unbound.remote_domid != dom2 )
|
||||
ERROR_EXIT(-EINVAL);
|
||||
break;
|
||||
|
||||
case ECS_INTERDOMAIN:
|
||||
if ( chn1->u.interdomain.remote_dom != d2 )
|
||||
ERROR_EXIT(-EINVAL);
|
||||
if ( (chn1->u.interdomain.remote_port != port2) && (bind->port2 != 0) )
|
||||
ERROR_EXIT(-EINVAL);
|
||||
port2 = chn1->u.interdomain.remote_port;
|
||||
goto out;
|
||||
|
||||
default:
|
||||
ERROR_EXIT(-EINVAL);
|
||||
}
|
||||
|
||||
/* Validate <dom2,port2>'s current state. */
|
||||
switch ( chn2->state )
|
||||
{
|
||||
case ECS_FREE:
|
||||
if ( !IS_PRIV(current->domain) && (dom2 != DOMID_SELF) )
|
||||
ERROR_EXIT(-EPERM);
|
||||
break;
|
||||
|
||||
case ECS_UNBOUND:
|
||||
if ( chn2->u.unbound.remote_domid != dom1 )
|
||||
ERROR_EXIT(-EINVAL);
|
||||
break;
|
||||
|
||||
case ECS_INTERDOMAIN:
|
||||
if ( chn2->u.interdomain.remote_dom != d1 )
|
||||
ERROR_EXIT(-EINVAL);
|
||||
if ( (chn2->u.interdomain.remote_port != port1) && (bind->port1 != 0) )
|
||||
ERROR_EXIT(-EINVAL);
|
||||
port1 = chn2->u.interdomain.remote_port;
|
||||
goto out;
|
||||
|
||||
default:
|
||||
ERROR_EXIT(-EINVAL);
|
||||
}
|
||||
lchn->u.interdomain.remote_dom = rd;
|
||||
lchn->u.interdomain.remote_port = (u16)rport;
|
||||
lchn->state = ECS_INTERDOMAIN;
|
||||
|
||||
rchn->u.interdomain.remote_dom = ld;
|
||||
rchn->u.interdomain.remote_port = (u16)lport;
|
||||
rchn->state = ECS_INTERDOMAIN;
|
||||
|
||||
/*
|
||||
* Everything checked out okay -- bind <dom1,port1> to <dom2,port2>.
|
||||
* We may have lost notifications on the remote unbound port. Fix that up
|
||||
* here by conservatively always setting a notification on the local port.
|
||||
*/
|
||||
evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
|
||||
|
||||
chn1->u.interdomain.remote_dom = d2;
|
||||
chn1->u.interdomain.remote_port = (u16)port2;
|
||||
chn1->state = ECS_INTERDOMAIN;
|
||||
|
||||
chn2->u.interdomain.remote_dom = d1;
|
||||
chn2->u.interdomain.remote_port = (u16)port1;
|
||||
chn2->state = ECS_INTERDOMAIN;
|
||||
bind->local_port = lport;
|
||||
|
||||
out:
|
||||
spin_unlock(&d1->evtchn_lock);
|
||||
if ( d1 != d2 )
|
||||
spin_unlock(&d2->evtchn_lock);
|
||||
spin_unlock(&ld->evtchn_lock);
|
||||
if ( ld != rd )
|
||||
spin_unlock(&rd->evtchn_lock);
|
||||
|
||||
put_domain(d1);
|
||||
put_domain(d2);
|
||||
|
||||
bind->port1 = port1;
|
||||
bind->port2 = port2;
|
||||
put_domain(rd);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -264,39 +168,34 @@ static long evtchn_bind_virq(evtchn_bind_virq_t *bind)
|
||||
struct evtchn *chn;
|
||||
struct vcpu *v;
|
||||
struct domain *d = current->domain;
|
||||
int port, virq = bind->virq;
|
||||
int port, virq = bind->virq, vcpu = bind->vcpu;
|
||||
long rc = 0;
|
||||
|
||||
if ( virq >= ARRAY_SIZE(v->virq_to_evtchn) )
|
||||
return -EINVAL;
|
||||
|
||||
if ( (v = d->vcpu[bind->vcpu]) == NULL )
|
||||
if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || ((v = d->vcpu[vcpu]) == NULL) )
|
||||
return -ENOENT;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
|
||||
/*
|
||||
* Port 0 is the fallback port for VIRQs that haven't been explicitly
|
||||
* bound yet.
|
||||
*/
|
||||
if ( ((port = v->virq_to_evtchn[virq]) != 0) ||
|
||||
((port = get_free_port(d)) < 0) )
|
||||
goto out;
|
||||
if ( v->virq_to_evtchn[virq] != 0 )
|
||||
ERROR_EXIT(-EEXIST);
|
||||
|
||||
if ( (port = get_free_port(d)) < 0 )
|
||||
ERROR_EXIT(port);
|
||||
|
||||
chn = evtchn_from_port(d, port);
|
||||
chn->state = ECS_VIRQ;
|
||||
chn->notify_vcpu_id = v->vcpu_id;
|
||||
chn->notify_vcpu_id = vcpu;
|
||||
chn->u.virq = virq;
|
||||
|
||||
v->virq_to_evtchn[virq] = port;
|
||||
v->virq_to_evtchn[virq] = bind->port = port;
|
||||
|
||||
out:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
|
||||
if ( port < 0 )
|
||||
return port;
|
||||
|
||||
bind->port = port;
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -304,27 +203,27 @@ static long evtchn_bind_ipi(evtchn_bind_ipi_t *bind)
|
||||
{
|
||||
struct evtchn *chn;
|
||||
struct domain *d = current->domain;
|
||||
int port;
|
||||
int port, vcpu = bind->vcpu;
|
||||
long rc = 0;
|
||||
|
||||
if ( d->vcpu[bind->vcpu] == NULL )
|
||||
if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || (d->vcpu[vcpu] == NULL) )
|
||||
return -ENOENT;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
|
||||
if ( (port = get_free_port(d)) >= 0 )
|
||||
{
|
||||
chn = evtchn_from_port(d, port);
|
||||
chn->state = ECS_IPI;
|
||||
chn->notify_vcpu_id = bind->vcpu;
|
||||
}
|
||||
if ( (port = get_free_port(d)) < 0 )
|
||||
ERROR_EXIT(port);
|
||||
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
|
||||
if ( port < 0 )
|
||||
return port;
|
||||
chn = evtchn_from_port(d, port);
|
||||
chn->state = ECS_IPI;
|
||||
chn->notify_vcpu_id = vcpu;
|
||||
|
||||
bind->port = port;
|
||||
return 0;
|
||||
|
||||
out:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -332,16 +231,19 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
|
||||
{
|
||||
struct evtchn *chn;
|
||||
struct domain *d = current->domain;
|
||||
int port, rc, pirq = bind->pirq;
|
||||
int port, pirq = bind->pirq;
|
||||
long rc;
|
||||
|
||||
if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
|
||||
if ( ((rc = port = d->pirq_to_evtchn[pirq]) != 0) ||
|
||||
((rc = port = get_free_port(d)) < 0) )
|
||||
goto out;
|
||||
if ( d->pirq_to_evtchn[pirq] != 0 )
|
||||
ERROR_EXIT(-EEXIST);
|
||||
|
||||
if ( (port = get_free_port(d)) < 0 )
|
||||
ERROR_EXIT(port);
|
||||
|
||||
chn = evtchn_from_port(d, port);
|
||||
|
||||
@@ -357,14 +259,12 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
|
||||
chn->state = ECS_PIRQ;
|
||||
chn->u.pirq = pirq;
|
||||
|
||||
bind->port = port;
|
||||
|
||||
out:
|
||||
spin_unlock(&d->evtchn_lock);
|
||||
|
||||
if ( rc < 0 )
|
||||
return rc;
|
||||
|
||||
bind->port = port;
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@@ -478,22 +378,7 @@ static long __evtchn_close(struct domain *d1, int port1)
|
||||
|
||||
static long evtchn_close(evtchn_close_t *close)
|
||||
{
|
||||
struct domain *d;
|
||||
long rc;
|
||||
domid_t dom = close->dom;
|
||||
|
||||
if ( dom == DOMID_SELF )
|
||||
dom = current->domain->domain_id;
|
||||
else if ( !IS_PRIV(current->domain) )
|
||||
return -EPERM;
|
||||
|
||||
if ( (d = find_domain_by_id(dom)) == NULL )
|
||||
return -ESRCH;
|
||||
|
||||
rc = __evtchn_close(d, close->port);
|
||||
|
||||
put_domain(d);
|
||||
return rc;
|
||||
return __evtchn_close(current->domain, close->port);
|
||||
}
|
||||
|
||||
|
||||
@@ -523,6 +408,9 @@ long evtchn_send(int lport)
|
||||
case ECS_IPI:
|
||||
evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport);
|
||||
break;
|
||||
case ECS_UNBOUND:
|
||||
/* silently drop the notification */
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
@@ -611,9 +499,8 @@ static long evtchn_bind_vcpu(evtchn_bind_vcpu_t *bind)
|
||||
struct evtchn *chn;
|
||||
long rc = 0;
|
||||
|
||||
if ( (vcpu >= MAX_VIRT_CPUS) || (d->vcpu[vcpu] == NULL) ) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if ( (vcpu >= ARRAY_SIZE(d->vcpu)) || (d->vcpu[vcpu] == NULL) )
|
||||
return -ENOENT;
|
||||
|
||||
spin_lock(&d->evtchn_lock);
|
||||
|
||||
@@ -689,7 +576,7 @@ long do_event_channel_op(evtchn_op_t *uop)
|
||||
break;
|
||||
|
||||
case EVTCHNOP_send:
|
||||
rc = evtchn_send(op.u.send.local_port);
|
||||
rc = evtchn_send(op.u.send.port);
|
||||
break;
|
||||
|
||||
case EVTCHNOP_status:
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
#define __XEN_PUBLIC_EVENT_CHANNEL_H__
|
||||
|
||||
/*
|
||||
* EVTCHNOP_alloc_unbound: Allocate a port in <dom> for later binding to
|
||||
* <remote_dom>. <port> may be wildcarded by setting to zero, in which case a
|
||||
* fresh port will be allocated, and the field filled in on return.
|
||||
* EVTCHNOP_alloc_unbound: Allocate a port in domain <dom> and mark as
|
||||
* accepting interdomain bindings from domain <remote_dom>. A fresh port
|
||||
* is allocated in <dom> and returned as <port>.
|
||||
* NOTES:
|
||||
* 1. If the caller is unprivileged then <dom> must be DOMID_SELF.
|
||||
*/
|
||||
@@ -20,36 +20,24 @@
|
||||
typedef struct evtchn_alloc_unbound {
|
||||
/* IN parameters */
|
||||
domid_t dom, remote_dom;
|
||||
/* IN/OUT parameters */
|
||||
/* OUT parameters */
|
||||
u32 port;
|
||||
} evtchn_alloc_unbound_t;
|
||||
|
||||
/*
|
||||
* EVTCHNOP_bind_interdomain: Construct an interdomain event channel between
|
||||
* <dom1> and <dom2>. Either <port1> or <port2> may be wildcarded by setting to
|
||||
* zero. On successful return both <port1> and <port2> are filled in and
|
||||
* <dom1,port1> is fully bound to <dom2,port2>.
|
||||
*
|
||||
* NOTES:
|
||||
* 1. A wildcarded port is allocated from the relevant domain's free list
|
||||
* (i.e., some port that was previously EVTCHNSTAT_closed). However, if the
|
||||
* remote port pair is already fully bound then a port is not allocated,
|
||||
* and instead the existing local port is returned to the caller.
|
||||
* 2. If the caller is unprivileged then <dom1> must be DOMID_SELF.
|
||||
* 3. If the caller is unprivileged and <dom2,port2> is EVTCHNSTAT_closed
|
||||
* then <dom2> must be DOMID_SELF.
|
||||
* 4. If either port is already bound then it must be bound to the other
|
||||
* specified domain and port (if not wildcarded).
|
||||
* 5. If either port is awaiting binding (EVTCHNSTAT_unbound) then it must
|
||||
* be awaiting binding to the other domain, and the other port pair must
|
||||
* be closed or unbound.
|
||||
* the calling domain and <remote_dom>. <remote_dom,remote_port> must identify
|
||||
* a port that is unbound and marked as accepting bindings from the calling
|
||||
* domain. A fresh port is allocated in the calling domain and returned as
|
||||
* <local_port>.
|
||||
*/
|
||||
#define EVTCHNOP_bind_interdomain 0
|
||||
typedef struct evtchn_bind_interdomain {
|
||||
/* IN parameters. */
|
||||
domid_t dom1, dom2;
|
||||
/* IN/OUT parameters. */
|
||||
u32 port1, port2;
|
||||
domid_t remote_dom;
|
||||
u32 remote_port;
|
||||
/* OUT parameters. */
|
||||
u32 local_port;
|
||||
} evtchn_bind_interdomain_t;
|
||||
|
||||
/*
|
||||
@@ -99,31 +87,24 @@ typedef struct evtchn_bind_ipi {
|
||||
} evtchn_bind_ipi_t;
|
||||
|
||||
/*
|
||||
* EVTCHNOP_close: Close the communication channel which has an endpoint at
|
||||
* <dom, port>. If the channel is interdomain then the remote end is placed in
|
||||
* the unbound state (EVTCHNSTAT_unbound), awaiting a new connection.
|
||||
* NOTES:
|
||||
* 1. <dom> may be specified as DOMID_SELF.
|
||||
* 2. Only a sufficiently-privileged domain may close an event channel
|
||||
* for which <dom> is not DOMID_SELF.
|
||||
* EVTCHNOP_close: Close a local event channel <port>. If the channel is
|
||||
* interdomain then the remote end is placed in the unbound state
|
||||
* (EVTCHNSTAT_unbound), awaiting a new connection.
|
||||
*/
|
||||
#define EVTCHNOP_close 3
|
||||
typedef struct evtchn_close {
|
||||
/* IN parameters. */
|
||||
domid_t dom;
|
||||
u32 port;
|
||||
/* No OUT parameters. */
|
||||
u32 port;
|
||||
} evtchn_close_t;
|
||||
|
||||
/*
|
||||
* EVTCHNOP_send: Send an event to the remote end of the channel whose local
|
||||
* endpoint is <DOMID_SELF, local_port>.
|
||||
* endpoint is <port>.
|
||||
*/
|
||||
#define EVTCHNOP_send 4
|
||||
typedef struct evtchn_send {
|
||||
/* IN parameters. */
|
||||
u32 local_port;
|
||||
/* No OUT parameters. */
|
||||
u32 port;
|
||||
} evtchn_send_t;
|
||||
|
||||
/*
|
||||
|
||||