aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-12-31 14:15:22 +0100
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-12-31 14:15:22 +0100
commit7e127cd35f6fd48eff4b9f8958eef8fac2b846aa (patch)
treed987ff8463d4e7d308925d8fa34c478f22865bd0
parenta8f5fb85087a4ebb9319fe6687eb60f29acbdb35 (diff)
downloadxen-7e127cd35f6fd48eff4b9f8958eef8fac2b846aa.tar.gz
xen-7e127cd35f6fd48eff4b9f8958eef8fac2b846aa.tar.bz2
xen-7e127cd35f6fd48eff4b9f8958eef8fac2b846aa.zip
Allow non-privileged domains restricted access to
I/O memory and physical interrupts, under control of domain0. Capabilities are maintained as rangesets in Xen. Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil> Signed-off-by: Keir Fraser <keir@xensource.com>
-rw-r--r--tools/libxc/xc_domain.c32
-rw-r--r--tools/libxc/xenctrl.h11
-rw-r--r--tools/python/xen/lowlevel/xc/xc.c65
-rw-r--r--xen/arch/ia64/xen/domain.c5
-rw-r--r--xen/arch/ia64/xen/irq.c3
-rw-r--r--xen/arch/x86/dom0_ops.c14
-rw-r--r--xen/arch/x86/domain_build.c22
-rw-r--r--xen/arch/x86/irq.c4
-rw-r--r--xen/arch/x86/mm.c7
-rw-r--r--xen/arch/x86/physdev.c7
-rw-r--r--xen/arch/x86/traps.c4
-rw-r--r--xen/common/dom0_ops.c49
-rw-r--r--xen/common/domain.c7
-rw-r--r--xen/common/event_channel.c4
-rw-r--r--xen/common/memory.c4
-rw-r--r--xen/common/rangeset.c6
-rw-r--r--xen/drivers/char/ns16550.c3
-rw-r--r--xen/include/asm-x86/iocap.h9
-rw-r--r--xen/include/public/dom0_ops.h17
-rw-r--r--xen/include/xen/compiler.h6
-rw-r--r--xen/include/xen/iocap.h21
-rw-r--r--xen/include/xen/rangeset.h15
-rw-r--r--xen/include/xen/sched.h20
23 files changed, 276 insertions, 59 deletions
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index fe3cf55618..b018318d62 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -404,6 +404,38 @@ int xc_domain_setinfo(int xc_handle,
}
+int xc_domain_irq_permission(int xc_handle,
+ uint32_t domid,
+ uint8_t pirq,
+ uint8_t allow_access)
+{
+ dom0_op_t op;
+
+ op.cmd = DOM0_IRQ_PERMISSION;
+ op.u.irq_permission.domain = domid;
+ op.u.irq_permission.pirq = pirq;
+ op.u.irq_permission.allow_access = allow_access;
+
+ return do_dom0_op(xc_handle, &op);
+}
+
+int xc_domain_iomem_permission(int xc_handle,
+ uint32_t domid,
+ unsigned long first_pfn,
+ unsigned long nr_pfns,
+ uint8_t allow_access)
+{
+ dom0_op_t op;
+
+ op.cmd = DOM0_IOMEM_PERMISSION;
+ op.u.iomem_permission.domain = domid;
+ op.u.iomem_permission.first_pfn = first_pfn;
+ op.u.iomem_permission.nr_pfns = nr_pfns;
+ op.u.iomem_permission.allow_access = allow_access;
+
+ return do_dom0_op(xc_handle, &op);
+}
+
/*
* Local variables:
* mode: C
diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
index 6700bd1c0d..f558b5985e 100644
--- a/tools/libxc/xenctrl.h
+++ b/tools/libxc/xenctrl.h
@@ -380,6 +380,17 @@ int xc_domain_ioport_permission(int xc_handle,
uint32_t nr_ports,
uint32_t allow_access);
+int xc_domain_irq_permission(int xc_handle,
+ uint32_t domid,
+ uint8_t pirq,
+ uint8_t allow_access);
+
+int xc_domain_iomem_permission(int xc_handle,
+ uint32_t domid,
+ unsigned long first_pfn,
+ unsigned long nr_pfns,
+ uint8_t allow_access);
+
unsigned long xc_make_page_below_4G(int xc_handle, uint32_t domid,
unsigned long mfn);
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index 95b0a9f101..30f0ef6d81 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -774,6 +774,52 @@ static PyObject *pyxc_domain_ioport_permission(XcObject *self,
return zero;
}
+static PyObject *pyxc_domain_irq_permission(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ uint32_t dom;
+ int pirq, allow_access, ret;
+
+ static char *kwd_list[] = { "dom", "pirq", "allow_access", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iii", kwd_list,
+ &dom, &pirq, &allow_access) )
+ return NULL;
+
+ ret = xc_domain_irq_permission(
+ xc->xc_handle, dom, pirq, allow_access);
+ if ( ret != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
+static PyObject *pyxc_domain_iomem_permission(PyObject *self,
+ PyObject *args,
+ PyObject *kwds)
+{
+ XcObject *xc = (XcObject *)self;
+ uint32_t dom;
+ unsigned long first_pfn, nr_pfns, allow_access, ret;
+
+ static char *kwd_list[] = { "dom", "first_pfn", "nr_pfns", "allow_access", NULL };
+
+ if ( !PyArg_ParseTupleAndKeywords(args, kwds, "illi", kwd_list,
+ &dom, &first_pfn, &nr_pfns, &allow_access) )
+ return NULL;
+
+ ret = xc_domain_iomem_permission(
+ xc->xc_handle, dom, first_pfn, nr_pfns, allow_access);
+ if ( ret != 0 )
+ return PyErr_SetFromErrno(xc_error);
+
+ Py_INCREF(zero);
+ return zero;
+}
+
static PyObject *dom_op(XcObject *self, PyObject *args,
int (*fn)(int, uint32_t))
@@ -1070,6 +1116,25 @@ static PyMethodDef pyxc_methods[] = {
" allow_access [int]: Non-zero means enable access; else disable access\n\n"
"Returns: [int] 0 on success; -1 on error.\n" },
+ { "domain_irq_permission",
+ (PyCFunction)pyxc_domain_irq_permission,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Allow a domain access to a physical IRQ\n"
+ " dom [int]: Identifier of domain to be allowed access.\n"
+ " pirq [int]: The Physical IRQ\n"
+ " allow_access [int]: Non-zero means enable access; else disable access\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
+ { "domain_iomem_permission",
+ (PyCFunction)pyxc_domain_iomem_permission,
+ METH_VARARGS | METH_KEYWORDS, "\n"
+ "Allow a domain access to a range of IO memory pages\n"
+ " dom [int]: Identifier of domain to be allowed access.\n"
+ " first_pfn [long]: First page of I/O Memory\n"
+ " nr_pfns [long]: Number of pages of I/O Memory (>0)\n"
+ " allow_access [int]: Non-zero means enable access; else disable access\n\n"
+ "Returns: [int] 0 on success; -1 on error.\n" },
+
{ "pages_to_kib",
(PyCFunction)pyxc_pages_to_kib,
METH_VARARGS, "\n"
diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c
index 5b68519bbe..b784372cd8 100644
--- a/xen/arch/ia64/xen/domain.c
+++ b/xen/arch/ia64/xen/domain.c
@@ -765,7 +765,10 @@ void alloc_dom0(void)
*/
void physdev_init_dom0(struct domain *d)
{
- set_bit(_DOMF_physdev_access, &d->domain_flags);
+ if (iomem_permit_access(d, 0UL, ~0UL))
+ BUG();
+ if (irqs_permit_access(d, 0, NR_PIRQS-1))
+ BUG();
}
unsigned int vmx_dom0 = 0;
diff --git a/xen/arch/ia64/xen/irq.c b/xen/arch/ia64/xen/irq.c
index b694d62bc9..1537873e04 100644
--- a/xen/arch/ia64/xen/irq.c
+++ b/xen/arch/ia64/xen/irq.c
@@ -1378,9 +1378,6 @@ int pirq_guest_bind(struct vcpu *d, int irq, int will_share)
unsigned long flags;
int rc = 0;
- if ( !IS_CAPABLE_PHYSDEV(d->domain) )
- return -EPERM;
-
spin_lock_irqsave(&desc->lock, flags);
action = (irq_guest_action_t *)desc->action;
diff --git a/xen/arch/x86/dom0_ops.c b/xen/arch/x86/dom0_ops.c
index 022fa33e35..5a4f493ce0 100644
--- a/xen/arch/x86/dom0_ops.c
+++ b/xen/arch/x86/dom0_ops.c
@@ -152,14 +152,12 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op)
op->u.ioport_permission.domain)) == NULL) )
break;
- ret = 0;
- if ( np > 0 )
- {
- if ( op->u.ioport_permission.allow_access )
- ioport_range_permit(d, fp, fp + np - 1);
- else
- ioport_range_deny(d, fp, fp + np - 1);
- }
+ if ( np == 0 )
+ ret = 0;
+ else if ( op->u.ioport_permission.allow_access )
+ ret = ioports_permit_access(d, fp, fp + np - 1);
+ else
+ ret = ioports_deny_access(d, fp, fp + np - 1);
put_domain(d);
}
diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c
index cdeb08265c..d08f2c12fb 100644
--- a/xen/arch/x86/domain_build.c
+++ b/xen/arch/x86/domain_build.c
@@ -94,7 +94,7 @@ static struct pfn_info *alloc_chunk(struct domain *d, unsigned long max_pages)
return page;
}
-static void process_dom0_ioports_disable()
+static void process_dom0_ioports_disable(void)
{
unsigned long io_from, io_to;
char *t, *u, *s = opt_dom0_ioports_disable;
@@ -126,7 +126,8 @@ static void process_dom0_ioports_disable()
printk("Disabling dom0 access to ioport range %04lx-%04lx\n",
io_from, io_to);
- ioport_range_deny(dom0, io_from, io_to);
+ if ( ioports_deny_access(dom0, io_from, io_to) != 0 )
+ BUG();
}
}
@@ -741,24 +742,29 @@ int construct_dom0(struct domain *d,
printk("dom0: shadow setup done\n");
}
+ i = 0;
+
/* DOM0 is permitted full I/O capabilities. */
- ioport_range_permit(dom0, 0, 0xFFFF);
- set_bit(_DOMF_physdev_access, &dom0->domain_flags);
+ i |= ioports_permit_access(dom0, 0, 0xFFFF);
+ i |= iomem_permit_access(dom0, 0UL, ~0UL);
+ i |= irqs_permit_access(dom0, 0, NR_PIRQS-1);
/*
* Modify I/O port access permissions.
*/
/* Master Interrupt Controller (PIC). */
- ioport_range_deny(dom0, 0x20, 0x21);
+ i |= ioports_deny_access(dom0, 0x20, 0x21);
/* Slave Interrupt Controller (PIC). */
- ioport_range_deny(dom0, 0xA0, 0xA1);
+ i |= ioports_deny_access(dom0, 0xA0, 0xA1);
/* Interval Timer (PIT). */
- ioport_range_deny(dom0, 0x40, 0x43);
+ i |= ioports_deny_access(dom0, 0x40, 0x43);
/* PIT Channel 2 / PC Speaker Control. */
- ioport_range_deny(dom0, 0x61, 0x61);
+ i |= ioports_deny_access(dom0, 0x61, 0x61);
/* Command-line I/O ranges. */
process_dom0_ioports_disable();
+ BUG_ON(i != 0);
+
return 0;
}
diff --git a/xen/arch/x86/irq.c b/xen/arch/x86/irq.c
index e0553486bc..a1aee360c3 100644
--- a/xen/arch/x86/irq.c
+++ b/xen/arch/x86/irq.c
@@ -199,16 +199,12 @@ int pirq_guest_unmask(struct domain *d)
int pirq_guest_bind(struct vcpu *v, int irq, int will_share)
{
unsigned int vector = irq_to_vector(irq);
- struct domain *d = v->domain;
irq_desc_t *desc = &irq_desc[vector];
irq_guest_action_t *action;
unsigned long flags;
int rc = 0;
cpumask_t cpumask = CPU_MASK_NONE;
- if ( !IS_CAPABLE_PHYSDEV(d) )
- return -EPERM;
-
if ( vector == 0 )
return -EBUSY;
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index e6a99065e3..683c4b7534 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -96,6 +96,7 @@
#include <xen/softirq.h>
#include <xen/domain_page.h>
#include <xen/event.h>
+#include <xen/iocap.h>
#include <asm/shadow.h>
#include <asm/page.h>
#include <asm/flushtlb.h>
@@ -437,7 +438,6 @@ get_page_from_l1e(
unsigned long mfn = l1e_get_pfn(l1e);
struct pfn_info *page = pfn_to_page(mfn);
int okay;
- extern int domain_iomem_in_pfn(struct domain *d, unsigned long pfn);
if ( !(l1e_get_flags(l1e) & _PAGE_PRESENT) )
return 1;
@@ -455,8 +455,7 @@ get_page_from_l1e(
if ( d == dom_io )
d = current->domain;
- if ( (!IS_PRIV(d)) &&
- (!IS_CAPABLE_PHYSDEV(d) || !domain_iomem_in_pfn(d, mfn)) )
+ if ( !iomem_access_permitted(d, mfn, mfn) )
{
MEM_LOG("Non-privileged attempt to map I/O space %08lx", mfn);
return 0;
@@ -1887,7 +1886,7 @@ int do_mmuext_op(
break;
case MMUEXT_FLUSH_CACHE:
- if ( unlikely(!IS_CAPABLE_PHYSDEV(d)) )
+ if ( unlikely(!cache_flush_permitted(d)) )
{
MEM_LOG("Non-physdev domain tried to FLUSH_CACHE.");
okay = 0;
diff --git a/xen/arch/x86/physdev.c b/xen/arch/x86/physdev.c
index 0e7c1c10c5..e8cb5b8707 100644
--- a/xen/arch/x86/physdev.c
+++ b/xen/arch/x86/physdev.c
@@ -14,13 +14,6 @@
extern int ioapic_guest_read(int apicid, int address, u32 *pval);
extern int ioapic_guest_write(int apicid, int address, u32 pval);
-/* Check if a domain controls a device with IO memory within frame @pfn.
- * Returns: 1 if the domain should be allowed to map @pfn, 0 otherwise. */
-int domain_iomem_in_pfn(struct domain *p, unsigned long pfn)
-{
- return 0;
-}
-
/*
* Demuxing hypercall.
*/
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index 8216452fd0..a4be3db3b3 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -623,7 +623,7 @@ static inline int admin_io_okay(
unsigned int port, unsigned int bytes,
struct vcpu *v, struct cpu_user_regs *regs)
{
- return ioport_range_access_permitted(v->domain, port, port + bytes - 1);
+ return ioports_access_permitted(v->domain, port, port + bytes - 1);
}
/* Check admin limits. Silently fail the access if it is disallowed. */
@@ -863,7 +863,7 @@ static int emulate_privileged_op(struct cpu_user_regs *regs)
case 0x09: /* WBINVD */
/* Ignore the instruction if unprivileged. */
- if ( !IS_CAPABLE_PHYSDEV(v->domain) )
+ if ( !cache_flush_permitted(v->domain) )
DPRINTK("Non-physdev domain attempted WBINVD.\n");
else
wbinvd();
diff --git a/xen/common/dom0_ops.c b/xen/common/dom0_ops.c
index a4cbc48b4f..97cd571376 100644
--- a/xen/common/dom0_ops.c
+++ b/xen/common/dom0_ops.c
@@ -16,6 +16,7 @@
#include <xen/domain_page.h>
#include <xen/trace.h>
#include <xen/console.h>
+#include <xen/iocap.h>
#include <asm/current.h>
#include <public/dom0_ops.h>
#include <public/sched_ctl.h>
@@ -582,6 +583,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
}
}
break;
+
case DOM0_SETDEBUGGING:
{
struct domain *d;
@@ -599,6 +601,53 @@ long do_dom0_op(dom0_op_t *u_dom0_op)
}
break;
+ case DOM0_IRQ_PERMISSION:
+ {
+ struct domain *d;
+ unsigned int pirq = op->u.irq_permission.pirq;
+
+ ret = -EINVAL;
+ if ( pirq >= NR_PIRQS )
+ break;
+
+ ret = -ESRCH;
+ d = find_domain_by_id(op->u.irq_permission.domain);
+ if ( d == NULL )
+ break;
+
+ if ( op->u.irq_permission.allow_access )
+ ret = irq_permit_access(d, pirq);
+ else
+ ret = irq_deny_access(d, pirq);
+
+ put_domain(d);
+ }
+ break;
+
+ case DOM0_IOMEM_PERMISSION:
+ {
+ struct domain *d;
+ unsigned long pfn = op->u.iomem_permission.first_pfn;
+ unsigned long nr_pfns = op->u.iomem_permission.nr_pfns;
+
+ ret = -EINVAL;
+ if ( (pfn + nr_pfns - 1) < pfn ) /* wrap? */
+ break;
+
+ ret = -ESRCH;
+ d = find_domain_by_id(op->u.iomem_permission.domain);
+ if ( d == NULL )
+ break;
+
+ if ( op->u.iomem_permission.allow_access )
+ ret = iomem_permit_access(d, pfn, pfn + nr_pfns - 1);
+ else
+ ret = iomem_deny_access(d, pfn, pfn + nr_pfns - 1);
+
+ put_domain(d);
+ }
+ break;
+
#ifdef PERF_COUNTERS
case DOM0_PERFCCONTROL:
{
diff --git a/xen/common/domain.c b/xen/common/domain.c
index 46f45950b2..0f206d8e1c 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -60,7 +60,12 @@ struct domain *do_createdomain(domid_t dom_id, unsigned int cpu)
rangeset_domain_initialise(d);
- if ( arch_do_createdomain(v) != 0 )
+ d->iomem_caps = rangeset_new(d, "I/O Memory", RANGESETF_prettyprint_hex);
+ d->irq_caps = rangeset_new(d, "Interrupts", 0);
+
+ if ( (d->iomem_caps == NULL) ||
+ (d->irq_caps == NULL) ||
+ (arch_do_createdomain(v) != 0) )
goto fail3;
if ( !is_idle_task(d) )
diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c
index eeccc0e160..fdda1e86b8 100644
--- a/xen/common/event_channel.c
+++ b/xen/common/event_channel.c
@@ -22,6 +22,7 @@
#include <xen/sched.h>
#include <xen/event.h>
#include <xen/irq.h>
+#include <xen/iocap.h>
#include <asm/current.h>
#include <public/xen.h>
@@ -242,6 +243,9 @@ static long evtchn_bind_pirq(evtchn_bind_pirq_t *bind)
if ( pirq >= ARRAY_SIZE(d->pirq_to_evtchn) )
return -EINVAL;
+ if ( !irq_access_permitted(d, pirq) )
+ return -EPERM;
+
spin_lock(&d->evtchn_lock);
if ( d->pirq_to_evtchn[pirq] != 0 )
diff --git a/xen/common/memory.c b/xen/common/memory.c
index 45934fdf76..847fcbb0cc 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -15,6 +15,7 @@
#include <xen/sched.h>
#include <xen/event.h>
#include <xen/shadow.h>
+#include <xen/iocap.h>
#include <asm/current.h>
#include <asm/hardirq.h>
#include <public/memory.h>
@@ -35,7 +36,8 @@ increase_reservation(
!array_access_ok(extent_list, nr_extents, sizeof(*extent_list)) )
return 0;
- if ( (extent_order != 0) && !IS_CAPABLE_PHYSDEV(current->domain) )
+ if ( (extent_order != 0) &&
+ !multipage_allocation_permitted(current->domain) )
{
DPRINTK("Only I/O-capable domains may allocate multi-page extents.\n");
return 0;
diff --git a/xen/common/rangeset.c b/xen/common/rangeset.c
index a1680a29f2..de17a90ec5 100644
--- a/xen/common/rangeset.c
+++ b/xen/common/rangeset.c
@@ -253,6 +253,12 @@ int rangeset_contains_singleton(
return rangeset_contains_range(r, s, s);
}
+int rangeset_is_empty(
+ struct rangeset *r)
+{
+ return list_empty(&r->range_list);
+}
+
struct rangeset *rangeset_new(
struct domain *d, char *name, unsigned int flags)
{
diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
index 6784983b3b..8ef838d3db 100644
--- a/xen/drivers/char/ns16550.c
+++ b/xen/drivers/char/ns16550.c
@@ -237,7 +237,8 @@ static void ns16550_init_postirq(struct serial_port *port)
static void ns16550_endboot(struct serial_port *port)
{
struct ns16550 *uart = port->uart;
- ioport_range_deny(dom0, uart->io_base, uart->io_base + 7);
+ if ( ioports_deny_access(dom0, uart->io_base, uart->io_base + 7) != 0 )
+ BUG();
}
#else
#define ns16550_endboot NULL
diff --git a/xen/include/asm-x86/iocap.h b/xen/include/asm-x86/iocap.h
index e60b82ff3a..c7463cb6f2 100644
--- a/xen/include/asm-x86/iocap.h
+++ b/xen/include/asm-x86/iocap.h
@@ -7,11 +7,14 @@
#ifndef __X86_IOCAP_H__
#define __X86_IOCAP_H__
-#define ioport_range_permit(d, s, e) \
+#define ioports_permit_access(d, s, e) \
rangeset_add_range((d)->arch.ioport_caps, s, e)
-#define ioport_range_deny(d, s, e) \
+#define ioports_deny_access(d, s, e) \
rangeset_remove_range((d)->arch.ioport_caps, s, e)
-#define ioport_range_access_permitted(d, s, e) \
+#define ioports_access_permitted(d, s, e) \
rangeset_contains_range((d)->arch.ioport_caps, s, e)
+#define cache_flush_permitted(d) \
+ (!rangeset_is_empty((d)->iomem_caps))
+
#endif /* __X86_IOCAP_H__ */
diff --git a/xen/include/public/dom0_ops.h b/xen/include/public/dom0_ops.h
index b6b5914200..a2c66be1f4 100644
--- a/xen/include/public/dom0_ops.h
+++ b/xen/include/public/dom0_ops.h
@@ -410,6 +410,21 @@ typedef struct {
uint8_t enable;
} dom0_setdebugging_t;
+#define DOM0_IRQ_PERMISSION 46
+typedef struct {
+ domid_t domain; /* domain to be affected */
+ uint8_t pirq;
+ uint8_t allow_access; /* flag to specify enable/disable of IRQ access */
+} dom0_irq_permission_t;
+
+#define DOM0_IOMEM_PERMISSION 47
+typedef struct {
+ domid_t domain; /* domain to be affected */
+ unsigned long first_pfn; /* first page (physical page number) in range */
+ unsigned long nr_pfns; /* number of pages in range (>0) */
+ uint8_t allow_access; /* allow (!0) or deny (0) access to range? */
+} dom0_iomem_permission_t;
+
typedef struct {
uint32_t cmd;
uint32_t interface_version; /* DOM0_INTERFACE_VERSION */
@@ -448,6 +463,8 @@ typedef struct {
dom0_max_vcpus_t max_vcpus;
dom0_setdomainhandle_t setdomainhandle;
dom0_setdebugging_t setdebugging;
+ dom0_irq_permission_t irq_permission;
+ dom0_iomem_permission_t iomem_permission;
uint8_t pad[128];
} u;
} dom0_op_t;
diff --git a/xen/include/xen/compiler.h b/xen/include/xen/compiler.h
index f0c5fbf17a..29acdc59e8 100644
--- a/xen/include/xen/compiler.h
+++ b/xen/include/xen/compiler.h
@@ -19,4 +19,10 @@
#define __attribute_used__ __attribute__((__unused__))
#endif
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define __must_check __attribute__((warn_unused_result))
+#else
+#define __must_check
+#endif
+
#endif /* __LINUX_COMPILER_H */
diff --git a/xen/include/xen/iocap.h b/xen/include/xen/iocap.h
index 967f70fe4b..db461b9dcb 100644
--- a/xen/include/xen/iocap.h
+++ b/xen/include/xen/iocap.h
@@ -10,4 +10,25 @@
#include <xen/rangeset.h>
#include <asm/iocap.h>
+#define iomem_permit_access(d, s, e) \
+ rangeset_add_range((d)->iomem_caps, s, e)
+#define iomem_deny_access(d, s, e) \
+ rangeset_remove_range((d)->iomem_caps, s, e)
+#define iomem_access_permitted(d, s, e) \
+ rangeset_contains_range((d)->iomem_caps, s, e)
+
+#define irq_permit_access(d, i) \
+ rangeset_add_singleton((d)->irq_caps, i)
+#define irq_deny_access(d, i) \
+ rangeset_remove_singleton((d)->irq_caps, i)
+#define irqs_permit_access(d, s, e) \
+ rangeset_add_range((d)->irq_caps, s, e)
+#define irqs_deny_access(d, s, e) \
+ rangeset_remove_range((d)->irq_caps, s, e)
+#define irq_access_permitted(d, i) \
+ rangeset_contains_singleton((d)->irq_caps, i)
+
+#define multipage_allocation_permitted(d) \
+ (!rangeset_is_empty((d)->iomem_caps))
+
#endif /* __XEN_IOCAP_H__ */
diff --git a/xen/include/xen/rangeset.h b/xen/include/xen/rangeset.h
index ffd14ad17d..d4a8e00393 100644
--- a/xen/include/xen/rangeset.h
+++ b/xen/include/xen/rangeset.h
@@ -43,20 +43,23 @@ void rangeset_destroy(
#define _RANGESETF_prettyprint_hex 0
#define RANGESETF_prettyprint_hex (1U << _RANGESETF_prettyprint_hex)
+int __must_check rangeset_is_empty(
+ struct rangeset *r);
+
/* Add/remove/query a numeric range. */
-int rangeset_add_range(
+int __must_check rangeset_add_range(
struct rangeset *r, unsigned long s, unsigned long e);
-int rangeset_remove_range(
+int __must_check rangeset_remove_range(
struct rangeset *r, unsigned long s, unsigned long e);
-int rangeset_contains_range(
+int __must_check rangeset_contains_range(
struct rangeset *r, unsigned long s, unsigned long e);
/* Add/remove/query a single number. */
-int rangeset_add_singleton(
+int __must_check rangeset_add_singleton(
struct rangeset *r, unsigned long s);
-int rangeset_remove_singleton(
+int __must_check rangeset_remove_singleton(
struct rangeset *r, unsigned long s);
-int rangeset_contains_singleton(
+int __must_check rangeset_contains_singleton(
struct rangeset *r, unsigned long s);
/* Rangeset pretty printing. */
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 4bc824741a..c686394b7f 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -11,6 +11,7 @@
#include <xen/time.h>
#include <xen/ac_timer.h>
#include <xen/grant_table.h>
+#include <xen/rangeset.h>
#include <asm/domain.h>
extern unsigned long volatile jiffies;
@@ -128,6 +129,10 @@ struct domain
u16 pirq_to_evtchn[NR_PIRQS];
u32 pirq_mask[NR_PIRQS/32];
+ /* I/O capabilities (access to IRQs and memory-mapped I/O). */
+ struct rangeset *iomem_caps;
+ struct rangeset *irq_caps;
+
unsigned long domain_flags;
unsigned long vm_assist;
@@ -381,23 +386,20 @@ extern struct domain *domain_list;
/* Is this domain privileged? */
#define _DOMF_privileged 1
#define DOMF_privileged (1UL<<_DOMF_privileged)
- /* May this domain do IO to physical devices? */
-#define _DOMF_physdev_access 2
-#define DOMF_physdev_access (1UL<<_DOMF_physdev_access)
/* Guest shut itself down for some reason. */
-#define _DOMF_shutdown 3
+#define _DOMF_shutdown 2
#define DOMF_shutdown (1UL<<_DOMF_shutdown)
/* Guest is in process of shutting itself down (becomes DOMF_shutdown). */
-#define _DOMF_shuttingdown 4
+#define _DOMF_shuttingdown 3
#define DOMF_shuttingdown (1UL<<_DOMF_shuttingdown)
/* Death rattle. */
-#define _DOMF_dying 5
+#define _DOMF_dying 4
#define DOMF_dying (1UL<<_DOMF_dying)
/* Domain is paused by controller software. */
-#define _DOMF_ctrl_pause 6
+#define _DOMF_ctrl_pause 5
#define DOMF_ctrl_pause (1UL<<_DOMF_ctrl_pause)
/* Domain is being debugged by controller software. */
-#define _DOMF_debugging 7
+#define _DOMF_debugging 6
#define DOMF_debugging (1UL<<_DOMF_debugging)
@@ -425,8 +427,6 @@ static inline void vcpu_unblock(struct vcpu *v)
#define IS_PRIV(_d) \
(test_bit(_DOMF_privileged, &(_d)->domain_flags))
-#define IS_CAPABLE_PHYSDEV(_d) \
- (test_bit(_DOMF_physdev_access, &(_d)->domain_flags))
#define VM_ASSIST(_d,_t) (test_bit((_t), &(_d)->vm_assist))