diff -r 8c6bb45901e7 xen/arch/ia64/xen/Makefile --- a/xen/arch/ia64/xen/Makefile Wed Aug 16 14:28:57 2006 -0600 +++ b/xen/arch/ia64/xen/Makefile Fri Aug 18 14:26:09 2006 +0200 @@ -25,5 +25,6 @@ obj-y += xentime.o obj-y += xentime.o obj-y += flushd.o obj-y += privop_stat.o +obj-y += usercopy.o obj-$(crash_debug) += gdbstub.o diff -r 8c6bb45901e7 xen/arch/ia64/xen/faults.c --- a/xen/arch/ia64/xen/faults.c Wed Aug 16 14:28:57 2006 -0600 +++ b/xen/arch/ia64/xen/faults.c Fri Aug 18 14:26:09 2006 +0200 @@ -225,10 +228,10 @@ void ia64_do_page_fault (unsigned long a // indicate a bad xen pointer printk("*** xen_handle_domain_access: exception table" " lookup failed, iip=0x%lx, addr=0x%lx, spinning...\n", - iip, address); + iip, address); panic_domain(regs,"*** xen_handle_domain_access: exception table" - " lookup failed, iip=0x%lx, addr=0x%lx, spinning...\n", - iip, address); + " lookup failed, iip=0x%lx, addr=0x%lx, spinning...\n", + iip, address); } return; } diff -r 8c6bb45901e7 xen/arch/ia64/xen/hypercall.c --- a/xen/arch/ia64/xen/hypercall.c Wed Aug 16 14:28:57 2006 -0600 +++ b/xen/arch/ia64/xen/hypercall.c Fri Aug 18 14:26:09 2006 +0200 @@ -29,7 +30,6 @@ #include #include -static long do_physdev_op_compat(XEN_GUEST_HANDLE(physdev_op_t) uop); static long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg); static long do_callback_op(int cmd, XEN_GUEST_HANDLE(void) arg); @@ -51,10 +51,10 @@ const hypercall_t ia64_hypercall_table[N (hypercall_t)do_multicall, (hypercall_t)do_ni_hypercall, /* do_update_va_mapping */ (hypercall_t)do_ni_hypercall, /* do_set_timer_op */ /* 15 */ - (hypercall_t)do_event_channel_op_compat, + (hypercall_t)do_ni_hypercall, (hypercall_t)do_xen_version, (hypercall_t)do_console_io, - (hypercall_t)do_physdev_op_compat, + (hypercall_t)do_ni_hypercall, (hypercall_t)do_grant_table_op, /* 20 */ (hypercall_t)do_ni_hypercall, /* do_vm_assist */ (hypercall_t)do_ni_hypercall, /* do_update_va_mapping_othe */ @@ -105,19 +105,6 @@ xen_hypercall (struct pt_regs *regs) xen_hypercall (struct pt_regs *regs) { uint32_t cmd = (uint32_t)regs->r2; - struct vcpu *v = current; - - if (cmd == __HYPERVISOR_grant_table_op) { - XEN_GUEST_HANDLE(void) uop; - - v->arch.hypercall_param.va = regs->r15; - v->arch.hypercall_param.pa1 = regs->r17; - v->arch.hypercall_param.pa2 = regs->r18; - set_xen_guest_handle(uop, (void *)regs->r15); - regs->r8 = do_grant_table_op(regs->r14, uop, regs->r16); - v->arch.hypercall_param.va = 0; - return IA64_NO_FAULT; - } if (cmd < NR_hypercalls) { perfc_incra(hypercalls, cmd); @@ -130,7 +117,7 @@ xen_hypercall (struct pt_regs *regs) regs->r19); } else regs->r8 = -ENOSYS; - + return IA64_NO_FAULT; } @@ -456,28 +443,6 @@ static long do_physdev_op(int cmd, XEN_G return ret; } -/* Legacy hypercall (as of 0x00030202). */ -static long do_physdev_op_compat(XEN_GUEST_HANDLE(physdev_op_t) uop) -{ - struct physdev_op op; - - if ( unlikely(copy_from_guest(&op, uop, 1) != 0) ) - return -EFAULT; - - return do_physdev_op(op.cmd, guest_handle_from_ptr(&uop.p->u, void)); -} - -/* Legacy hypercall (as of 0x00030202). */ -long do_event_channel_op_compat(XEN_GUEST_HANDLE(evtchn_op_t) uop) -{ - struct evtchn_op op; - - if ( unlikely(copy_from_guest(&op, uop, 1) != 0) ) - return -EFAULT; - - return do_event_channel_op(op.cmd, guest_handle_from_ptr(&uop.p->u, void)); -} - static long register_guest_callback(struct callback_register *reg) { long ret = 0; diff -r 8c6bb45901e7 xen/include/asm-ia64/guest_access.h --- a/xen/include/asm-ia64/guest_access.h Wed Aug 16 14:28:57 2006 -0600 +++ b/xen/include/asm-ia64/guest_access.h Fri Aug 18 14:26:09 2006 +0200 @@ -1,91 +1,103 @@ -/****************************************************************************** - * guest_access.h - * - * Copyright (c) 2006, K A Fraser +/* + * 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 */ -#ifndef __ASM_IA64_GUEST_ACCESS_H__ -#define __ASM_IA64_GUEST_ACCESS_H__ +#ifndef __ASM_GUEST_ACCESS_H__ +#define __ASM_GUEST_ACCESS_H__ -#include +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) +#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) ((hnd).p += (nr)) +#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)) { _x }; \ + XEN_GUEST_HANDLE(type) _y; \ + set_xen_guest_handle(_y, _x); \ + _y; \ }) -#define guest_handle_from_ptr(ptr, type) ((XEN_GUEST_HANDLE(type)) { (type *)ptr }) + +/* 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, - * specifying an offset into the guest array. + * 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, off, ptr, nr) ({ \ - const typeof(ptr) _x = (hnd).p; \ - const typeof(ptr) _y = (ptr); \ - copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ +#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)); \ }) -/* - * Copy an array of objects from guest context via a guest handle, - * specifying an offset into the guest array. - */ -#define copy_from_guest_offset(ptr, hnd, off, nr) ({ \ - const typeof(ptr) _x = (hnd).p; \ - const typeof(ptr) _y = (ptr); \ - copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ +#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); \ }) -/* Copy sub-field of a structure to guest context via a guest handle. */ -#define copy_field_to_guest(hnd, ptr, field) ({ \ - const typeof(&(ptr)->field) _x = &(hnd).p->field; \ - const typeof(&(ptr)->field) _y = &(ptr)->field; \ - copy_to_user(_x, _y, sizeof(*_x)); \ +#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)); \ }) -/* Copy sub-field of a structure from guest context via a guest handle. */ -#define copy_field_from_guest(ptr, hnd, field) ({ \ - const typeof(&(ptr)->field) _x = &(hnd).p->field; \ - const typeof(&(ptr)->field) _y = &(ptr)->field; \ - copy_from_user(_y, _x, sizeof(*_x)); \ +#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); \ }) -/* - * Pre-validate a guest handle. - * Allows use of faster __copy_* functions. - */ -#define guest_handle_okay(hnd, nr) \ - array_access_ok((hnd).p, (nr), sizeof(*(hnd).p)) - -#define __copy_to_guest_offset(hnd, off, ptr, nr) ({ \ - const typeof(ptr) _x = (hnd).p; \ - const typeof(ptr) _y = (ptr); \ - __copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ -}) - -#define __copy_from_guest_offset(ptr, hnd, off, nr) ({ \ - const typeof(ptr) _x = (hnd).p; \ - const typeof(ptr) _y = (ptr); \ - __copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ -}) - -#define __copy_field_to_guest(hnd, ptr, field) ({ \ - const typeof(&(ptr)->field) _x = &(hnd).p->field; \ - const typeof(&(ptr)->field) _y = &(ptr)->field; \ - __copy_to_user(_x, _y, sizeof(*_x)); \ -}) - -#define __copy_field_from_guest(ptr, hnd, field) ({ \ - const typeof(&(ptr)->field) _x = &(hnd).p->field; \ - const typeof(&(ptr)->field) _y = &(ptr)->field; \ - __copy_from_user(_y, _x, sizeof(*_x)); \ -}) - -#endif /* __ASM_IA64_GUEST_ACCESS_H__ */ +#endif /* __ASM_GUEST_ACCESS_H__ */ diff -r 8c6bb45901e7 xen/include/public/xencomm.h --- a/xen/include/public/xencomm.h Wed Aug 16 14:28:57 2006 -0600 +++ b/xen/include/public/xencomm.h Fri Aug 18 14:26:09 2006 +0200 @@ -34,4 +34,10 @@ struct xencomm_desc { uint64_t address[0]; }; +/* If the inline flag is set, the descriptor is simply the 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. */ +#define XENCOMM_INLINE (1UL << 63) + #endif /* _XEN_XENCOMM_H_ */ diff -r 8c6bb45901e7 xen/arch/ia64/xen/usercopy.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/ia64/xen/usercopy.c Fri Aug 18 14:26:09 2006 +0200 @@ -0,0 +1,303 @@ +/* + * 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +static int xencomm_debug = 1; /* extremely verbose */ +#else +#define xencomm_debug 0 +#endif + +/* XXX need to return error, not panic, if domain passed a bad pointer */ +static unsigned long paddr_to_maddr(unsigned long paddr) +{ + struct vcpu *v = current; + struct domain *d = v->domain; + u64 pa; + + pa = ____lookup_domain_mpa (d, paddr); + if (pa == INVALID_MFN) + panic_domain(NULL, + "%s: called with bad memory address type: 0x%lx\n", + __func__, paddr); + return __va_ul ((pa & _PFN_MASK) | (paddr & ~PAGE_MASK)); +} + +/** + * 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 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 ((unsigned long)from & XENCOMM_INLINE) { + unsigned long src_paddr = (unsigned long)from & ~XENCOMM_INLINE; + + 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 = paddr_to_maddr(src_paddr); + if (xencomm_debug > 1) + printk("%lx[%d] -> %lx\n", + src_maddr, bytes, (unsigned long)to); + 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 = (struct xencomm_desc *)paddr_to_maddr((unsigned long)from); + if (desc->magic != XENCOMM_MAGIC) { + printk("%s: error: %p magic was 0x%x\n", + __func__, desc, desc->magic); + return n; + } + + /* 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 = paddr_to_maddr(src_paddr + chunk_skip); + if (xencomm_debug > 1) + printk("%lx[%d] -> %lx\n", src_maddr, bytes, dest); + 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 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 ((unsigned long)to & XENCOMM_INLINE) { + unsigned long dest_paddr = (unsigned long)to & ~XENCOMM_INLINE; + + 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 = paddr_to_maddr(dest_paddr); + if (xencomm_debug > 1) + printk("%lx[%d] -> %lx\n", + (unsigned long)from, bytes, dest_maddr); + 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 = (struct xencomm_desc *)paddr_to_maddr((unsigned long)to); + if (desc->magic != XENCOMM_MAGIC) { + printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic); + return n; + } + + /* 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 = paddr_to_maddr(dest_paddr + chunk_skip); + if (xencomm_debug > 1) + printk("%lx[%d] -> %lx\n", source, bytes, dest_maddr); + 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; + int i = 0; + + if ((unsigned long)handle & XENCOMM_INLINE) { + return (void *)((unsigned long)handle + bytes); + } + + /* first we need to access the descriptor */ + desc = (struct xencomm_desc *)paddr_to_maddr((unsigned long)handle); + 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) +{ + struct xencomm_desc *desc; + + if ((unsigned long)ptr & XENCOMM_INLINE) + return (unsigned long)ptr == XENCOMM_INLINE; + else { + desc = (struct xencomm_desc *)paddr_to_maddr((unsigned long)ptr); + return (desc->address[0] == XENCOMM_INVALID); + } +}