bitkeeper revision 1.1159.130.1 (41792c8bfIrnaq8cezNM7nbYpseVFQ)

Extend Xen's evtchn interface.
This commit is contained in:
kaf24@freefall.cl.cam.ac.uk committed 2004-10-22 15:51:39 +00:00
1 parent b9d51015ab
commit 6f46072ed0
6 files changed
+199 -29

No files matched your search

+3
View File
@@ -146,6 +146,9 @@ typedef struct {
} u;
} xc_evtchn_status_t;
int xc_evtchn_alloc_unbound(int xc_handle,
u32 dom,
int *port);
int xc_evtchn_bind_interdomain(int xc_handle,
u32 dom1, /* may be DOMID_SELF */
u32 dom2, /* may be DOMID_SELF */
+26 -3
View File
@@ -31,6 +31,26 @@ static int do_evtchn_op(int xc_handle, evtchn_op_t *op)
}
int xc_evtchn_alloc_unbound(int xc_handle,
u32 dom,
int *port)
{
evtchn_op_t op;
int rc;
op.cmd = EVTCHNOP_alloc_unbound;
op.u.alloc_unbound.dom = (domid_t)dom;
if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
{
if ( port != NULL )
*port = op.u.alloc_unbound.port;
}
return rc;
}
int xc_evtchn_bind_interdomain(int xc_handle,
u32 dom1,
u32 dom2,
@@ -41,9 +61,12 @@ int xc_evtchn_bind_interdomain(int xc_handle,
int rc;
op.cmd = EVTCHNOP_bind_interdomain;
op.u.bind_interdomain.dom1 = (domid_t)dom1;
op.u.bind_interdomain.dom2 = (domid_t)dom2;
op.u.bind_interdomain.dom1 = (domid_t)dom1;
op.u.bind_interdomain.dom2 = (domid_t)dom2;
op.u.bind_interdomain.port1 = (port1 != NULL) ? *port1 : 0;
op.u.bind_interdomain.port2 = (port2 != NULL) ? *port2 : 0;
if ( (rc = do_evtchn_op(xc_handle, &op)) == 0 )
{
if ( port1 != NULL )
+32 -5
View File
@@ -462,6 +462,26 @@ static PyObject *pyxc_bvtsched_domain_get(PyObject *self,
"warpu", warpu);
}
static PyObject *pyxc_evtchn_alloc_unbound(PyObject *self,
PyObject *args,
PyObject *kwds)
{
XcObject *xc = (XcObject *)self;
u32 dom;
int port;
static char *kwd_list[] = { "dom", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "i", kwd_list, &dom) )
return NULL;
if ( xc_evtchn_alloc_unbound(xc->xc_handle, dom, &port) != 0 )
return PyErr_SetFromErrno(xc_error);
return PyInt_FromLong(port);
}
static PyObject *pyxc_evtchn_bind_interdomain(PyObject *self,
PyObject *args,
PyObject *kwds)
@@ -469,12 +489,12 @@ static PyObject *pyxc_evtchn_bind_interdomain(PyObject *self,
XcObject *xc = (XcObject *)self;
u32 dom1 = DOMID_SELF, dom2 = DOMID_SELF;
int port1, port2;
int port1 = 0, port2 = 0;
static char *kwd_list[] = { "dom1", "dom2", NULL };
static char *kwd_list[] = { "dom1", "dom2", "port1", "port2", NULL };
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|ii", kwd_list,
&dom1, &dom2) )
if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iiii", kwd_list,
&dom1, &dom2, &port1, &port2) )
return NULL;
if ( xc_evtchn_bind_interdomain(xc->xc_handle, dom1,
@@ -965,6 +985,13 @@ static PyMethodDef pyxc_methods[] = {
"Returns [dict]:\n"
" slice [long]: Scheduler time slice.\n" },
{ "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"
"Returns: [int] Unbound event-channel port.\n" },
{ "evtchn_bind_interdomain",
(PyCFunction)pyxc_evtchn_bind_interdomain,
METH_VARARGS | METH_KEYWORDS, "\n"
@@ -985,7 +1012,7 @@ static PyMethodDef pyxc_methods[] = {
{ "evtchn_close",
(PyCFunction)pyxc_evtchn_close,
METH_VARARGS | METH_KEYWORDS, "\n"
"Close an event channel.\n"
"Close an event channel. If interdomain, sets remote end to 'unbound'.\n"
" dom [int, SELF]: Dom-id of one endpoint of the channel.\n"
" port [int]: Port-id of one endpoint of the channel.\n\n"
"Returns: [int] 0 on success; -1 on error.\n" },
+1 -1
View File
@@ -1059,7 +1059,7 @@ static PyObject *xu_port_new(PyObject *self, PyObject *args)
{
xu_port_object *xup;
u32 dom;
int port1, port2;
int port1 = 0, port2 = 0;
if ( !PyArg_ParseTuple(args, "i", &dom) )
return NULL;
+98 -12
View File
@@ -29,6 +29,7 @@
#define INIT_EVENT_CHANNELS 16
#define MAX_EVENT_CHANNELS 1024
static int get_free_port(struct domain *d)
{
int max, port;
@@ -67,16 +68,44 @@ static int get_free_port(struct domain *d)
return port;
}
static long evtchn_alloc_unbound(evtchn_alloc_unbound_t *alloc)
{
struct domain *d = current;
int port;
spin_lock(&d->event_channel_lock);
if ( (port = get_free_port(d)) >= 0 )
{
d->event_channel[port].state = ECS_UNBOUND;
d->event_channel[port].u.unbound.remote_domid = alloc->dom;
}
spin_unlock(&d->event_channel_lock);
if ( port < 0 )
return port;
alloc->port = port;
return 0;
}
static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
{
#define ERROR_EXIT(_errno) do { rc = (_errno); goto out; } while ( 0 )
struct domain *d1, *d2;
int port1 = 0, port2 = 0;
int port1 = bind->port1, port2 = bind->port2;
domid_t dom1 = bind->dom1, dom2 = bind->dom2;
long rc = 0;
if ( !IS_PRIV(current) )
if ( !IS_PRIV(current) && (dom1 != DOMID_SELF) )
return -EPERM;
if ( (port1 < 0) || (port2 < 0) )
return -EINVAL;
if ( dom1 == DOMID_SELF )
dom1 = current->id;
if ( dom2 == DOMID_SELF )
@@ -103,25 +132,73 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
spin_lock(&d1->event_channel_lock);
}
if ( (port1 = get_free_port(d1)) < 0 )
/* Obtain, or ensure that we already have, a valid <port1>. */
if ( port1 == 0 )
{
rc = port1;
if ( (port1 = get_free_port(d1)) < 0 )
ERROR_EXIT(port1);
}
else if ( port1 >= d1->max_event_channel )
ERROR_EXIT(-EINVAL);
/* 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 tmp = d1->event_channel[port1].state;
d1->event_channel[port1].state = ECS_INTERDOMAIN;
port2 = get_free_port(d2);
d1->event_channel[port1].state = tmp;
if ( port2 < 0 )
ERROR_EXIT(port2);
}
else if ( port2 >= d2->max_event_channel )
ERROR_EXIT(-EINVAL);
/* Validate <dom1,port1>'s current state. */
switch ( d1->event_channel[port1].state )
{
case ECS_FREE:
break;
case ECS_UNBOUND:
if ( d1->event_channel[port1].u.unbound.remote_domid != dom2 )
ERROR_EXIT(-EINVAL);
break;
case ECS_INTERDOMAIN:
rc = ((d1->event_channel[port1].u.interdomain.remote_dom != d2) ||
(d1->event_channel[port1].u.interdomain.remote_port != port2)) ?
-EINVAL : 0;
goto out;
default:
ERROR_EXIT(-EINVAL);
}
/* 'Allocate' port1 before searching for a free port2. */
d1->event_channel[port1].state = ECS_INTERDOMAIN;
if ( (port2 = get_free_port(d2)) < 0 )
/* Validate <dom2,port2>'s current state. */
switch ( d2->event_channel[port2].state )
{
d1->event_channel[port1].state = ECS_FREE;
rc = port2;
goto out;
case ECS_FREE:
break;
case ECS_UNBOUND:
if ( d2->event_channel[port2].u.unbound.remote_domid != dom1 )
ERROR_EXIT(-EINVAL);
break;
default:
ERROR_EXIT(-EINVAL);
}
/*
* Everything checked out okay -- bind <dom1,port1> to <dom2,port2>.
*/
d1->event_channel[port1].u.interdomain.remote_dom = d2;
d1->event_channel[port1].u.interdomain.remote_port = (u16)port2;
d1->event_channel[port1].state = ECS_INTERDOMAIN;
d2->event_channel[port2].u.interdomain.remote_dom = d1;
d2->event_channel[port2].u.interdomain.remote_port = (u16)port1;
d2->event_channel[port2].state = ECS_INTERDOMAIN;
@@ -138,6 +215,7 @@ static long evtchn_bind_interdomain(evtchn_bind_interdomain_t *bind)
bind->port2 = port2;
return rc;
#undef ERROR_EXIT
}
@@ -295,6 +373,7 @@ static long __evtchn_close(struct domain *d1, int port1)
BUG();
chn2[port2].state = ECS_UNBOUND;
chn2[port2].u.unbound.remote_domid = d1->id;
break;
default:
@@ -397,6 +476,7 @@ static long evtchn_status(evtchn_status_t *status)
break;
case ECS_UNBOUND:
status->status = EVTCHNSTAT_unbound;
status->u.unbound.dom = chn[port].u.unbound.remote_domid;
break;
case ECS_INTERDOMAIN:
status->status = EVTCHNSTAT_interdomain;
@@ -432,6 +512,12 @@ long do_event_channel_op(evtchn_op_t *uop)
switch ( op.cmd )
{
case EVTCHNOP_alloc_unbound:
rc = evtchn_alloc_unbound(&op.u.alloc_unbound);
if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
rc = -EFAULT; /* Cleaning up here would be a mess! */
break;
case EVTCHNOP_bind_interdomain:
rc = evtchn_bind_interdomain(&op.u.bind_interdomain);
if ( (rc == 0) && (copy_to_user(uop, &op, sizeof(op)) != 0) )
+39 -8
View File
@@ -10,17 +10,43 @@
#define __HYPERVISOR_IFS__EVENT_CHANNEL_H__
/*
* EVTCHNOP_bind_interdomain: Open an event channel between <dom1> and <dom2>.
* EVTCHNOP_alloc_unbound: Allocate a fresh local port and prepare
* it for binding to <dom>.
*/
#define EVTCHNOP_alloc_unbound 6
typedef struct {
/* IN parameters */
domid_t dom; /* 0 */
u16 __pad;
/* OUT parameters */
u32 port; /* 4 */
} PACKED evtchn_alloc_unbound_t; /* 8 bytes */
/*
* 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. <dom1> and/or <dom2> may be specified as DOMID_SELF.
* 2. Only a sufficiently-privileged domain may create an event channel.
* 3. <port1> and <port2> are only supplied if the op succeeds.
* 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.
*/
#define EVTCHNOP_bind_interdomain 0
typedef struct {
/* IN parameters. */
domid_t dom1, dom2; /* 0, 2 */
/* OUT parameters. */
/* IN/OUT parameters. */
u32 port1, port2; /* 4, 8 */
} PACKED evtchn_bind_interdomain_t; /* 12 bytes */
@@ -55,7 +81,8 @@ typedef struct {
/*
* EVTCHNOP_close: Close the communication channel which has an endpoint at
* <dom, port>.
* <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
@@ -96,13 +123,16 @@ typedef struct {
u16 __pad;
u32 port; /* 4 */
/* OUT parameters */
#define EVTCHNSTAT_closed 0 /* Chennel is not in use. */
#define EVTCHNSTAT_unbound 1 /* Channel is not bound to a source. */
#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 */
u32 status; /* 8 */
union { /* 12 */
struct {
domid_t dom; /* 12 */
} PACKED unbound; /* EVTCHNSTAT_unbound */
struct {
domid_t dom; /* 12 */
u16 __pad;
@@ -117,6 +147,7 @@ typedef struct {
u32 cmd; /* EVTCHNOP_* */ /* 0 */
u32 __reserved; /* 4 */
union { /* 8 */
evtchn_alloc_unbound_t alloc_unbound;
evtchn_bind_interdomain_t bind_interdomain;
evtchn_bind_virq_t bind_virq;
evtchn_bind_pirq_t bind_pirq;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.