mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
bitkeeper revision 1.751 (403ce3e1pBEv9Q629_q2HvL9RZ0ThA)
Merge labyrinth.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk into labyrinth.cl.cam.ac.uk:/auto/homes/maw48/xeno-unstable-tbufs-new.bk
This commit is contained in:
commit
f0dddbaf4a
8 files changed
+342
-188
No files matched your search
@@ -417,6 +417,7 @@
|
||||
3ddb79c2YTaZwOqWin9-QNgHge5RVw xen/include/hypervisor-ifs/block.h
|
||||
3ddb79c2PMeWTK86y4C3F4MzHw4A1g xen/include/hypervisor-ifs/dom0_ops.h
|
||||
3e6377eaioRoNm0m_HSDEAd4Vqrq_w xen/include/hypervisor-ifs/dom_mem_ops.h
|
||||
403cd194j2pyLqXD8FJ-ukvZzkPenw xen/include/hypervisor-ifs/event_channel.h
|
||||
3ddb79c25UE59iu4JJcbRalx95mvcg xen/include/hypervisor-ifs/hypervisor-if.h
|
||||
3ead095dE_VF-QA88rl_5cWYRWtRVQ xen/include/hypervisor-ifs/kbd.h
|
||||
3ddb79c2oRPrzClk3zbTkRHlpumzKA xen/include/hypervisor-ifs/network.h
|
||||
|
||||
@@ -21,6 +21,7 @@ kaf24@scramble.cl.cam.ac.uk
|
||||
kaf24@striker.cl.cam.ac.uk
|
||||
laudney@eclipse.(none)
|
||||
lynx@idefix.cl.cam.ac.uk
|
||||
maw48@labyrinth.cl.cam.ac.uk
|
||||
mwilli2@equilibrium.research.intel-research.net
|
||||
rac61@labyrinth.cl.cam.ac.uk
|
||||
rgr22@boulderdash.cl.cam.ac.uk
|
||||
|
||||
+14
-9
@@ -659,7 +659,6 @@ void __init setup_APIC_clocks (void)
|
||||
*/
|
||||
int reprogram_ac_timer(s_time_t timeout)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
s_time_t now;
|
||||
s_time_t expire;
|
||||
u64 apic_tmict;
|
||||
@@ -669,7 +668,8 @@ int reprogram_ac_timer(s_time_t timeout)
|
||||
* cause an immediate interrupt). At least this is guaranteed to hold it
|
||||
* off for ages (esp. since the clock ticks on bus clock, not cpu clock!).
|
||||
*/
|
||||
if (timeout == 0) {
|
||||
if ( timeout == 0 )
|
||||
{
|
||||
apic_tmict = 0xffffffff;
|
||||
goto reprogram;
|
||||
}
|
||||
@@ -677,10 +677,12 @@ int reprogram_ac_timer(s_time_t timeout)
|
||||
now = NOW();
|
||||
expire = timeout - now; /* value from now */
|
||||
|
||||
if (expire <= 0) {
|
||||
if ( expire <= 0 )
|
||||
{
|
||||
Dprintk("APICT[%02d] Timeout in the past 0x%08X%08X > 0x%08X%08X\n",
|
||||
cpu, (u32)(now>>32), (u32)now, (u32)(timeout>>32),(u32)timeout);
|
||||
return 0; /* timeout value in the past */
|
||||
smp_processor_id(), (u32)(now>>32),
|
||||
(u32)now, (u32)(timeout>>32),(u32)timeout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -693,12 +695,15 @@ int reprogram_ac_timer(s_time_t timeout)
|
||||
/* conversion to bus units */
|
||||
apic_tmict = (((u64)bus_scale) * expire)>>18;
|
||||
|
||||
if (apic_tmict >= 0xffffffff) {
|
||||
Dprintk("APICT[%02d] Timeout value too large\n", cpu);
|
||||
if ( apic_tmict >= 0xffffffff )
|
||||
{
|
||||
Dprintk("APICT[%02d] Timeout value too large\n", smp_processor_id());
|
||||
apic_tmict = 0xffffffff;
|
||||
}
|
||||
if (apic_tmict == 0) {
|
||||
Dprintk("APICT[%02d] timeout value too small\n", cpu);
|
||||
|
||||
if ( apic_tmict == 0 )
|
||||
{
|
||||
Dprintk("APICT[%02d] timeout value too small\n", smp_processor_id());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -127,6 +127,8 @@ void kill_domain_with_errmsg(const char *err)
|
||||
|
||||
void __kill_domain(struct task_struct *p)
|
||||
{
|
||||
extern void destroy_event_channels(struct task_struct *);
|
||||
|
||||
int i;
|
||||
struct task_struct **pp;
|
||||
unsigned long flags;
|
||||
@@ -149,6 +151,8 @@ void __kill_domain(struct task_struct *p)
|
||||
for ( i = 0; i < MAX_DOMAIN_VIFS; i++ )
|
||||
unlink_net_vif(p->net_vif_list[i]);
|
||||
|
||||
destroy_event_channels(p);
|
||||
|
||||
/*
|
||||
* Note this means that find_domain_by_id may fail, even when the caller
|
||||
* holds a reference to the domain being queried. Take care!
|
||||
@@ -467,8 +471,6 @@ unsigned int alloc_new_dom_mem(struct task_struct *p, unsigned int kbytes)
|
||||
/* Release resources belonging to task @p. */
|
||||
void release_task(struct task_struct *p)
|
||||
{
|
||||
extern void destroy_event_channels(struct task_struct *);
|
||||
|
||||
ASSERT(p->state == TASK_DYING);
|
||||
ASSERT(!p->has_cpu);
|
||||
|
||||
@@ -481,7 +483,6 @@ void release_task(struct task_struct *p)
|
||||
destroy_blkdev_info(p);
|
||||
|
||||
/* Free all memory associated with this domain. */
|
||||
destroy_event_channels(p);
|
||||
free_page((unsigned long)p->mm.perdomain_pt);
|
||||
UNSHARE_PFN(virt_to_page(p->shared_info));
|
||||
free_all_dom_mem(p);
|
||||
|
||||
+221
-156
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Event channels between domains.
|
||||
*
|
||||
* Copyright (c) 2003, K A Fraser.
|
||||
* Copyright (c) 2003-2004, K A Fraser.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@@ -22,135 +22,147 @@
|
||||
#include <xeno/sched.h>
|
||||
#include <xeno/event.h>
|
||||
|
||||
#include <hypervisor-ifs/hypervisor-if.h>
|
||||
#include <hypervisor-ifs/event_channel.h>
|
||||
|
||||
#define MAX_EVENT_CHANNELS 1024
|
||||
|
||||
static long event_channel_open(u16 target_dom)
|
||||
static int get_free_port(struct task_struct *p)
|
||||
{
|
||||
struct task_struct *lp = current, *rp;
|
||||
int i, lmax, rmax, lid, rid;
|
||||
event_channel_t *lchn, *rchn;
|
||||
shared_info_t *rsi;
|
||||
int max, port;
|
||||
event_channel_t *chn;
|
||||
|
||||
max = p->max_event_channel;
|
||||
chn = p->event_channel;
|
||||
|
||||
for ( port = 0; port < max; port++ )
|
||||
if ( chn[port].state == ECS_FREE )
|
||||
break;
|
||||
|
||||
if ( port == max )
|
||||
{
|
||||
if ( max == MAX_EVENT_CHANNELS )
|
||||
return -ENOSPC;
|
||||
|
||||
max = (max == 0) ? 4 : (max * 2);
|
||||
|
||||
chn = kmalloc(max * sizeof(event_channel_t), GFP_KERNEL);
|
||||
if ( unlikely(chn == NULL) )
|
||||
return -ENOMEM;
|
||||
|
||||
memset(chn, 0, max * sizeof(event_channel_t));
|
||||
|
||||
if ( p->event_channel != NULL )
|
||||
{
|
||||
memcpy(chn, p->event_channel, (max/2) * sizeof(event_channel_t));
|
||||
kfree(p->event_channel);
|
||||
}
|
||||
|
||||
p->event_channel = chn;
|
||||
p->max_event_channel = max;
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
static inline unsigned long set_event_pending(struct task_struct *p, int port)
|
||||
{
|
||||
if ( !test_and_set_bit(port, &p->shared_info->event_channel_pend[0]) &&
|
||||
!test_and_set_bit(port>>5, &p->shared_info->event_channel_pend_sel) )
|
||||
return mark_guest_event(p, _EVENT_EVTCHN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned long set_event_disc(struct task_struct *p, int port)
|
||||
{
|
||||
if ( !test_and_set_bit(port, &p->shared_info->event_channel_disc[0]) &&
|
||||
!test_and_set_bit(port>>5, &p->shared_info->event_channel_disc_sel) )
|
||||
return mark_guest_event(p, _EVENT_EVTCHN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long event_channel_open(evtchn_open_t *open)
|
||||
{
|
||||
struct task_struct *lp, *rp;
|
||||
int lport = 0, rport = 0;
|
||||
unsigned long cpu_mask;
|
||||
domid_t ldom = open->local_dom, rdom = open->remote_dom;
|
||||
long rc = 0;
|
||||
|
||||
rp = find_domain_by_id(target_dom);
|
||||
if ( !IS_PRIV(current) )
|
||||
return -EPERM;
|
||||
|
||||
/*
|
||||
* We need locks at both ends to make a connection. We avoid deadlock
|
||||
* by acquiring the locks in address order.
|
||||
*/
|
||||
if ( (unsigned long)lp < (unsigned long)rp )
|
||||
/* 'local_dom' may be DOMID_SELF. 'remote_dom' cannot be.*/
|
||||
if ( ldom == DOMID_SELF )
|
||||
ldom = current->domain;
|
||||
|
||||
/* Event channel must connect distinct domains. */
|
||||
if ( ldom == rdom )
|
||||
return -EINVAL;
|
||||
|
||||
if ( ((lp = find_domain_by_id(ldom)) == NULL) ||
|
||||
((rp = find_domain_by_id(rdom)) == NULL) )
|
||||
{
|
||||
if ( lp != NULL )
|
||||
put_task_struct(lp);
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
/* Avoid deadlock by first acquiring lock of domain with smaller id. */
|
||||
if ( ldom < rdom )
|
||||
{
|
||||
spin_lock(&lp->event_channel_lock);
|
||||
spin_lock(&rp->event_channel_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( likely(rp != NULL) )
|
||||
spin_lock(&rp->event_channel_lock);
|
||||
spin_lock(&rp->event_channel_lock);
|
||||
spin_lock(&lp->event_channel_lock);
|
||||
}
|
||||
|
||||
lmax = lp->max_event_channel;
|
||||
lchn = lp->event_channel;
|
||||
lid = -1;
|
||||
|
||||
/*
|
||||
* Find the first unused event channel. Also ensure bo channel already
|
||||
* exists to the specified target domain.
|
||||
*/
|
||||
for ( i = 0; i < lmax; i++ )
|
||||
if ( (lport = get_free_port(lp)) < 0 )
|
||||
{
|
||||
if ( (lid == -1) && !(lchn[i].flags & ECF_INUSE) )
|
||||
{
|
||||
lid = i;
|
||||
}
|
||||
else if ( unlikely(lchn[i].target_dom == target_dom) )
|
||||
{
|
||||
rc = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* If there is no free slot we need to allocate a bigger channel list. */
|
||||
if ( unlikely(lid == -1) )
|
||||
{
|
||||
/* Reached maximum channel count? */
|
||||
if ( unlikely(lmax == MAX_EVENT_CHANNELS) )
|
||||
{
|
||||
rc = -ENOSPC;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lmax = (lmax == 0) ? 4 : (lmax * 2);
|
||||
|
||||
lchn = kmalloc(lmax * sizeof(event_channel_t), GFP_KERNEL);
|
||||
if ( unlikely(lchn == NULL) )
|
||||
{
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memset(lchn, 0, lmax * sizeof(event_channel_t));
|
||||
|
||||
if ( likely(lp->event_channel != NULL) )
|
||||
kfree(lp->event_channel);
|
||||
|
||||
lp->event_channel = lchn;
|
||||
lp->max_event_channel = lmax;
|
||||
rc = lport;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lchn[lid].target_dom = target_dom;
|
||||
lchn[lid].flags = ECF_INUSE;
|
||||
|
||||
if ( likely(rp != NULL) )
|
||||
if ( (rport = get_free_port(rp)) < 0 )
|
||||
{
|
||||
rchn = rp->event_channel;
|
||||
rmax = rp->max_event_channel;
|
||||
|
||||
for ( rid = 0; rid < rmax; rid++ )
|
||||
{
|
||||
if ( (rchn[rid].target_dom == lp->domain) &&
|
||||
(rchn[rid].flags & ECF_INUSE) )
|
||||
{
|
||||
/*
|
||||
* The target was awaiting a connection. We make the connection
|
||||
* and send a connection-made event to the remote end.
|
||||
*/
|
||||
rchn[rid].flags = ECF_INUSE | ECF_CONNECTED | lid;
|
||||
lchn[lid].flags = ECF_INUSE | ECF_CONNECTED | rid;
|
||||
|
||||
rsi = rp->shared_info;
|
||||
if ( !test_and_set_bit(rid, &rsi->event_channel_pend[0]) &&
|
||||
!test_and_set_bit(rid>>5, &rsi->event_channel_pend_sel) )
|
||||
{
|
||||
cpu_mask = mark_guest_event(rp, _EVENT_EVTCHN);
|
||||
guest_event_notify(cpu_mask);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
rc = rport;
|
||||
goto out;
|
||||
}
|
||||
|
||||
lp->event_channel[lport].remote_dom = rp;
|
||||
lp->event_channel[lport].remote_port = (u16)rport;
|
||||
lp->event_channel[lport].state = ECS_CONNECTED;
|
||||
|
||||
rp->event_channel[rport].remote_dom = lp;
|
||||
rp->event_channel[rport].remote_port = (u16)lport;
|
||||
rp->event_channel[rport].state = ECS_CONNECTED;
|
||||
|
||||
cpu_mask = set_event_pending(lp, lport);
|
||||
cpu_mask |= set_event_pending(rp, rport);
|
||||
guest_event_notify(cpu_mask);
|
||||
|
||||
out:
|
||||
spin_unlock(&lp->event_channel_lock);
|
||||
if ( rp != NULL )
|
||||
{
|
||||
spin_unlock(&rp->event_channel_lock);
|
||||
put_task_struct(rp);
|
||||
}
|
||||
spin_unlock(&rp->event_channel_lock);
|
||||
|
||||
put_task_struct(lp);
|
||||
put_task_struct(rp);
|
||||
|
||||
open->local_port = lport;
|
||||
open->remote_port = rport;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static long event_channel_close(u16 lid)
|
||||
static long __event_channel_close(struct task_struct *lp, int lport)
|
||||
{
|
||||
struct task_struct *lp = current, *rp = NULL;
|
||||
struct task_struct *rp = NULL;
|
||||
event_channel_t *lchn, *rchn;
|
||||
u16 rid;
|
||||
shared_info_t *rsi;
|
||||
int rport;
|
||||
unsigned long cpu_mask;
|
||||
long rc = 0;
|
||||
|
||||
@@ -159,21 +171,21 @@ static long event_channel_close(u16 lid)
|
||||
|
||||
lchn = lp->event_channel;
|
||||
|
||||
if ( unlikely(lid >= lp->max_event_channel) ||
|
||||
unlikely(!(lchn[lid].flags & ECF_INUSE)) )
|
||||
if ( (lport < 0) || (lport >= lp->max_event_channel) ||
|
||||
(lchn[lport].state == ECS_FREE) )
|
||||
{
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ( lchn[lid].flags & ECF_CONNECTED )
|
||||
if ( lchn[lport].state == ECS_CONNECTED )
|
||||
{
|
||||
if ( rp == NULL )
|
||||
{
|
||||
rp = find_domain_by_id(lchn[lid].target_dom);
|
||||
ASSERT(rp != NULL);
|
||||
|
||||
if ( (unsigned long)lp < (unsigned long)rp )
|
||||
rp = lchn[lport].remote_dom;
|
||||
get_task_struct(rp);
|
||||
|
||||
if ( lp->domain < rp->domain )
|
||||
{
|
||||
spin_lock(&rp->event_channel_lock);
|
||||
}
|
||||
@@ -184,34 +196,39 @@ static long event_channel_close(u16 lid)
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
else if ( rp->domain != lchn[lid].target_dom )
|
||||
else if ( rp != lchn[lport].remote_dom )
|
||||
{
|
||||
rc = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rchn = rp->event_channel;
|
||||
rid = lchn[lid].flags & ECF_TARGET_ID;
|
||||
ASSERT(rid < rp->max_event_channel);
|
||||
ASSERT(rchn[rid].flags == (ECF_INUSE | ECF_CONNECTED | lid));
|
||||
ASSERT(rchn[rid].target_dom == lp->domain);
|
||||
rchn = rp->event_channel;
|
||||
rport = lchn[lport].remote_port;
|
||||
|
||||
rchn[rid].flags = ECF_INUSE;
|
||||
if ( rport >= rp->max_event_channel )
|
||||
BUG();
|
||||
if ( rchn[rport].state != ECS_CONNECTED )
|
||||
BUG();
|
||||
if ( rchn[rport].remote_dom != lp )
|
||||
BUG();
|
||||
|
||||
rsi = rp->shared_info;
|
||||
if ( !test_and_set_bit(rid, &rsi->event_channel_disc[0]) &&
|
||||
!test_and_set_bit(rid>>5, &rsi->event_channel_disc_sel) )
|
||||
{
|
||||
cpu_mask = mark_guest_event(rp, _EVENT_EVTCHN);
|
||||
guest_event_notify(cpu_mask);
|
||||
}
|
||||
rchn[rport].state = ECS_ZOMBIE;
|
||||
rchn[rport].remote_dom = NULL;
|
||||
rchn[rport].remote_port = 0xFFFF;
|
||||
|
||||
cpu_mask = set_event_disc(lp, lport);
|
||||
cpu_mask |= set_event_disc(rp, rport);
|
||||
guest_event_notify(cpu_mask);
|
||||
}
|
||||
|
||||
lchn[lid].target_dom = 0;
|
||||
lchn[lid].flags = 0;
|
||||
lchn[lport].state = ECS_FREE;
|
||||
lchn[lport].remote_dom = NULL;
|
||||
lchn[lport].remote_port = 0xFFFF;
|
||||
|
||||
out:
|
||||
spin_unlock(&lp->event_channel_lock);
|
||||
put_task_struct(lp);
|
||||
|
||||
if ( rp != NULL )
|
||||
{
|
||||
spin_unlock(&rp->event_channel_lock);
|
||||
@@ -222,87 +239,135 @@ static long event_channel_close(u16 lid)
|
||||
}
|
||||
|
||||
|
||||
static long event_channel_send(u16 lid)
|
||||
static long event_channel_close(evtchn_close_t *close)
|
||||
{
|
||||
struct task_struct *lp;
|
||||
int lport = close->local_port;
|
||||
long rc;
|
||||
domid_t ldom = close->local_dom;
|
||||
|
||||
if ( ldom == DOMID_SELF )
|
||||
ldom = current->domain;
|
||||
else if ( !IS_PRIV(current) )
|
||||
return -EPERM;
|
||||
|
||||
if ( (lp = find_domain_by_id(ldom)) == NULL )
|
||||
return -ESRCH;
|
||||
|
||||
rc = __event_channel_close(lp, lport);
|
||||
|
||||
put_task_struct(lp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static long event_channel_send(int lport)
|
||||
{
|
||||
struct task_struct *lp = current, *rp;
|
||||
u16 rid, rdom;
|
||||
shared_info_t *rsi;
|
||||
int rport;
|
||||
unsigned long cpu_mask;
|
||||
|
||||
spin_lock(&lp->event_channel_lock);
|
||||
|
||||
if ( unlikely(lid >= lp->max_event_channel) ||
|
||||
unlikely(!(lp->event_channel[lid].flags & ECF_CONNECTED)) )
|
||||
if ( unlikely(lport < 0) ||
|
||||
unlikely(lport >= lp->max_event_channel) ||
|
||||
unlikely(lp->event_channel[lport].state != ECS_CONNECTED) )
|
||||
{
|
||||
spin_unlock(&lp->event_channel_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rdom = lp->event_channel[lid].target_dom;
|
||||
rid = lp->event_channel[lid].flags & ECF_TARGET_ID;
|
||||
rp = lp->event_channel[lport].remote_dom;
|
||||
rport = lp->event_channel[lport].remote_port;
|
||||
|
||||
get_task_struct(rp);
|
||||
|
||||
spin_unlock(&lp->event_channel_lock);
|
||||
|
||||
if ( unlikely(rid >= MAX_EVENT_CHANNELS) ||
|
||||
unlikely ((rp = find_domain_by_id(rdom)) == NULL) )
|
||||
return -EINVAL;
|
||||
|
||||
rsi = rp->shared_info;
|
||||
if ( !test_and_set_bit(rid, &rsi->event_channel_pend[0]) &&
|
||||
!test_and_set_bit(rid>>5, &rsi->event_channel_pend_sel) )
|
||||
{
|
||||
cpu_mask = mark_guest_event(rp, _EVENT_EVTCHN);
|
||||
guest_event_notify(cpu_mask);
|
||||
}
|
||||
cpu_mask = set_event_pending(rp, rport);
|
||||
guest_event_notify(cpu_mask);
|
||||
|
||||
put_task_struct(rp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static long event_channel_status(u16 lid)
|
||||
static long event_channel_status(evtchn_status_t *status)
|
||||
{
|
||||
struct task_struct *lp = current;
|
||||
struct task_struct *lp;
|
||||
domid_t ldom = status->local_dom;
|
||||
int lport = status->local_port;
|
||||
event_channel_t *lchn;
|
||||
long rc = EVTCHNSTAT_closed;
|
||||
|
||||
if ( ldom == DOMID_SELF )
|
||||
ldom = current->domain;
|
||||
else if ( !IS_PRIV(current) )
|
||||
return -EPERM;
|
||||
|
||||
if ( (lp = find_domain_by_id(ldom)) == NULL )
|
||||
return -ESRCH;
|
||||
|
||||
spin_lock(&lp->event_channel_lock);
|
||||
|
||||
lchn = lp->event_channel;
|
||||
|
||||
if ( lid < lp->max_event_channel )
|
||||
if ( (lport < 0) || (lport >= lp->max_event_channel) )
|
||||
{
|
||||
if ( lchn[lid].flags & ECF_CONNECTED )
|
||||
rc = EVTCHNSTAT_connected;
|
||||
else if ( lchn[lid].flags & ECF_INUSE )
|
||||
rc = EVTCHNSTAT_disconnected;
|
||||
spin_unlock(&lp->event_channel_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch ( lchn[lport].state )
|
||||
{
|
||||
case ECS_FREE:
|
||||
status->status = EVTCHNSTAT_closed;
|
||||
break;
|
||||
case ECS_ZOMBIE:
|
||||
status->status = EVTCHNSTAT_disconnected;
|
||||
break;
|
||||
case ECS_CONNECTED:
|
||||
status->status = EVTCHNSTAT_connected;
|
||||
status->remote_dom = lchn[lport].remote_dom->domain;
|
||||
status->remote_port = lchn[lport].remote_port;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
spin_unlock(&lp->event_channel_lock);
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long do_event_channel_op(unsigned int cmd, unsigned int id)
|
||||
long do_event_channel_op(evtchn_op_t *uop)
|
||||
{
|
||||
long rc;
|
||||
evtchn_op_t op;
|
||||
|
||||
switch ( cmd )
|
||||
if ( copy_from_user(&op, uop, sizeof(op)) != 0 )
|
||||
return -EFAULT;
|
||||
|
||||
switch ( op.cmd )
|
||||
{
|
||||
case EVTCHNOP_open:
|
||||
rc = event_channel_open((u16)id);
|
||||
rc = event_channel_open(&op.u.open);
|
||||
if ( copy_to_user(uop, &op, sizeof(op)) != 0 )
|
||||
rc = -EFAULT; /* Cleaning up here would be a mess! */
|
||||
break;
|
||||
|
||||
case EVTCHNOP_close:
|
||||
rc = event_channel_close((u16)id);
|
||||
rc = event_channel_close(&op.u.close);
|
||||
break;
|
||||
|
||||
case EVTCHNOP_send:
|
||||
rc = event_channel_send((u16)id);
|
||||
rc = event_channel_send(op.u.send.local_port);
|
||||
break;
|
||||
|
||||
case EVTCHNOP_status:
|
||||
rc = event_channel_status((u16)id);
|
||||
rc = event_channel_status(&op.u.status);
|
||||
if ( copy_to_user(uop, &op, sizeof(op)) != 0 )
|
||||
rc = -EFAULT;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -320,7 +385,7 @@ void destroy_event_channels(struct task_struct *p)
|
||||
if ( p->event_channel != NULL )
|
||||
{
|
||||
for ( i = 0; i < p->max_event_channel; i++ )
|
||||
(void)event_channel_close((u16)i);
|
||||
(void)__event_channel_close(p, i);
|
||||
kfree(p->event_channel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/******************************************************************************
|
||||
* event_channel.h
|
||||
*
|
||||
* Event channels between domains.
|
||||
*
|
||||
* Copyright (c) 2003-2004, K A Fraser.
|
||||
*/
|
||||
|
||||
#ifndef __HYPERVISOR_IFS__EVENT_CHANNEL_H__
|
||||
#define __HYPERVISOR_IFS__EVENT_CHANNEL_H__
|
||||
|
||||
/*
|
||||
* EVTCHNOP_open: Open a communication channel between <local_dom> and
|
||||
* <remote_dom>.
|
||||
* NOTES:
|
||||
* 1. <local_dom> may be specified as DOMID_SELF.
|
||||
* 2. Only a sufficiently-privileged domain may create an event channel.
|
||||
* 3. <local_port> and <remote_port> are only supplied if the op succeeds.
|
||||
*/
|
||||
#define EVTCHNOP_open 0
|
||||
typedef struct evtchn_open
|
||||
{
|
||||
/* IN parameters. */
|
||||
domid_t local_dom, remote_dom;
|
||||
/* OUT parameters. */
|
||||
int local_port, remote_port;
|
||||
} evtchn_open_t;
|
||||
|
||||
/*
|
||||
* EVTCHNOP_close: Close the communication channel which has an endpoint at
|
||||
* <local_dom, local_port>.
|
||||
* NOTES:
|
||||
* 1. <local_dom> may be specified as DOMID_SELF.
|
||||
* 2. Only a sufficiently-privileged domain may close an event channel
|
||||
* for which <local_dom> is not DOMID_SELF.
|
||||
*/
|
||||
#define EVTCHNOP_close 1
|
||||
typedef struct evtchn_close
|
||||
{
|
||||
/* IN parameters. */
|
||||
domid_t local_dom;
|
||||
int local_port;
|
||||
/* No OUT parameters. */
|
||||
} evtchn_close_t;
|
||||
|
||||
/*
|
||||
* EVTCHNOP_send: Send an event to the remote end of the channel whose local
|
||||
* endpoint is <DOMID_SELF, local_port>.
|
||||
*/
|
||||
#define EVTCHNOP_send 2
|
||||
typedef struct evtchn_send
|
||||
{
|
||||
/* IN parameters. */
|
||||
int local_port;
|
||||
/* No OUT parameters. */
|
||||
} evtchn_send_t;
|
||||
|
||||
/*
|
||||
* EVTCHNOP_status: Get the current status of the communication channel which
|
||||
* has an endpoint at <local_dom, local_port>.
|
||||
* NOTES:
|
||||
* 1. <local_dom> may be specified as DOMID_SELF.
|
||||
* 2. Only a sufficiently-privileged domain may obtain the status of an event
|
||||
* channel for which <local_dom> is not DOMID_SELF.
|
||||
* 3. <remote_dom, remote_port> is only supplied if status is 'connected'.
|
||||
*/
|
||||
#define EVTCHNOP_status 3 /* Get status of <channel id>. */
|
||||
typedef struct evtchn_status
|
||||
{
|
||||
/* IN parameters */
|
||||
domid_t local_dom;
|
||||
int local_port;
|
||||
/* OUT parameters */
|
||||
domid_t remote_dom;
|
||||
int remote_port;
|
||||
#define EVTCHNSTAT_closed 0 /* Chennel is not in use. */
|
||||
#define EVTCHNSTAT_disconnected 1 /* Channel is not connected to remote. */
|
||||
#define EVTCHNSTAT_connected 2 /* Channel is connected to remote. */
|
||||
int status;
|
||||
} evtchn_status_t;
|
||||
|
||||
typedef struct evtchn_op
|
||||
{
|
||||
int cmd; /* EVTCHNOP_* */
|
||||
union {
|
||||
evtchn_open_t open;
|
||||
evtchn_close_t close;
|
||||
evtchn_send_t send;
|
||||
evtchn_status_t status;
|
||||
} u;
|
||||
} evtchn_op_t;
|
||||
|
||||
#endif /* __HYPERVISOR_IFS__EVENT_CHANNEL_H__ */
|
||||
@@ -168,21 +168,6 @@
|
||||
#define SCHEDOP_exit 3 /* Exit and kill this domain. */
|
||||
#define SCHEDOP_stop 4 /* Stop executing this domain. */
|
||||
|
||||
/*
|
||||
* EVTCHNOP_* - Event channel operations.
|
||||
*/
|
||||
#define EVTCHNOP_open 0 /* Open channel to <target domain>. */
|
||||
#define EVTCHNOP_close 1 /* Close <channel id>. */
|
||||
#define EVTCHNOP_send 2 /* Send event on <channel id>. */
|
||||
#define EVTCHNOP_status 3 /* Get status of <channel id>. */
|
||||
|
||||
/*
|
||||
* EVTCHNSTAT_* - Non-error return values from EVTCHNOP_status.
|
||||
*/
|
||||
#define EVTCHNSTAT_closed 0 /* Chennel is not in use. */
|
||||
#define EVTCHNSTAT_disconnected 1 /* Channel is not connected to remote. */
|
||||
#define EVTCHNSTAT_connected 2 /* Channel is connected to remote. */
|
||||
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
|
||||
@@ -45,13 +45,16 @@ extern struct mm_struct init_mm;
|
||||
|
||||
#define IS_PRIV(_p) (test_bit(PF_PRIVILEGED, &(_p)->flags))
|
||||
|
||||
struct task_struct;
|
||||
|
||||
typedef struct event_channel_st
|
||||
{
|
||||
u16 target_dom; /* Target domain (i.e. domain at remote end). */
|
||||
#define ECF_TARGET_ID ((1<<10)-1) /* Channel identifier at remote end. */
|
||||
#define ECF_INUSE (1<<10) /* Is this channel descriptor in use? */
|
||||
#define ECF_CONNECTED (1<<11) /* Is this channel connected to remote? */
|
||||
u16 flags;
|
||||
struct task_struct *remote_dom;
|
||||
u16 remote_port;
|
||||
#define ECS_FREE 0 /* Available for use. */
|
||||
#define ECS_ZOMBIE 1 /* Connection is closed. Remote is disconnected. */
|
||||
#define ECS_CONNECTED 2 /* Connected to remote end. */
|
||||
u16 state;
|
||||
} event_channel_t;
|
||||
|
||||
struct task_struct
|
||||
|
||||