Hi,
xencomm is the ppc infrastructure to do hypercalls with guest physical
addresses instead of virtual address.
Because ia64 should also use physicall address, I think it's better to re-use
the ppc code and to put into common code.
I'd propose to submit this patch is every part is OK (ie no NAK).
This patch creates include/xen/xencomm_access.h which is to be included by
asm/guest_access.h. It also creates common/xencomm.c which is compiled only
if HAS_XENCOMM is y in Rules.mk.
Arch using xencomm should defines a few arch-specific macros and function.
I will submit the linux side soon.
Tristan.
diff -r 1a542420ccf4 xen/common/Makefile
--- a/xen/common/Makefile Fri Aug 18 15:48:42 2006 +0200
+++ b/xen/common/Makefile Mon Aug 21 07:37:35 2006 +0200
@@ -26,6 +26,8 @@ obj-y += vsprintf.o
obj-y += vsprintf.o
obj-y += xmalloc.o
+obj-$(HAS_XENCOMM) += xencomm.o
+
obj-$(perfc) += perfc.o
obj-$(crash_debug) += gdbstub.o
diff -r 1a542420ccf4 xen/include/public/xencomm.h
--- a/xen/include/public/xencomm.h Fri Aug 18 15:48:42 2006 +0200
+++ b/xen/include/public/xencomm.h Mon Aug 21 07:37:35 2006 +0200
@@ -34,4 +34,15 @@ struct xencomm_desc {
uint64_t address[0];
};
+/* Inline Xencomm.
+ If the inline flag is set, the descriptor is simply a the flagged
+ physical address of the buffer which is known to be contiguous in
+ physical memory. Because the kernels are often 1:1 mapped, this is
+ interesting for kernel issued hypercalls. */
+/* These macros should be defined by arch-xxx.h:
+ XENCOMM_IS_INLINE(addr): true if ADDR is an inline address.
+ XENCOMM_INLINE_ADDR(addr): extract the physical address (as an unsigned).
+ XENCOMM_INLINE_MAKE(addr): flag ADDR and returns an unsigned.
+*/
+
#endif /* _XEN_XENCOMM_H_ */
diff -r 1a542420ccf4 xen/common/xencomm.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/common/xencomm.c Mon Aug 21 07:37:35 2006 +0200
@@ -0,0 +1,316 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright (C) IBM Corp. 2006
+ *
+ * Authors: Hollis Blanchard <[EMAIL PROTECTED]>
+ * Tristan Gingold <[EMAIL PROTECTED]>
+ */
+
+#include <xen/config.h>
+#include <xen/mm.h>
+#include <xen/sched.h>
+#include <asm/current.h>
+#include <xen/xencomm_access.h>
+#include <public/xen.h>
+#include <public/xencomm.h>
+#include <xen/errno.h>
+
+#undef DEBUG
+#ifdef DEBUG
+static int xencomm_debug = 1; /* extremely verbose */
+#else
+#define xencomm_debug 0
+#endif
+
+/**
+ * xencomm_copy_from_guest: Copy a block of data from domain space.
+ * @to: Machine address.
+ * @from: Physical address to a xencomm buffer descriptor.
+ * @n: Number of bytes to copy.
+ * @skip: Number of bytes from the start to skip.
+ *
+ * Copy data from domain to hypervisor.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+unsigned long
+xencomm_copy_from_guest(void *to, const void *from, unsigned int n,
+ unsigned int skip)
+{
+ struct xencomm_desc *desc;
+ unsigned long desc_addr;
+ unsigned int from_pos = 0;
+ unsigned int to_pos = 0;
+ unsigned int i = 0;
+
+ if (xencomm_debug)
+ printf ("xencomm_copy_from_guest: from=%lx+%u n=%u\n",
+ (unsigned long)from, skip, n);
+
+ if (XENCOMM_IS_INLINE (from)) {
+ unsigned long src_paddr = XENCOMM_INLINE_ADDR (from);
+
+ src_paddr += skip;
+
+ while (n > 0) {
+ unsigned int chunksz;
+ unsigned long src_maddr;
+ unsigned int bytes;
+
+ chunksz = PAGE_SIZE - (src_paddr % PAGE_SIZE);
+
+ bytes = min(chunksz, n);
+
+ src_maddr = xencomm_paddr_to_maddr(src_paddr);
+ if (xencomm_debug > 1)
+ printk("%lx[%d] -> %lx\n",
+ src_maddr, bytes, (unsigned long)to);
+ if (src_maddr == 0)
+ return -EFAULT;
+ memcpy(to, (void *)src_maddr, bytes);
+ src_paddr += bytes;
+ to += bytes;
+ n -= bytes;
+ }
+
+ /* Always successful. */
+ return 0;
+ }
+
+ /* first we need to access the descriptor */
+ desc_addr = xencomm_paddr_to_maddr((unsigned long)from);
+ if (desc_addr == 0)
+ return -EFAULT;
+
+ desc = (struct xencomm_desc *)desc_addr;
+ if (desc->magic != XENCOMM_MAGIC) {
+ printk("%s: error: %p magic was 0x%x\n",
+ __func__, desc, desc->magic);
+ return -EFAULT;
+ }
+
+ /* iterate through the descriptor, copying up to a page at a time */
+ while ((to_pos < n) && (i < desc->nr_addrs)) {
+ unsigned long src_paddr = desc->address[i];
+ unsigned int pgoffset;
+ unsigned int chunksz;
+ unsigned int chunk_skip;
+
+ if (src_paddr == XENCOMM_INVALID) {
+ i++;
+ continue;
+ }
+
+ pgoffset = src_paddr % PAGE_SIZE;
+ chunksz = PAGE_SIZE - pgoffset;
+
+ chunk_skip = min(chunksz, skip);
+ from_pos += chunk_skip;
+ chunksz -= chunk_skip;
+ skip -= chunk_skip;
+
+ if (skip == 0) {
+ unsigned long src_maddr;
+ unsigned long dest = (unsigned long)to + to_pos;
+ unsigned int bytes = min(chunksz, n - to_pos);
+
+ if (xencomm_debug > 1)
+ printf ("src_paddr=%lx i=%d, skip=%d\n",
+ src_paddr, i, chunk_skip);
+ src_maddr = xencomm_paddr_to_maddr(src_paddr + chunk_skip);
+ if (xencomm_debug > 1)
+ printk("%lx[%d] -> %lx\n", src_maddr, bytes, dest);
+ if (src_maddr == 0)
+ return -EFAULT;
+ memcpy((void *)dest, (void *)src_maddr, bytes);
+ from_pos += bytes;
+ to_pos += bytes;
+ }
+
+ i++;
+ }
+
+ return n - to_pos;
+}
+
+/**
+ * xencomm_copy_to_guest: Copy a block of data to domain space.
+ * @to: Physical address to xencomm buffer descriptor.
+ * @from: Machine address.
+ * @n: Number of bytes to copy.
+ * @skip: Number of bytes from the start to skip.
+ *
+ * Copy data from hypervisor to domain.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+unsigned long
+xencomm_copy_to_guest(void *to, const void *from, unsigned int n,
+ unsigned int skip)
+{
+ struct xencomm_desc *desc;
+ unsigned long desc_addr;
+ unsigned int from_pos = 0;
+ unsigned int to_pos = 0;
+ unsigned int i = 0;
+
+ if (xencomm_debug)
+ printf ("xencomm_copy_to_guest: to=%lx+%u n=%u\n",
+ (unsigned long)to, skip, n);
+
+ if (XENCOMM_IS_INLINE (to)) {
+ unsigned long dest_paddr = XENCOMM_INLINE_ADDR (to);
+
+ dest_paddr += skip;
+
+ while (n > 0) {
+ unsigned int chunksz;
+ unsigned long dest_maddr;
+ unsigned int bytes;
+
+ chunksz = PAGE_SIZE - (dest_paddr % PAGE_SIZE);
+
+ bytes = min(chunksz, n);
+
+ dest_maddr = xencomm_paddr_to_maddr(dest_paddr);
+ if (xencomm_debug > 1)
+ printk("%lx[%d] -> %lx\n",
+ (unsigned long)from, bytes, dest_maddr);
+ if (dest_maddr == 0)
+ return -EFAULT;
+ memcpy((void *)dest_maddr, (void *)from, bytes);
+ dest_paddr += bytes;
+ from += bytes;
+ n -= bytes;
+ }
+
+ /* Always successful. */
+ return 0;
+ }
+
+ /* first we need to access the descriptor */
+ desc_addr = xencomm_paddr_to_maddr((unsigned long)to);
+ if (desc_addr == 0)
+ return -EFAULT;
+ desc = (struct xencomm_desc *)desc_addr;
+ if (desc->magic != XENCOMM_MAGIC) {
+ printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic);
+ return -EFAULT;
+ }
+
+ /* iterate through the descriptor, copying up to a page at a time */
+ while ((from_pos < n) && (i < desc->nr_addrs)) {
+ unsigned long dest_paddr = desc->address[i];
+ unsigned int pgoffset;
+ unsigned int chunksz;
+ unsigned int chunk_skip;
+
+ if (dest_paddr == XENCOMM_INVALID) {
+ i++;
+ continue;
+ }
+
+ pgoffset = dest_paddr % PAGE_SIZE;
+ chunksz = PAGE_SIZE - pgoffset;
+
+ chunk_skip = min(chunksz, skip);
+ to_pos += chunk_skip;
+ chunksz -= chunk_skip;
+ skip -= chunk_skip;
+
+ if (skip == 0) {
+ unsigned long dest_maddr;
+ unsigned long source = (unsigned long)from + from_pos;
+ unsigned int bytes = min(chunksz, n - from_pos);
+
+ dest_maddr = xencomm_paddr_to_maddr(dest_paddr + chunk_skip);
+ if (xencomm_debug > 1)
+ printk("%lx[%d] -> %lx\n", source, bytes, dest_maddr);
+ if (dest_maddr == 0)
+ return -EFAULT;
+ memcpy((void *)dest_maddr, (void *)source, bytes);
+ from_pos += bytes;
+ to_pos += bytes;
+ }
+
+ i++;
+ }
+
+ return n - from_pos;
+}
+
+/* Offset page addresses in 'handle' to skip 'bytes' bytes. Set completely
+ * exhausted pages to XENCOMM_INVALID. */
+void *xencomm_add_offset(void *handle, unsigned int bytes)
+{
+ struct xencomm_desc *desc;
+ unsigned long desc_addr;
+ int i = 0;
+
+ if (XENCOMM_IS_INLINE (handle)) {
+ return (void *)((unsigned long)handle + bytes);
+ }
+
+ /* first we need to access the descriptor */
+ desc_addr = xencomm_paddr_to_maddr((unsigned long)handle);
+ if (desc_addr == 0)
+ return NULL;
+ desc = (struct xencomm_desc *)desc_addr;
+ if (desc->magic != XENCOMM_MAGIC) {
+ printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic);
+ return NULL;
+ }
+
+ /* iterate through the descriptor incrementing addresses */
+ while ((bytes > 0) && (i < desc->nr_addrs)) {
+ unsigned long dest_paddr = desc->address[i];
+ unsigned int pgoffset;
+ unsigned int chunksz;
+ unsigned int chunk_skip;
+
+ pgoffset = dest_paddr % PAGE_SIZE;
+ chunksz = PAGE_SIZE - pgoffset;
+
+ chunk_skip = min(chunksz, bytes);
+ if (chunk_skip == chunksz) {
+ /* exhausted this page */
+ desc->address[i] = XENCOMM_INVALID;
+ } else {
+ desc->address[i] += chunk_skip;
+ }
+ bytes -= chunk_skip;
+ }
+ return handle;
+}
+
+int xencomm_handle_is_null(void *ptr)
+{
+ if (XENCOMM_IS_INLINE (ptr)) {
+ return XENCOMM_INLINE_ADDR (ptr) == 0;
+ }
+ else {
+ struct xencomm_desc *desc;
+ unsigned long desc_addr;
+
+ desc_addr = xencomm_paddr_to_maddr((unsigned long)ptr);
+ if (desc_addr == 0)
+ return 1;
+ desc = (struct xencomm_desc *)desc_addr;
+ return (desc->address[0] == XENCOMM_INVALID);
+ }
+}
diff -r 1a542420ccf4 xen/include/xen/xencomm_access.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xen/include/xen/xencomm_access.h Mon Aug 21 07:37:35 2006 +0200
@@ -0,0 +1,107 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright (C) IBM Corp. 2006
+ *
+ * Authors: Hollis Blanchard <[EMAIL PROTECTED]>
+ * Tristan Gingold <[EMAIL PROTECTED]>
+ */
+
+#ifndef __ASM_GUEST_ACCESS_H__
+#define __ASM_GUEST_ACCESS_H__
+
+extern unsigned long xencomm_copy_to_guest(void *to, const void *from,
+ unsigned int len, unsigned int skip);
+extern unsigned long xencomm_copy_from_guest(void *to, const void *from,
+ unsigned int len, unsigned int skip);
+extern void *xencomm_add_offset(void *handle, unsigned int bytes);
+extern int xencomm_handle_is_null(void *ptr);
+
+
+/* Is the guest handle a NULL reference? */
+#define guest_handle_is_null(hnd) \
+ ((hnd).p == NULL || xencomm_handle_is_null((hnd).p))
+
+/* Offset the given guest handle into the array it refers to. */
+#define guest_handle_add_offset(hnd, nr) ({ \
+ const typeof((hnd).p) _ptr = (hnd).p; \
+ (hnd).p = xencomm_add_offset(_ptr, nr * sizeof(*_ptr)); \
+})
+
+/* Cast a guest handle to the specified type of handle. */
+#define guest_handle_cast(hnd, type) ({ \
+ type *_x = (hnd).p; \
+ XEN_GUEST_HANDLE(type) _y; \
+ set_xen_guest_handle(_y, _x); \
+ _y; \
+})
+
+
+/* Since we run in real mode, we can safely access all addresses. That also
+ * means our __routines are identical to our "normal" routines. */
+#define guest_handle_okay(hnd, nr) 1
+
+/*
+ * Copy an array of objects to guest context via a guest handle.
+ * Optionally specify an offset into the guest array.
+ */
+#define copy_to_guest_offset(hnd, idx, ptr, nr) \
+ __copy_to_guest_offset(hnd, idx, ptr, nr)
+
+/* Copy sub-field of a structure to guest context via a guest handle. */
+#define copy_field_to_guest(hnd, ptr, field) \
+ __copy_field_to_guest(hnd, ptr, field)
+
+/*
+ * Copy an array of objects from guest context via a guest handle.
+ * Optionally specify an offset into the guest array.
+ */
+#define copy_from_guest_offset(ptr, hnd, idx, nr) \
+ __copy_from_guest_offset(ptr, hnd, idx, nr)
+
+/* Copy sub-field of a structure from guest context via a guest handle. */
+#define copy_field_from_guest(ptr, hnd, field) \
+ __copy_field_from_guest(ptr, hnd, field)
+
+#define __copy_to_guest_offset(hnd, idx, ptr, nr) ({ \
+ const typeof(ptr) _d = (hnd).p; \
+ const typeof(ptr) _s = (ptr); \
+ xencomm_copy_to_guest(_d, _s, sizeof(*_s)*(nr), sizeof(*_s)*(idx)); \
+})
+
+#define __copy_field_to_guest(hnd, ptr, field) ({ \
+ const int _off = offsetof(typeof(*ptr), field); \
+ const typeof(ptr) _d = (hnd).p; \
+ const typeof(&(ptr)->field) _s = &(ptr)->field; \
+ xencomm_copy_to_guest(_d, _s, sizeof(*_s), _off); \
+})
+
+#define __copy_from_guest_offset(ptr, hnd, idx, nr) ({ \
+ const typeof(ptr) _s = (hnd).p; \
+ const typeof(ptr) _d = (ptr); \
+ xencomm_copy_from_guest(_d, _s, sizeof(*_s)*(nr), sizeof(*_s)*(idx)); \
+})
+
+#define __copy_field_from_guest(ptr, hnd, field) ({ \
+ const int _off = offsetof(typeof(*ptr), field); \
+ const typeof(ptr) _s = (hnd).p; \
+ const typeof(&(ptr)->field) _d = &(ptr)->field; \
+ xencomm_copy_from_guest(_d, _s, sizeof(*_d), _off); \
+})
+
+/* Internal use only: returns 0 in case of bad address. */
+extern unsigned long xencomm_paddr_to_maddr (unsigned long paddr);
+
+#endif /* __ASM_GUEST_ACCESS_H__ */
_______________________________________________
Xen-ppc-devel mailing list
[email protected]
http://lists.xensource.com/xen-ppc-devel