On Sun, Mar 26, 2006 at 11:08:09PM +0200, Muli Ben-Yehuda wrote:
> The following two patches, against the xen-unstable and linux-2.6-xen
> repositories, introduce proof-of-concept IOMMU support in Xen.
Signed-off-by: Muli Ben-Yehuda <mulix@xxxxxxxxx>
Signed-off-by: Jon Mason <jdmason@xxxxxxxxxx>
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/arch/x86/x86_64/entry.S
xen/xen/arch/x86/x86_64/entry.S
--- vanilla.xen/xen/arch/x86/x86_64/entry.S 2006-03-16 09:53:07.000000000
+0200
+++ xen/xen/arch/x86/x86_64/entry.S 2006-03-20 15:15:00.000000000 +0200
@@ -557,6 +557,8 @@ ENTRY(hypercall_table)
.quad do_acm_op
.quad do_nmi_op
.quad do_arch_sched_op_new
+ .quad do_iommu_map /* 30 */
+ .quad do_iommu_unmap
.rept NR_hypercalls-((.-hypercall_table)/8)
.quad do_ni_hypercall
.endr
@@ -592,6 +594,8 @@ ENTRY(hypercall_args_table)
.byte 1 /* do_acm_op */
.byte 2 /* do_nmi_op */
.byte 2 /* do_arch_sched_op_new */
+ .byte 5 /* do_iommu_map */ /* 30 */
+ .byte 3 /* do_iommu_unmap */
.rept NR_hypercalls-(.-hypercall_args_table)
.byte 0 /* do_ni_hypercall */
.endr
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/common/calgary.c
xen/xen/common/calgary.c
--- vanilla.xen/xen/common/calgary.c 1970-01-01 02:00:00.000000000 +0200
+++ xen/xen/common/calgary.c 2006-03-26 21:57:45.000000000 +0200
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2006 Muli Ben-Yehuda <mulix@xxxxxxxxx>, IBM Corporation
+ */
+
+#include <xen/lib.h>
+#include <xen/iommu.h>
+#include <xen/calgary.h>
+#include <xen/errno.h>
+#include <xen/mm.h>
+#include <asm/types.h>
+#include <asm/system.h>
+
+#define swab64(x) \
+({ \
+ u64 __x = (x); \
+ ((u64)( \
+ (u64)(((u64)(__x) & (u64)0x00000000000000ffULL) << 56) | \
+ (u64)(((u64)(__x) & (u64)0x000000000000ff00ULL) << 40) | \
+ (u64)(((u64)(__x) & (u64)0x0000000000ff0000ULL) << 24) | \
+ (u64)(((u64)(__x) & (u64)0x00000000ff000000ULL) << 8) | \
+ (u64)(((u64)(__x) & (u64)0x000000ff00000000ULL) >> 8) | \
+ (u64)(((u64)(__x) & (u64)0x0000ff0000000000ULL) >> 24) | \
+ (u64)(((u64)(__x) & (u64)0x00ff000000000000ULL) >> 40) | \
+ (u64)(((u64)(__x) & (u64)0xff00000000000000ULL) >> 56) )); \
+})
+
+/* flush a tce at 'tceaddr' to main memory */
+static inline void flush_tce(void* tceaddr)
+{
+ /* a single tce can't cross a cache line */
+ if (cpu_has_clflush)
+ asm volatile("clflush (%0)" :: "r" (tceaddr));
+ else
+ asm volatile("wbinvd":::"memory");
+}
+
+static void tce_build(struct iommu_table* tbl, u64 index, u64 mfn, u32 access)
+{
+ u64* tp;
+ u64 t;
+
+ BUG_ON(!tbl);
+
+ t = (mfn << TCE_RPN_SHIFT) | access;
+
+ tp = ((u64*)tbl->ptr) + index;
+ *tp = swab64(t);
+
+ /* make sure HW sees it */
+ flush_tce(tp);
+}
+
+static inline u64 iospace_size_to_num_table_entries(u64 maxaddr)
+{
+ u64 ret;
+ u64 order;
+
+ order = get_order_from_bytes(maxaddr >> 13);
+
+ if (order > TCE_MAX_TABLE_SIZE)
+ order = TCE_MAX_TABLE_SIZE;
+
+ ret = (1 << order) * 0x2000;
+
+ return ret;
+}
+
+int calgary_create_io_space(u64 size, u32 bdf, void** space, u64* rootmfn)
+{
+ struct iommu_table* tbl;
+ int ret;
+ u64 bytes;
+
+ tbl = xmalloc(struct iommu_table);
+ if (!tbl) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ tbl->size = iospace_size_to_num_table_entries(size); /* number of entries
*/
+ bytes = tbl->size * TCE_ENTRY_SIZE;
+
+ tbl->ptr = alloc_xenheap_pages(get_order_from_bytes(bytes));
+ if (!tbl->ptr) {
+ ret = -ENODEV;
+ goto free_table;
+ }
+
+ *space = tbl;
+ *rootmfn = virt_to_maddr(tbl->ptr) >> PAGE_SHIFT;
+ return 0;
+
+free_table:
+ xfree(tbl);
+ *space = NULL;
+ *rootmfn = 0;
+done:
+ BUG_ON(ret);
+ return ret;
+}
+
+void calgary_destroy_io_space(void* space)
+{
+ struct iommu_table* tbl = space;
+ u64 bytes = tbl->size * TCE_ENTRY_SIZE;
+
+ free_xenheap_pages(tbl->ptr, get_order_from_bytes(bytes));
+ tbl->ptr = NULL;
+}
+
+u64 calgary_map(void* space, u64 ioaddr, u64 mfn, u32 access, u32 bdf, u32
size)
+{
+ struct iommu_table* tbl = space;
+ u64 index = ioaddr >> PAGE_SHIFT;
+
+ BUG_ON(size != PAGE_SIZE);
+
+ tce_build(tbl, index, mfn, access);
+
+ return ioaddr;
+}
+
+int calgary_unmap(void* space, u64 ioaddr, u32 bdf, u32 size)
+{
+ struct iommu_table* tbl = space;
+ u64 index = ioaddr >> PAGE_SHIFT;
+
+ BUG_ON(size != PAGE_SIZE);
+
+ /* set the tce to all 0's */
+ tce_build(tbl, index, 0, 0);
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/common/dom0_ops.c
xen/xen/common/dom0_ops.c
--- vanilla.xen/xen/common/dom0_ops.c 2006-03-05 13:44:48.000000000 +0200
+++ xen/xen/common/dom0_ops.c 2006-03-07 15:28:26.000000000 +0200
@@ -18,6 +18,7 @@
#include <xen/console.h>
#include <xen/iocap.h>
#include <xen/guest_access.h>
+#include <xen/iommu.h>
#include <asm/current.h>
#include <public/dom0_ops.h>
#include <public/sched_ctl.h>
@@ -682,6 +683,20 @@ long do_dom0_op(GUEST_HANDLE(dom0_op_t)
break;
#endif
+ case DOM0_IOMMU_CREATE_IO_SPACE:
+ {
+ ret = iommu_create_io_space(u_dom0_op, op);
+ }
+ break;
+
+ case DOM0_IOMMU_DESTROY_IO_SPACE:
+ {
+ u32 bdf = op->u.iommu_destroy_io_space.bdf;
+
+ ret = iommu_destroy_io_space(bdf);
+ }
+ break;
+
default:
ret = arch_do_dom0_op(op, u_dom0_op);
break;
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/common/iommu.c
xen/xen/common/iommu.c
--- vanilla.xen/xen/common/iommu.c 1970-01-01 02:00:00.000000000 +0200
+++ xen/xen/common/iommu.c 2006-03-26 15:15:12.000000000 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2006 Muli Ben-Yehuda <mulix@xxxxxxxxx>, IBM Corporation
+ */
+
+#include <xen/iommu.h>
+#include <xen/calgary.h>
+#include <xen/guest_access.h>
+
+/*
+ * TODOs:
+ * - use a tree sorted by BDF to hold IO spaces
+ * - add cache flushing interfaces - all entries, single entry, range of
entries
+ * - TODO: add iommu_ops with dynamic registration, call iommu_ops->op for ops
+ */
+
+#define NUM_IOMMU_SPACES 2
+void* iommu_space[NUM_IOMMU_SPACES];
+
+int iommu_create_io_space(GUEST_HANDLE(dom0_op_t) u_dom0_op, struct dom0_op*
op)
+{
+ void* space;
+ int ret;
+ u64 size = op->u.iommu_create_io_space.size;
+ u32 bdf = op->u.iommu_create_io_space.bdf;
+ u64* rootmfn = &op->u.iommu_create_io_space.rootmfn;
+
+ printk("%s called (size %"PRIu64" bdf 0x%x)!\n", __func__,
+ size, bdf);
+
+ ret = calgary_create_io_space(size, bdf, &space, rootmfn);
+ if (ret)
+ goto done;
+
+ printk("space %p rootmfn %"PRIx64"\n", space, *rootmfn);
+ if (bdf == 0)
+ iommu_space[0] = space;
+ else
+ iommu_space[1] = space;
+
+ ret = 0;
+
+ /* FIXME: cleanup if fails */
+ if ( copy_to_guest(u_dom0_op, op, 1) )
+ ret = -EFAULT;
+done:
+ return ret;
+}
+
+/* should this take BDF instead? */
+int iommu_destroy_io_space(u32 bdf)
+{
+ void** space;
+
+ if (bdf == 0)
+ space = &iommu_space[0];
+ else
+ space = &iommu_space[1];
+
+ calgary_destroy_io_space(*space);
+ *space = NULL;
+
+ return 0;
+}
+
+static inline void* find_io_space(u32 bdf)
+{
+ void* space;
+
+ space = (bdf == 0 ? iommu_space[0] : iommu_space[1]);
+
+ return space;
+}
+
+/* map takes a single "entry" - use hypercalls for batching */
+u64 do_iommu_map(u64 ioaddr, u64 mfn, u32 access, u32 bdf, u32 size)
+{
+ void* space;
+ u64 retaddr;
+
+ space = find_io_space(bdf);
+
+ retaddr = calgary_map(space, ioaddr, mfn, access, bdf, size);
+
+ /* the interface allows it but the current implementation doesn't */
+ BUG_ON(retaddr != ioaddr);
+
+ return retaddr;
+}
+
+/* unmap takes a single "entry" - use hypercalls for batching */
+int do_iommu_unmap(u64 ioaddr, u32 bdf, u32 size)
+{
+ void* space;
+ int ret;
+
+ space = find_io_space(bdf);
+
+ ret = calgary_unmap(space, ioaddr, bdf, size);
+
+ return ret;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/common/Makefile
xen/xen/common/Makefile
--- vanilla.xen/xen/common/Makefile 2006-03-19 20:10:13.000000000 +0200
+++ xen/xen/common/Makefile 2006-03-20 12:28:54.000000000 +0200
@@ -2,11 +2,13 @@ include $(BASEDIR)/Rules.mk
obj-y += acm_ops.o
obj-y += bitmap.o
+obj-y += calgary.o
obj-y += dom0_ops.o
obj-y += domain.o
obj-y += elf.o
obj-y += event_channel.o
obj-y += grant_table.o
+obj-y += iommu.o
obj-y += kernel.o
obj-y += keyhandler.o
obj-y += lib.o
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/include/public/dom0_ops.h
xen/xen/include/public/dom0_ops.h
--- vanilla.xen/xen/include/public/dom0_ops.h 2006-03-07 19:54:46.000000000
+0200
+++ xen/xen/include/public/dom0_ops.h 2006-03-07 20:35:04.000000000 +0200
@@ -470,6 +470,20 @@ typedef struct dom0_hypercall_init {
unsigned long mfn; /* machine frame to be initialised */
} dom0_hypercall_init_t;
DEFINE_GUEST_HANDLE(dom0_hypercall_init_t);
+
+#define DOM0_IOMMU_CREATE_IO_SPACE 49
+typedef struct dom0_iommu_create_io_space {
+ u64 size; /* size of the IO address space in bytes */
+ u32 bdf; /* bus/dev/func this space translates for */
+ u64 rootmfn; /* mfn of the root of the iommu table */
+} dom0_iommu_create_io_space_t;
+DEFINE_GUEST_HANDLE(dom0_iommu_create_io_space_t);
+
+#define DOM0_IOMMU_DESTROY_IO_SPACE 50
+typedef struct dom0_iommu_destroy_io_space {
+ u32 bdf;
+} dom0_iommu_destroy_io_space_t;
+DEFINE_GUEST_HANDLE(dom0_iommu_destroy_io_space_t);
typedef struct dom0_op {
uint32_t cmd;
@@ -512,6 +526,8 @@ typedef struct dom0_op {
struct dom0_irq_permission irq_permission;
struct dom0_iomem_permission iomem_permission;
struct dom0_hypercall_init hypercall_init;
+ struct dom0_iommu_create_io_space iommu_create_io_space;
+ struct dom0_iommu_destroy_io_space iommu_destroy_io_space;
uint8_t pad[128];
} u;
} dom0_op_t;
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/include/public/xen.h
xen/xen/include/public/xen.h
--- vanilla.xen/xen/include/public/xen.h 2006-03-16 09:53:07.000000000
+0200
+++ xen/xen/include/public/xen.h 2006-03-16 23:08:13.000000000 +0200
@@ -60,6 +60,8 @@
#define __HYPERVISOR_acm_op 27
#define __HYPERVISOR_nmi_op 28
#define __HYPERVISOR_sched_op_new 29
+#define __HYPERVISOR_iommu_map 30
+#define __HYPERVISOR_iommu_unmap 31
/*
* VIRTUAL INTERRUPTS
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/include/xen/calgary.h
xen/xen/include/xen/calgary.h
--- vanilla.xen/xen/include/xen/calgary.h 1970-01-01 02:00:00.000000000
+0200
+++ xen/xen/include/xen/calgary.h 2006-03-16 23:22:27.000000000 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2006 Muli Ben-Yehuda <mulix@xxxxxxxxx>, IBM Corporation
+ */
+
+#define TCE_MAX_TABLE_SIZE 7
+
+struct iommu_table {
+ u32 size; /* in number of entries */
+ void* ptr;
+};
+
+#define TCE_ENTRY_SIZE 8 /* in bytes */
+
+#define TCE_READ_SHIFT 0
+#define TCE_WRITE_SHIFT 1
+#define TCE_HUBID_SHIFT 2 /* unused */
+#define TCE_RSVD_SHIFT 8 /* unused */
+#define TCE_RPN_SHIFT 12
+#define TCE_UNUSED_SHIFT 48 /* unused */
+
+#define TCE_RPN_MASK 0x0000fffffffff000ULL
+
+int calgary_create_io_space(u64 size, u32 bdf, void** space, u64* rootmfn);
+void calgary_destroy_io_space(void* space);
+u64 calgary_map(void* space, u64 ioaddr, u64 mfn, u32 access, u32 bdf,
+ u32 size);
+int calgary_unmap(void* space, u64 ioaddr, u32 bdf, u32 size);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/include/xen/iommu.h
xen/xen/include/xen/iommu.h
--- vanilla.xen/xen/include/xen/iommu.h 1970-01-01 02:00:00.000000000 +0200
+++ xen/xen/include/xen/iommu.h 2006-03-20 15:17:11.000000000 +0200
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006 Muli Ben-Yehuda <mulix@xxxxxxxxx>, IBM Corporation
+ */
+
+#include <asm/types.h>
+#include <asm/page.h>
+#include <public/dom0_ops.h>
+
+int iommu_create_io_space(GUEST_HANDLE(dom0_op_t) u_dom0_op,
+ struct dom0_op *op);
+int iommu_destroy_io_space(u32 bdf);
+u64 do_iommu_map(u64 ioaddr, u64 mfn, u32 access, u32 bdf, u32 size);
+int do_iommu_unmap(u64 ioaddr, u32 bdf, u32 size);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
Muli Ben-Yehuda
http://www.mulix.org | http://mulix.livejournal.com/
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|