# HG changeset patch # User gingold@virtu10 # Node ID e62f8f7fce90aec8c18e53f66de715f0acbb1f92 # Parent f34e37d0742d80ccfefd017a91f93310ebc2dfe8 Use xencomm for hypercalls. With xencomm metaphysical addresses are passed to the hypervisor instead of virtual addresses. This patch breaks compatibility. Signed-off-by: Tristan Gingold diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/arch/ia64/kernel/setup.c --- a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c Tue Sep 26 19:11:33 2006 -0600 +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c Thu Sep 28 10:37:56 2006 +0200 @@ -76,6 +76,8 @@ EXPORT_SYMBOL(__per_cpu_offset); #endif #ifdef CONFIG_XEN +unsigned long kernel_start_pa; + static int xen_panic_event(struct notifier_block *this, unsigned long event, void *ptr) { @@ -433,6 +435,7 @@ setup_arch (char **cmdline_p) #ifdef CONFIG_XEN if (is_running_on_xen()) { + kernel_start_pa = KERNEL_START - ia64_tpa (KERNEL_START); setup_xen_features(); /* Register a call for panic conditions. */ notifier_chain_register(&panic_notifier_list, &xen_panic_block); diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/arch/ia64/xen/Makefile --- a/linux-2.6-xen-sparse/arch/ia64/xen/Makefile Tue Sep 26 19:11:33 2006 -0600 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/Makefile Thu Sep 28 10:37:56 2006 +0200 @@ -3,6 +3,7 @@ # obj-y := hypercall.o xenivt.o xenentry.o xensetup.o xenpal.o xenhpski.o \ - hypervisor.o pci-dma-xen.o util.o + hypervisor.o pci-dma-xen.o util.o xencomm.o xcom_hcall.o \ + xcom_privcmd.o pci-dma-xen-y := ../../i386/kernel/pci-dma-xen.o diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c --- a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c Tue Sep 26 19:11:33 2006 -0600 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c Thu Sep 28 10:37:56 2006 +0200 @@ -39,60 +39,6 @@ EXPORT_SYMBOL(xen_start_info); int running_on_xen; EXPORT_SYMBOL(running_on_xen); - -//XXX xen/ia64 copy_from_guest() is broken. -// This is a temporal work around until it is fixed. -// used by balloon.c netfront.c - -// get_xen_guest_handle is defined only when __XEN_TOOLS__ is defined -// if the definition in arch-ia64.h is changed, this must be updated. -#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0) - -int -ia64_xenmem_reservation_op(unsigned long op, - struct xen_memory_reservation* reservation__) -{ - struct xen_memory_reservation reservation = *reservation__; - unsigned long* frame_list; - unsigned long nr_extents = reservation__->nr_extents; - int ret = 0; - get_xen_guest_handle(frame_list, reservation__->extent_start); - - BUG_ON(op != XENMEM_increase_reservation && - op != XENMEM_decrease_reservation && - op != XENMEM_populate_physmap); - - while (nr_extents > 0) { - int tmp_ret; - volatile unsigned long dummy; - - set_xen_guest_handle(reservation.extent_start, frame_list); - reservation.nr_extents = nr_extents; - - dummy = frame_list[0];// re-install tlb entry before hypercall - tmp_ret = ____HYPERVISOR_memory_op(op, &reservation); - if (tmp_ret < 0) { - if (ret == 0) { - ret = tmp_ret; - } - break; - } - if (tmp_ret == 0) { - //XXX dirty work around for skbuff_ctor() - // of a non-privileged domain, - if ((op == XENMEM_increase_reservation || - op == XENMEM_populate_physmap) && - !is_initial_xendomain() && - reservation.extent_order > 0) - return ret; - } - frame_list += tmp_ret; - nr_extents -= tmp_ret; - ret += tmp_ret; - } - return ret; -} -EXPORT_SYMBOL(ia64_xenmem_reservation_op); //XXX same as i386, x86_64 contiguous_bitmap_set(), contiguous_bitmap_clear() // move those to lib/contiguous_bitmap? @@ -371,8 +317,6 @@ int int HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count) { - __u64 va1, va2, pa1, pa2; - if (cmd == GNTTABOP_map_grant_ref) { unsigned int i; for (i = 0; i < count; i++) { @@ -380,29 +324,7 @@ HYPERVISOR_grant_table_op(unsigned int c (struct gnttab_map_grant_ref*)uop + i); } } - va1 = (__u64)uop & PAGE_MASK; - pa1 = pa2 = 0; - if ((REGION_NUMBER(va1) == 5) && - ((va1 - KERNEL_START) >= KERNEL_TR_PAGE_SIZE)) { - pa1 = ia64_tpa(va1); - if (cmd <= GNTTABOP_transfer) { - static uint32_t uop_size[GNTTABOP_transfer + 1] = { - sizeof(struct gnttab_map_grant_ref), - sizeof(struct gnttab_unmap_grant_ref), - sizeof(struct gnttab_setup_table), - sizeof(struct gnttab_dump_table), - sizeof(struct gnttab_transfer), - }; - va2 = (__u64)uop + (uop_size[cmd] * count) - 1; - va2 &= PAGE_MASK; - if (va1 != va2) { - /* maximum size of uop is 2pages */ - BUG_ON(va2 > va1 + PAGE_SIZE); - pa2 = ia64_tpa(va2); - } - } - } - return ____HYPERVISOR_grant_table_op(cmd, uop, count, pa1, pa2); + return xencomm_mini_hypercall_grant_table_op(cmd, uop, count); } EXPORT_SYMBOL(HYPERVISOR_grant_table_op); diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/arch/ia64/xen/util.c --- a/linux-2.6-xen-sparse/arch/ia64/xen/util.c Tue Sep 26 19:11:33 2006 -0600 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/util.c Thu Sep 28 10:37:56 2006 +0200 @@ -28,6 +28,8 @@ #include #include #include +#include +#include struct vm_struct *alloc_vm_area(unsigned long size) { diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c Tue Sep 26 19:11:33 2006 -0600 +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c Thu Sep 28 10:37:56 2006 +0200 @@ -83,18 +83,7 @@ static int privcmd_ioctl(struct inode *i : "r8", "r10", "memory" ); } #elif defined (__ia64__) - __asm__ __volatile__ ( - ";; mov r14=%2; mov r15=%3; " - "mov r16=%4; mov r17=%5; mov r18=%6;" - "mov r2=%1; break 0x1000;; mov %0=r8 ;;" - : "=r" (ret) - : "r" (hypercall.op), - "r" (hypercall.arg[0]), - "r" (hypercall.arg[1]), - "r" (hypercall.arg[2]), - "r" (hypercall.arg[3]), - "r" (hypercall.arg[4]) - : "r14","r15","r16","r17","r18","r2","r8","memory"); + ret = privcmd_hypercall (&hypercall); #endif } break; diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/include/asm-ia64/hypercall.h --- a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h Tue Sep 26 19:11:33 2006 -0600 +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h Thu Sep 28 10:37:56 2006 +0200 @@ -33,11 +33,12 @@ #ifndef __HYPERCALL_H__ #define __HYPERCALL_H__ -#include /* memcpy() */ - #ifndef __HYPERVISOR_H__ # error "please don't include this file directly" #endif + +#include +struct xencomm_handle; /* * Assembler stubs for hyper-calls. @@ -157,157 +158,105 @@ (type)__res; \ }) -static inline int -HYPERVISOR_sched_op_compat( - int cmd, unsigned long arg) -{ - return _hypercall2(int, sched_op_compat, cmd, arg); -} - -static inline int -HYPERVISOR_sched_op( - int cmd, void *arg) + +static inline int +xencomm_arch_hypercall_sched_op(int cmd, struct xencomm_handle *arg) { return _hypercall2(int, sched_op, cmd, arg); } static inline long -HYPERVISOR_set_timer_op( - u64 timeout) -{ - unsigned long timeout_hi = (unsigned long)(timeout>>32); - unsigned long timeout_lo = (unsigned long)timeout; - return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); -} - -static inline int -HYPERVISOR_dom0_op( - dom0_op_t *dom0_op) -{ - dom0_op->interface_version = DOM0_INTERFACE_VERSION; - return _hypercall1(int, dom0_op, dom0_op); -} - -static inline int -HYPERVISOR_multicall( - void *call_list, int nr_calls) -{ - return _hypercall2(int, multicall, call_list, nr_calls); -} - -//XXX xen/ia64 copy_from_guest() is broken. -// This is a temporal work around until it is fixed. -static inline int -____HYPERVISOR_memory_op( - unsigned int cmd, void *arg) -{ - return _hypercall2(int, memory_op, cmd, arg); -} - -#include -#ifdef CONFIG_VMX_GUEST -# define ia64_xenmem_reservation_op(op, xmr) (0) -#else -int ia64_xenmem_reservation_op(unsigned long op, - struct xen_memory_reservation* reservation__); -#endif -static inline int -HYPERVISOR_memory_op( - unsigned int cmd, void *arg) -{ - switch (cmd) { - case XENMEM_increase_reservation: - case XENMEM_decrease_reservation: - case XENMEM_populate_physmap: - return ia64_xenmem_reservation_op(cmd, - (struct xen_memory_reservation*)arg); - default: - return ____HYPERVISOR_memory_op(cmd, arg); - } - /* NOTREACHED */ -} - -static inline int -HYPERVISOR_event_channel_op( - int cmd, void *arg) -{ - int rc = _hypercall2(int, event_channel_op, cmd, arg); - if (unlikely(rc == -ENOSYS)) { - struct evtchn_op op; - op.cmd = cmd; - memcpy(&op.u, arg, sizeof(op.u)); - rc = _hypercall1(int, event_channel_op_compat, &op); - } - return rc; -} - -static inline int -HYPERVISOR_acm_op( - unsigned int cmd, void *arg) -{ - return _hypercall2(int, acm_op, cmd, arg); -} - -static inline int -HYPERVISOR_xen_version( - int cmd, void *arg) -{ - return _hypercall2(int, xen_version, cmd, arg); -} - -static inline int -HYPERVISOR_console_io( - int cmd, int count, char *str) -{ - return _hypercall3(int, console_io, cmd, count, str); -} - -static inline int -HYPERVISOR_physdev_op( - int cmd, void *arg) -{ - int rc = _hypercall2(int, physdev_op, cmd, arg); - if (unlikely(rc == -ENOSYS)) { - struct physdev_op op; - op.cmd = cmd; - memcpy(&op.u, arg, sizeof(op.u)); - rc = _hypercall1(int, physdev_op_compat, &op); - } - return rc; -} - -//XXX __HYPERVISOR_grant_table_op is used for this hypercall constant. -static inline int -____HYPERVISOR_grant_table_op( - unsigned int cmd, void *uop, unsigned int count, - unsigned long pa1, unsigned long pa2) -{ - return _hypercall5(int, grant_table_op, cmd, uop, count, pa1, pa2); +HYPERVISOR_set_timer_op(u64 timeout) +{ + unsigned long timeout_hi = (unsigned long)(timeout>>32); + unsigned long timeout_lo = (unsigned long)timeout; + return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); +} + +static inline int +xencomm_arch_hypercall_dom0_op(struct xencomm_handle *op) +{ + return _hypercall1(int, dom0_op, op); +} + +static inline int +xencomm_arch_hypercall_sysctl(struct xencomm_handle *op) +{ + return _hypercall1(int, sysctl, op); +} + +static inline int +xencomm_arch_hypercall_domctl(struct xencomm_handle *op) +{ + return _hypercall1(int, domctl, op); +} + +static inline int +xencomm_arch_hypercall_multicall(struct xencomm_handle *call_list, + int nr_calls) +{ + return _hypercall2(int, multicall, call_list, nr_calls); +} + +static inline int +xencomm_arch_hypercall_memory_op(unsigned int cmd, struct xencomm_handle *arg) +{ + return _hypercall2(int, memory_op, cmd, arg); +} + +static inline int +xencomm_arch_hypercall_event_channel_op(int cmd, struct xencomm_handle *arg) +{ + return _hypercall2(int, event_channel_op, cmd, arg); +} + +static inline int +xencomm_arch_hypercall_acm_op(unsigned int cmd, struct xencomm_handle *arg) +{ + return _hypercall2(int, acm_op, cmd, arg); +} + +static inline int +xencomm_arch_hypercall_xen_version(int cmd, struct xencomm_handle *arg) +{ + return _hypercall2(int, xen_version, cmd, arg); +} + +static inline int +xencomm_arch_hypercall_console_io(int cmd, int count, + struct xencomm_handle *str) +{ + return _hypercall3(int, console_io, cmd, count, str); +} + +static inline int +xencomm_arch_hypercall_physdev_op(int cmd, struct xencomm_handle *arg) +{ + return _hypercall2(int, physdev_op, cmd, arg); +} + +static inline int +xencomm_arch_hypercall_grant_table_op(unsigned int cmd, + struct xencomm_handle *uop, + unsigned int count) +{ + return _hypercall3(int, grant_table_op, cmd, uop, count); } int HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count); -static inline int -HYPERVISOR_vcpu_op( - int cmd, int vcpuid, void *extra_args) -{ - return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); -} - extern int HYPERVISOR_suspend(unsigned long srec); -static inline unsigned long -HYPERVISOR_hvm_op( - int cmd, void *arg) +static inline int +xencomm_arch_hypercall_callback_op(int cmd, struct xencomm_handle *arg) +{ + return _hypercall2(int, callback_op, cmd, arg); +} + +static inline unsigned long +xencomm_arch_hypercall_hvm_op(int cmd, void *arg) { return _hypercall2(unsigned long, hvm_op, cmd, arg); -} - -static inline int -HYPERVISOR_callback_op( - int cmd, void *arg) -{ - return _hypercall2(int, callback_op, cmd, arg); } extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); @@ -420,4 +369,31 @@ HYPERVISOR_add_physmap(unsigned long gpf // for balloon driver #define HYPERVISOR_update_va_mapping(va, new_val, flags) (0) +/* Use xencomm to do hypercalls. */ +#ifdef MODULE +#define HYPERVISOR_sched_op xencomm_mini_hypercall_sched_op +#define HYPERVISOR_event_channel_op xencomm_mini_hypercall_event_channel_op +#define HYPERVISOR_callback_op xencomm_mini_hypercall_callback_op +#define HYPERVISOR_multicall xencomm_mini_hypercall_multicall +#define HYPERVISOR_xen_version xencomm_mini_hypercall_xen_version +#define HYPERVISOR_console_io xencomm_mini_hypercall_console_io +#define HYPERVISOR_physdev_op xencomm_mini_hypercall_physdev_op +#define HYPERVISOR_hvm_op xencomm_mini_hypercall_hvm_op +#ifdef CONFIG_VMX_GUEST +#define HYPERVISOR_memory_op 0 +#else +#define HYPERVISOR_memory_op xencomm_mini_hypercall_memory_op +#endif +#else +#define HYPERVISOR_sched_op xencomm_hypercall_sched_op +#define HYPERVISOR_event_channel_op xencomm_hypercall_event_channel_op +#define HYPERVISOR_callback_op xencomm_hypercall_callback_op +#define HYPERVISOR_multicall xencomm_hypercall_multicall +#define HYPERVISOR_xen_version xencomm_hypercall_xen_version +#define HYPERVISOR_console_io xencomm_hypercall_console_io +#define HYPERVISOR_physdev_op xencomm_hypercall_physdev_op +#define HYPERVISOR_hvm_op xencomm_hypercall_hvm_op +#define HYPERVISOR_memory_op xencomm_hypercall_memory_op +#endif + #endif /* __HYPERCALL_H__ */ diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h --- a/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h Tue Sep 26 19:11:33 2006 -0600 +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h Thu Sep 28 10:37:56 2006 +0200 @@ -75,9 +75,6 @@ HYPERVISOR_yield( { int rc = HYPERVISOR_sched_op(SCHEDOP_yield, NULL); - if (rc == -ENOSYS) - rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0); - return rc; } @@ -86,9 +83,6 @@ HYPERVISOR_block( void) { int rc = HYPERVISOR_sched_op(SCHEDOP_block, NULL); - - if (rc == -ENOSYS) - rc = HYPERVISOR_sched_op_compat(SCHEDOP_block, 0); return rc; } @@ -102,9 +96,6 @@ HYPERVISOR_shutdown( }; int rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown); - - if (rc == -ENOSYS) - rc = HYPERVISOR_sched_op_compat(SCHEDOP_shutdown, reason); return rc; } @@ -122,8 +113,6 @@ HYPERVISOR_poll( set_xen_guest_handle(sched_poll.ports, ports); rc = HYPERVISOR_sched_op(SCHEDOP_poll, &sched_poll); - if (rc == -ENOSYS) - rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0); return rc; } diff -r f34e37d0742d -r e62f8f7fce90 xen/arch/ia64/xen/Makefile --- a/xen/arch/ia64/xen/Makefile Tue Sep 26 19:11:33 2006 -0600 +++ b/xen/arch/ia64/xen/Makefile Thu Sep 28 10:37:56 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 += xencomm.o obj-$(crash_debug) += gdbstub.o diff -r f34e37d0742d -r e62f8f7fce90 xen/arch/ia64/xen/domain.c --- a/xen/arch/ia64/xen/domain.c Tue Sep 26 19:11:33 2006 -0600 +++ b/xen/arch/ia64/xen/domain.c Thu Sep 28 10:37:56 2006 +0200 @@ -46,6 +46,7 @@ #include #include #include +#include unsigned long dom0_size = 512*1024*1024; unsigned long dom0_align = 64*1024*1024; diff -r f34e37d0742d -r e62f8f7fce90 xen/arch/ia64/xen/faults.c --- a/xen/arch/ia64/xen/faults.c Tue Sep 26 19:11:33 2006 -0600 +++ b/xen/arch/ia64/xen/faults.c Thu Sep 28 10:37:56 2006 +0200 @@ -228,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 f34e37d0742d -r e62f8f7fce90 xen/arch/ia64/xen/fw_emul.c --- a/xen/arch/ia64/xen/fw_emul.c Tue Sep 26 19:11:33 2006 -0600 +++ b/xen/arch/ia64/xen/fw_emul.c Thu Sep 28 10:37:56 2006 +0200 @@ -16,7 +16,6 @@ * */ #include -#include #include #include @@ -29,6 +28,7 @@ #include #include #include +#include extern unsigned long running_on_sim; diff -r f34e37d0742d -r e62f8f7fce90 xen/arch/ia64/xen/hypercall.c --- a/xen/arch/ia64/xen/hypercall.c Tue Sep 26 19:11:33 2006 -0600 +++ b/xen/arch/ia64/xen/hypercall.c Thu Sep 28 10:37:56 2006 +0200 @@ -32,7 +32,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); @@ -54,10 +53,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 */ @@ -108,19 +107,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); @@ -133,7 +119,7 @@ xen_hypercall (struct pt_regs *regs) regs->r19); } else regs->r8 = -ENOSYS; - + return IA64_NO_FAULT; } @@ -465,28 +451,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 f34e37d0742d -r e62f8f7fce90 xen/arch/ia64/xen/mm.c --- a/xen/arch/ia64/xen/mm.c Tue Sep 26 19:11:33 2006 -0600 +++ b/xen/arch/ia64/xen/mm.c Thu Sep 28 10:37:56 2006 +0200 @@ -702,6 +702,21 @@ void *domain_mpa_to_imva(struct domain * } #endif +unsigned long xencomm_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) { + printf("%s: called with bad memory address: 0x%lx - iip=%lx\n", + __func__, paddr, vcpu_regs(v)->cr_iip); + return 0; + } + return __va_ul ((pa & _PFN_MASK) | (paddr & ~PAGE_MASK)); +} + /* Allocate a new page for domain and map it to the specified metaphysical address. */ static struct page_info * diff -r f34e37d0742d -r e62f8f7fce90 xen/include/asm-ia64/guest_access.h --- a/xen/include/asm-ia64/guest_access.h Tue Sep 26 19:11:33 2006 -0600 +++ b/xen/include/asm-ia64/guest_access.h Thu Sep 28 10:37:56 2006 +0200 @@ -1,91 +1,107 @@ -/****************************************************************************** - * 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 + * Tristan Gingold */ -#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)) +/* Internal use only: returns 0 in case of bad address. */ +extern unsigned long xencomm_paddr_to_maddr (unsigned long paddr); -#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 f34e37d0742d -r e62f8f7fce90 xen/include/public/arch-ia64.h --- a/xen/include/public/arch-ia64.h Tue Sep 26 19:11:33 2006 -0600 +++ b/xen/include/public/arch-ia64.h Thu Sep 28 10:37:56 2006 +0200 @@ -435,6 +435,14 @@ struct xen_ia64_boot_param { #define HYPERPRIVOP_GET_PSR 0x19 #define HYPERPRIVOP_MAX 0x19 +/* Xencomm macros. */ +#define XENCOMM_INLINE_MASK 0xf800000000000000UL +#define XENCOMM_INLINE_FLAG 0x8000000000000000UL + +#define XENCOMM_IS_INLINE(addr) \ + (((unsigned long)(addr) & XENCOMM_INLINE_MASK) == XENCOMM_INLINE_FLAG) +#define XENCOMM_INLINE_ADDR(addr) \ + ((unsigned long)(addr) & ~XENCOMM_INLINE_MASK) #endif /* __HYPERVISOR_IF_IA64_H__ */ /* diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c Thu Sep 28 10:37:56 2006 +0200 @@ -0,0 +1,433 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Xencomm notes: + * This file defines hypercalls to be used by xencomm. The hypercalls simply + * create inlines descriptors for pointers and then call the raw arch hypercall + * xencomm_arch_hypercall_XXX + * + * If the arch wants to directly use these hypercalls, simply define macros + * in asm/hypercall.h, eg: + * #define HYPERVISOR_sched_op xencomm_hypercall_sched_op + * + * The arch may also define HYPERVISOR_xxx as a function and do more operations + * before/after doing the hypercall. + * + * Note: because only inline descriptors are created these functions must only + * be called with in kernel memory parameters. + */ + +int xencomm_hypercall_console_io(int cmd, int count, char *str) +{ + return xencomm_arch_hypercall_console_io + (cmd, count, xencomm_create_inline(str)); +} + +int xencomm_hypercall_event_channel_op(int cmd, void *op) +{ + return xencomm_arch_hypercall_event_channel_op + (cmd, xencomm_create_inline(op)); +} + +int xencomm_hypercall_xen_version(int cmd, void *arg) +{ + switch (cmd) { + case XENVER_version: + case XENVER_extraversion: + case XENVER_compile_info: + case XENVER_capabilities: + case XENVER_changeset: + case XENVER_platform_parameters: + case XENVER_pagesize: + case XENVER_get_features: + break; + default: + printk("%s: unknown version cmd %d\n", __func__, cmd); + return -ENOSYS; + } + + return xencomm_arch_hypercall_xen_version + (cmd, xencomm_create_inline(arg)); +} + +int xencomm_hypercall_physdev_op(int cmd, void *op) +{ + return xencomm_arch_hypercall_physdev_op + (cmd, xencomm_create_inline(op)); +} + +static void *xencommize_grant_table_op(unsigned int cmd, void *op, + unsigned int count) +{ + switch (cmd) { + case GNTTABOP_map_grant_ref: + case GNTTABOP_unmap_grant_ref: + break; + case GNTTABOP_setup_table: + { + struct gnttab_setup_table *setup = op; + struct xencomm_handle *frame_list; + + frame_list = xencomm_create_inline + (xen_guest_handle(setup->frame_list)); + + set_xen_guest_handle(setup->frame_list, (void *)frame_list); + break; + } + case GNTTABOP_dump_table: + case GNTTABOP_transfer: + break; + default: + printk("%s: unknown grant table op %d\n", __func__, cmd); + BUG (); + } + + return xencomm_create_inline(op); +} + +int xencomm_hypercall_grant_table_op(unsigned int cmd, void *op, + unsigned int count) +{ + void *desc = xencommize_grant_table_op (cmd, op, count); + + return xencomm_arch_hypercall_grant_table_op(cmd, desc, count); +} + +int xencomm_hypercall_sched_op(int cmd, void *arg) +{ + switch (cmd) { + case SCHEDOP_yield: + case SCHEDOP_block: + case SCHEDOP_shutdown: + case SCHEDOP_poll: + case SCHEDOP_remote_shutdown: + break; + default: + printk("%s: unknown sched op %d\n", __func__, cmd); + return -ENOSYS; + } + + return xencomm_arch_hypercall_sched_op + (cmd, xencomm_create_inline(arg)); +} + +int xencomm_hypercall_multicall(void *call_list, int nr_calls) +{ + int i; + multicall_entry_t *mce; + + for (i = 0; i < nr_calls; i++) { + mce = (multicall_entry_t *)call_list + i; + + switch (mce->op) { + case __HYPERVISOR_update_va_mapping: + case __HYPERVISOR_mmu_update: + /* No-op on ia64. */ + break; + case __HYPERVISOR_grant_table_op: + mce->args[1] = (unsigned long)xencommize_grant_table_op + (mce->args[0], (void *)mce->args[1], + mce->args[2]); + break; + case __HYPERVISOR_memory_op: + default: + printk("%s: unhandled multicall op entry op %lu\n", + __func__, mce->op); + return -ENOSYS; + } + } + + return xencomm_arch_hypercall_multicall + (xencomm_create_inline (call_list), nr_calls); +} + +int xencomm_hypercall_callback_op(int cmd, void *arg) +{ + switch (cmd) + { + case CALLBACKOP_register: + case CALLBACKOP_unregister: + break; + default: + printk("%s: unknown callback op %d\n", __func__, cmd); + return -ENOSYS; + } + + return xencomm_arch_hypercall_callback_op + (cmd, xencomm_create_inline (arg)); +} + +static void xencommize_memory_reservation (xen_memory_reservation_t *mop) +{ + struct xencomm_handle *desc; + + desc = xencomm_create_inline(xen_guest_handle(mop->extent_start)); + set_xen_guest_handle(mop->extent_start, (void *)desc); +} + +int xencomm_hypercall_memory_op(unsigned int cmd, void *arg) +{ + switch (cmd) { + case XENMEM_increase_reservation: + case XENMEM_decrease_reservation: + case XENMEM_populate_physmap: + xencommize_memory_reservation + ((xen_memory_reservation_t *)arg); + break; + + case XENMEM_maximum_ram_page: + break; + + case XENMEM_exchange: + xencommize_memory_reservation + (&((xen_memory_exchange_t *)arg)->in); + xencommize_memory_reservation + (&((xen_memory_exchange_t *)arg)->out); + break; + + default: + printk("%s: unknown memory op %d\n", __func__, cmd); + return -ENOSYS; + } + + return xencomm_arch_hypercall_memory_op + (cmd, xencomm_create_inline(arg)); +} + +unsigned long xencomm_hypercall_hvm_op(int cmd, void *arg) +{ + switch (cmd) { + case HVMOP_set_param: + case HVMOP_get_param: + break; + default: + printk("%s: unknown hvm op %d\n", __func__, cmd); + return -ENOSYS; + } + + return xencomm_arch_hypercall_hvm_op + (cmd, xencomm_create_inline(arg)); +} + + +int xencomm_mini_hypercall_event_channel_op(int cmd, void *op) +{ + struct xencomm_mini xc_area[2]; + int nbr_area = 2; + struct xencomm_handle *desc; + int rc; + + rc = xencomm_create_mini(xc_area, &nbr_area, + op, sizeof(evtchn_op_t), &desc); + if (rc) + return rc; + + return xencomm_arch_hypercall_event_channel_op(cmd, desc); +} +EXPORT_SYMBOL(xencomm_mini_hypercall_event_channel_op); + +static int xencommize_mini_grant_table_op(struct xencomm_mini *xc_area, + int *nbr_area, + unsigned int cmd, void *op, + unsigned int count, + struct xencomm_handle **desc) +{ + struct xencomm_handle *desc1; + unsigned int argsize; + int rc; + + switch (cmd) { + case GNTTABOP_map_grant_ref: + argsize = sizeof(struct gnttab_map_grant_ref); + break; + case GNTTABOP_unmap_grant_ref: + argsize = sizeof(struct gnttab_unmap_grant_ref); + break; + case GNTTABOP_setup_table: + { + struct gnttab_setup_table *setup = op; + + argsize = sizeof(*setup); + + if (count != 1) + return -EINVAL; + rc = xencomm_create_mini + (xc_area, nbr_area, + xen_guest_handle(setup->frame_list), + setup->nr_frames + * sizeof(*xen_guest_handle(setup->frame_list)), + &desc1); + if (rc) + return rc; + set_xen_guest_handle(setup->frame_list, (void *)desc1); + break; + } + case GNTTABOP_dump_table: + argsize = sizeof(struct gnttab_dump_table); + break; + case GNTTABOP_transfer: + argsize = sizeof(struct gnttab_transfer); + break; + default: + printk("%s: unknown mini grant table op %d\n", __func__, cmd); + BUG (); + } + + rc = xencomm_create_mini(xc_area, nbr_area, op, count * argsize, desc); + if (rc) + return rc; + + return 0; +} + +int xencomm_mini_hypercall_grant_table_op(unsigned int cmd, void *op, + unsigned int count) +{ + int rc; + struct xencomm_handle *desc; + int nbr_area = 2; + struct xencomm_mini xc_area[2]; + + rc = xencommize_mini_grant_table_op (xc_area, &nbr_area, + cmd, op, count, &desc); + if (rc) + return rc; + + return xencomm_arch_hypercall_grant_table_op(cmd, desc, count); +} +EXPORT_SYMBOL(xencomm_mini_hypercall_grant_table_op); + +int xencomm_mini_hypercall_multicall(void *call_list, int nr_calls) +{ + int i; + multicall_entry_t *mce; + int nbr_area = 2 + nr_calls * 3; + struct xencomm_mini xc_area[nbr_area]; + struct xencomm_handle *desc; + int rc; + + for (i = 0; i < nr_calls; i++) { + mce = (multicall_entry_t *)call_list + i; + + switch (mce->op) { + case __HYPERVISOR_update_va_mapping: + case __HYPERVISOR_mmu_update: + /* No-op on ia64. */ + break; + case __HYPERVISOR_grant_table_op: + rc = xencommize_mini_grant_table_op + (xc_area, &nbr_area, + mce->args[0], (void *)mce->args[1], + mce->args[2], &desc); + if (rc) + return rc; + mce->args[1] = (unsigned long)desc; + break; + case __HYPERVISOR_memory_op: + default: + printk("%s: unhandled multicall op entry op %lu\n", + __func__, mce->op); + return -ENOSYS; + } + } + + rc = xencomm_create_mini + (xc_area, &nbr_area, + call_list, nr_calls * sizeof(multicall_entry_t), &desc); + if (rc) + return rc; + + return xencomm_arch_hypercall_multicall(desc, nr_calls); +} +EXPORT_SYMBOL(xencomm_mini_hypercall_multicall); + +static int xencommize_mini_memory_reservation (struct xencomm_mini *area, + int *nbr_area, + xen_memory_reservation_t *mop) +{ + struct xencomm_handle *desc; + int rc; + + rc = xencomm_create_mini + (area, nbr_area, + xen_guest_handle(mop->extent_start), + mop->nr_extents + * sizeof(*xen_guest_handle(mop->extent_start)), + &desc); + if (rc) + return rc; + + set_xen_guest_handle(mop->extent_start, (void *)desc); + + return 0; +} + +int xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg) +{ + int nbr_area = 4; + struct xencomm_mini xc_area[4]; + struct xencomm_handle *desc; + int rc; + unsigned int argsize; + + switch (cmd) { + case XENMEM_increase_reservation: + case XENMEM_decrease_reservation: + case XENMEM_populate_physmap: + argsize = sizeof(xen_memory_reservation_t); + rc = xencommize_mini_memory_reservation + (xc_area, &nbr_area, (xen_memory_reservation_t *)arg); + if (rc) + return rc; + break; + + case XENMEM_maximum_ram_page: + argsize = 0; + break; + + case XENMEM_exchange: + argsize = sizeof(xen_memory_exchange_t); + rc = xencommize_mini_memory_reservation + (xc_area, &nbr_area, + &((xen_memory_exchange_t *)arg)->in); + if (rc) + return rc; + rc = xencommize_mini_memory_reservation + (xc_area, &nbr_area, + &((xen_memory_exchange_t *)arg)->out); + if (rc) + return rc; + break; + + default: + printk("%s: unknown mini memory op %d\n", __func__, cmd); + return -ENOSYS; + } + + rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); + if (rc) + return rc; + + return xencomm_arch_hypercall_memory_op(cmd, desc); +} +EXPORT_SYMBOL(xencomm_mini_hypercall_memory_op); diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c Thu Sep 28 10:37:56 2006 +0200 @@ -0,0 +1,461 @@ +#include +#include +#include +#include +#include +#include +#include +#define __XEN__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ROUND_DIV(v,s) (((v) + (s) - 1) / (s)) + +static int xencomm_privcmd_dom0_op(privcmd_hypercall_t *hypercall) +{ + dom0_op_t kern_op; + dom0_op_t __user *user_op = (dom0_op_t __user *)hypercall->arg[0]; + struct xencomm_handle *op_desc; + struct xencomm_handle *desc = NULL; + int ret = 0; + + if (copy_from_user(&kern_op, user_op, sizeof(dom0_op_t))) + return -EFAULT; + + if (kern_op.interface_version != DOM0_INTERFACE_VERSION) + return -EACCES; + + op_desc = xencomm_create_inline(&kern_op); + + switch (kern_op.cmd) { + default: + printk("%s: unknown dom0 cmd %d\n", __func__, kern_op.cmd); + return -ENOSYS; + } + + if (ret) { + /* error mapping the nested pointer */ + return ret; + } + + ret = xencomm_arch_hypercall_dom0_op (op_desc); + + /* FIXME: should we restore the handle? */ + if (copy_to_user(user_op, &kern_op, sizeof(dom0_op_t))) + ret = -EFAULT; + + if (desc) + xencomm_free(desc); + return ret; +} + +static int xencomm_privcmd_sysctl(privcmd_hypercall_t *hypercall) +{ + xen_sysctl_t kern_op; + xen_sysctl_t __user *user_op; + struct xencomm_handle *op_desc; + struct xencomm_handle *desc = NULL; + struct xencomm_handle *desc1 = NULL; + int ret = 0; + + user_op = (xen_sysctl_t __user *)hypercall->arg[0]; + + if (copy_from_user(&kern_op, user_op, sizeof(xen_sysctl_t))) + return -EFAULT; + + if (kern_op.interface_version != XEN_SYSCTL_INTERFACE_VERSION) + return -EACCES; + + op_desc = xencomm_create_inline(&kern_op); + + switch (kern_op.cmd) { + case XEN_SYSCTL_readconsole: + ret = xencomm_create( + xen_guest_handle(kern_op.u.readconsole.buffer), + kern_op.u.readconsole.count, + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.readconsole.buffer, + (void *)desc); + break; + case XEN_SYSCTL_tbuf_op: + case XEN_SYSCTL_physinfo: + case XEN_SYSCTL_sched_id: + break; + case XEN_SYSCTL_perfc_op: + ret = xencomm_create( + xen_guest_handle(kern_op.u.perfc_op.desc), + kern_op.u.perfc_op.nr_counters * + sizeof(xen_sysctl_perfc_desc_t), + &desc, GFP_KERNEL); + if (ret) + return ret; + set_xen_guest_handle(kern_op.u.perfc_op.val, + (void *)desc); + ret = xencomm_create( + xen_guest_handle(kern_op.u.perfc_op.val), + kern_op.u.perfc_op.nr_vals * + sizeof(xen_sysctl_perfc_desc_t), + &desc1, GFP_KERNEL); + if (ret) + xencomm_free(desc); + set_xen_guest_handle(kern_op.u.perfc_op.val, + (void *)desc1); + break; + case XEN_SYSCTL_getdomaininfolist: + ret = xencomm_create( + xen_guest_handle(kern_op.u.getdomaininfolist.buffer), + kern_op.u.getdomaininfolist.max_domains * + sizeof(xen_domctl_getdomaininfo_t), + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.getdomaininfolist.buffer, + (void *)desc); + break; + default: + printk("%s: unknown sysctl cmd %d\n", __func__, kern_op.cmd); + return -ENOSYS; + } + + if (ret) { + /* error mapping the nested pointer */ + return ret; + } + + ret = xencomm_arch_hypercall_sysctl (op_desc); + + /* FIXME: should we restore the handle? */ + if (copy_to_user(user_op, &kern_op, sizeof(xen_sysctl_t))) + ret = -EFAULT; + + if (desc) + xencomm_free(desc); + if (desc1) + xencomm_free(desc1); + return ret; +} + +static int xencomm_privcmd_domctl(privcmd_hypercall_t *hypercall) +{ + xen_domctl_t kern_op; + xen_domctl_t __user *user_op; + struct xencomm_handle *op_desc; + struct xencomm_handle *desc = NULL; + int ret = 0; + + user_op = (xen_domctl_t __user *)hypercall->arg[0]; + + if (copy_from_user(&kern_op, user_op, sizeof(xen_domctl_t))) + return -EFAULT; + + if (kern_op.interface_version != XEN_DOMCTL_INTERFACE_VERSION) + return -EACCES; + + op_desc = xencomm_create_inline(&kern_op); + + switch (kern_op.cmd) { + case XEN_DOMCTL_createdomain: + case XEN_DOMCTL_destroydomain: + case XEN_DOMCTL_pausedomain: + case XEN_DOMCTL_unpausedomain: + case XEN_DOMCTL_getdomaininfo: + break; + case XEN_DOMCTL_getmemlist: + { + unsigned long nr_pages = kern_op.u.getmemlist.max_pfns; +#ifdef __ia64__ + /* FIXME: Xen/ia64 pass first_page and nr_pages in max_pfns! */ + nr_pages &= 0xffffffff; +#endif + ret = xencomm_create( + xen_guest_handle(kern_op.u.getmemlist.buffer), + nr_pages * sizeof(unsigned long), + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.getmemlist.buffer, + (void *)desc); + break; + } + case XEN_DOMCTL_getpageframeinfo: + break; + case XEN_DOMCTL_getpageframeinfo2: + ret = xencomm_create( + xen_guest_handle(kern_op.u.getpageframeinfo2.array), + kern_op.u.getpageframeinfo2.num, + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.getpageframeinfo2.array, + (void *)desc); + break; + case XEN_DOMCTL_shadow_op: + ret = xencomm_create( + xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap), + ROUND_DIV(kern_op.u.shadow_op.pages, 8), + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap, + (void *)desc); + break; + case XEN_DOMCTL_max_mem: + break; + case XEN_DOMCTL_setvcpucontext: + case XEN_DOMCTL_getvcpucontext: + ret = xencomm_create( + xen_guest_handle(kern_op.u.vcpucontext.ctxt), + sizeof(vcpu_guest_context_t), + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.vcpucontext.ctxt, + (void *)desc); + break; + case XEN_DOMCTL_getvcpuinfo: + break; + case XEN_DOMCTL_setvcpuaffinity: + case XEN_DOMCTL_getvcpuaffinity: + ret = xencomm_create( + xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap), + ROUND_DIV(kern_op.u.vcpuaffinity.cpumap.nr_cpus, 8), + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap, + (void *)desc); + break; + case XEN_DOMCTL_max_vcpus: + case XEN_DOMCTL_scheduler_op: + case XEN_DOMCTL_setdomainhandle: + case XEN_DOMCTL_setdebugging: + case XEN_DOMCTL_irq_permission: + case XEN_DOMCTL_iomem_permission: + case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_hypercall_init: + case XEN_DOMCTL_arch_setup: + case XEN_DOMCTL_settimeoffset: + break; + default: + printk("%s: unknown domctl cmd %d\n", __func__, kern_op.cmd); + return -ENOSYS; + } + + if (ret) { + /* error mapping the nested pointer */ + return ret; + } + + ret = xencomm_arch_hypercall_domctl (op_desc); + + /* FIXME: should we restore the handle? */ + if (copy_to_user(user_op, &kern_op, sizeof(xen_domctl_t))) + ret = -EFAULT; + + if (desc) + xencomm_free(desc); + return ret; +} + +static int xencomm_privcmd_acm_op(privcmd_hypercall_t *hypercall) +{ + int cmd = hypercall->arg[0]; + void __user *arg = (void __user *)hypercall->arg[1]; + struct xencomm_handle *op_desc; + struct xencomm_handle *desc = NULL; + int ret; + + switch (cmd) { + case ACMOP_getssid: + { + struct acm_getssid kern_arg; + + if (copy_from_user(&kern_arg, arg, sizeof (kern_arg))) + return -EFAULT; + + op_desc = xencomm_create_inline(&kern_arg); + + ret = xencomm_create(xen_guest_handle(kern_arg.ssidbuf), + kern_arg.ssidbuf_size, + &desc, GFP_KERNEL); + if (ret) + return ret; + + set_xen_guest_handle(kern_arg.ssidbuf, (void *)desc); + + ret = xencomm_arch_hypercall_acm_op(cmd, op_desc); + + xencomm_free(desc); + + if (copy_to_user(arg, &kern_arg, sizeof (kern_arg))) + return -EFAULT; + + return ret; + } + default: + printk("%s: unknown acm_op cmd %d\n", __func__, cmd); + return -ENOSYS; + } + + return ret; +} + +static int xencomm_privcmd_memory_op(privcmd_hypercall_t *hypercall) +{ + const unsigned long cmd = hypercall->arg[0]; + int ret = 0; + + switch (cmd) { + case XENMEM_increase_reservation: + case XENMEM_decrease_reservation: + { + xen_memory_reservation_t kern_op; + xen_memory_reservation_t __user *user_op; + struct xencomm_handle *desc = NULL; + struct xencomm_handle *desc_op; + + user_op = (xen_memory_reservation_t __user *)hypercall->arg[1]; + if (copy_from_user(&kern_op, user_op, + sizeof(xen_memory_reservation_t))) + return -EFAULT; + desc_op = xencomm_create_inline(&kern_op); + + if (xen_guest_handle(kern_op.extent_start)) { + void * addr; + + addr = xen_guest_handle(kern_op.extent_start); + ret = xencomm_create + (addr, + kern_op.nr_extents * + sizeof(*xen_guest_handle + (kern_op.extent_start)), + &desc, GFP_KERNEL); + if (ret) + return ret; + set_xen_guest_handle(kern_op.extent_start, + (void *)desc); + } + + ret = xencomm_arch_hypercall_memory_op(cmd, desc_op); + + if (desc) + xencomm_free(desc); + + if (ret != 0) + return ret; + + if (copy_to_user(user_op, &kern_op, + sizeof(xen_memory_reservation_t))) + return -EFAULT; + + return ret; + } + default: + printk("%s: unknown memory op %lu\n", __func__, cmd); + ret = -ENOSYS; + } + return ret; +} + +static int xencomm_privcmd_xen_version(privcmd_hypercall_t *hypercall) +{ + int cmd = hypercall->arg[0]; + void __user *arg = (void __user *)hypercall->arg[1]; + struct xencomm_handle *desc; + size_t argsize; + int rc; + + switch (cmd) { + case XENVER_version: + /* do not actually pass an argument */ + return xencomm_arch_hypercall_xen_version(cmd, 0); + case XENVER_extraversion: + argsize = sizeof(xen_extraversion_t); + break; + case XENVER_compile_info: + argsize = sizeof(xen_compile_info_t); + break; + case XENVER_capabilities: + argsize = sizeof(xen_capabilities_info_t); + break; + case XENVER_changeset: + argsize = sizeof(xen_changeset_info_t); + break; + case XENVER_platform_parameters: + argsize = sizeof(xen_platform_parameters_t); + break; + case XENVER_pagesize: + argsize = (arg == NULL) ? 0 : sizeof(void *); + break; + case XENVER_get_features: + argsize = (arg == NULL) ? 0 : sizeof(xen_feature_info_t); + break; + + default: + printk("%s: unknown version op %d\n", __func__, cmd); + return -ENOSYS; + } + + rc = xencomm_create(arg, argsize, &desc, GFP_KERNEL); + if (rc) + return rc; + + rc = xencomm_arch_hypercall_xen_version(cmd, desc); + + xencomm_free(desc); + + return rc; +} + +static int xencomm_privcmd_event_channel_op(privcmd_hypercall_t *hypercall) +{ + int cmd = hypercall->arg[0]; + struct xencomm_handle *desc; + unsigned int argsize; + int ret; + + switch (cmd) { + case EVTCHNOP_alloc_unbound: + argsize = sizeof(evtchn_alloc_unbound_t); + break; + + case EVTCHNOP_status: + argsize = sizeof(evtchn_status_t); + break; + + default: + printk("%s: unknown EVTCHNOP %d\n", __func__, cmd); + return -EINVAL; + } + + ret = xencomm_create((void *)hypercall->arg[1], argsize, + &desc, GFP_KERNEL); + if (ret) + return ret; + + ret = xencomm_arch_hypercall_event_channel_op(cmd, desc); + + xencomm_free(desc); + return ret; +} + +int privcmd_hypercall(privcmd_hypercall_t *hypercall) +{ + switch (hypercall->op) { + case __HYPERVISOR_dom0_op: + return xencomm_privcmd_dom0_op(hypercall); + case __HYPERVISOR_domctl: + return xencomm_privcmd_domctl(hypercall); + case __HYPERVISOR_sysctl: + return xencomm_privcmd_sysctl(hypercall); + case __HYPERVISOR_acm_op: + return xencomm_privcmd_acm_op(hypercall); + case __HYPERVISOR_xen_version: + return xencomm_privcmd_xen_version(hypercall); + case __HYPERVISOR_memory_op: + return xencomm_privcmd_memory_op(hypercall); + case __HYPERVISOR_event_channel_op: + return xencomm_privcmd_event_channel_op(hypercall); + default: + printk("%s: unknown hcall (%ld)\n", __func__, hypercall->op); + return -ENOSYS; + } +} + diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/arch/ia64/xen/xencomm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xencomm.c Thu Sep 28 10:37:56 2006 +0200 @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2006 Hollis Blanchard , IBM Corporation + * + * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +static int xencomm_debug = 0; + +/* Translate virtual address to physical address. */ +unsigned long xencomm_vaddr_to_paddr(unsigned long vaddr) +{ + struct page *page; + struct vm_area_struct *vma; + + if (vaddr == 0) + return 0; + +#ifdef __ia64__ + if (REGION_NUMBER(vaddr) == 5) { + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *ptep; + + /* On ia64, TASK_SIZE refers to current. It is not initialized + during boot. + Furthermore the kernel is relocatable and __pa() doesn't + work on addresses. */ + if (vaddr >= KERNEL_START + && vaddr < (KERNEL_START + KERNEL_TR_PAGE_SIZE)) { + extern unsigned long kernel_start_pa; + + return vaddr - kernel_start_pa; + } + + /* In kernel area -- virtually mapped. */ + pgd = pgd_offset_k(vaddr); + if (pgd_none(*pgd) || pgd_bad(*pgd)) + return ~0UL; + + pud = pud_offset(pgd, vaddr); + if (pud_none(*pud) || pud_bad(*pud)) + return ~0UL; + + pmd = pmd_offset(pud, vaddr); + if (pmd_none(*pmd) || pmd_bad(*pmd)) + return ~0UL; + + ptep = pte_offset_kernel(pmd, vaddr); + if (!ptep) + return ~0UL; + + return (pte_val(*ptep) & _PFN_MASK) | (vaddr & ~PAGE_MASK); + } +#endif + + if (vaddr > TASK_SIZE) { + /* kernel address */ + return __pa(vaddr); + } + + /* XXX double-check (lack of) locking */ + vma = find_extend_vma(current->mm, vaddr); + if (!vma) + return ~0UL; + + /* We assume the page is modified. */ + page = follow_page(vma, vaddr, FOLL_WRITE | FOLL_TOUCH); + if (!page) + return ~0UL; + + return (page_to_pfn(page) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK); +} + +static int xencomm_init(struct xencomm_desc *desc, + void *buffer, unsigned long bytes) +{ + unsigned long recorded = 0; + int i = 0; + + BUG_ON((buffer == NULL) && (bytes > 0)); + + /* record the physical pages used */ + if (buffer == NULL) + desc->nr_addrs = 0; + + while ((recorded < bytes) && (i < desc->nr_addrs)) { + unsigned long vaddr = (unsigned long)buffer + recorded; + unsigned long paddr; + int offset; + int chunksz; + + offset = vaddr % PAGE_SIZE; /* handle partial pages */ + chunksz = min(PAGE_SIZE - offset, bytes - recorded); + + paddr = xencomm_vaddr_to_paddr(vaddr); + if (paddr == ~0UL) { + printk("%s: couldn't translate vaddr %lx\n", + __func__, vaddr); + return -EINVAL; + } + + desc->address[i++] = paddr; + recorded += chunksz; + } + + if (recorded < bytes) { + printk("%s: could only translate %ld of %ld bytes\n", + __func__, recorded, bytes); + return -ENOSPC; + } + + /* mark remaining addresses invalid (just for safety) */ + while (i < desc->nr_addrs) + desc->address[i++] = XENCOMM_INVALID; + + desc->magic = XENCOMM_MAGIC; + + return 0; +} + +static struct xencomm_desc *xencomm_alloc(gfp_t gfp_mask) +{ + struct xencomm_desc *desc; + + desc = (struct xencomm_desc *)__get_free_page(gfp_mask); + if (desc == NULL) { + panic("%s: page allocation failed\n", __func__); + } + desc->nr_addrs = (PAGE_SIZE - sizeof(struct xencomm_desc)) / + sizeof(*desc->address); + + return desc; +} + +void xencomm_free(struct xencomm_handle *desc) +{ + if (desc) + free_page((unsigned long)__va(desc)); +} + +int xencomm_create(void *buffer, unsigned long bytes, + struct xencomm_handle **ret, gfp_t gfp_mask) +{ + struct xencomm_desc *desc; + struct xencomm_handle *handle; + int rc; + + if (xencomm_debug) { + printk("%s: %p[%ld]\n", __func__, buffer, bytes); + } + + if (buffer == NULL || bytes == 0) { + *ret = (struct xencomm_handle *)NULL; + return 0; + } + + desc = xencomm_alloc(gfp_mask); + if (!desc) { + printk("%s failure\n", "xencomm_alloc"); + return -ENOMEM; + } + handle = (struct xencomm_handle *)__pa(desc); + + rc = xencomm_init(desc, buffer, bytes); + if (rc) { + printk("%s failure: %d\n", "xencomm_init", rc); + xencomm_free(handle); + return rc; + } + + *ret = handle; + return 0; +} + +/* "mini" routines, for stack-based communications: */ + +static void *xencomm_alloc_mini(struct xencomm_mini *area, int *nbr_area) +{ + unsigned long base; + unsigned int pageoffset; + + while (*nbr_area >= 0) { + /* Allocate an area. */ + (*nbr_area)--; + + base = (unsigned long)(area + *nbr_area); + pageoffset = base % PAGE_SIZE; + + /* If the area does not cross a page, use it. */ + if ((PAGE_SIZE - pageoffset) >= sizeof(struct xencomm_mini)) { + return &area[*nbr_area]; + } + } + /* No more area. */ + return NULL; +} + +int xencomm_create_mini(struct xencomm_mini *area, int *nbr_area, + void *buffer, unsigned long bytes, + struct xencomm_handle **ret) +{ + struct xencomm_desc *desc; + int rc; + unsigned long res; + + desc = xencomm_alloc_mini(area, nbr_area); + if (!desc) + return -ENOMEM; + desc->nr_addrs = XENCOMM_MINI_ADDRS; + + rc = xencomm_init(desc, buffer, bytes); + if (rc) + return rc; + + res = xencomm_vaddr_to_paddr((unsigned long)desc); + if (res == ~0UL) + return -EINVAL; + + *ret = (struct xencomm_handle*)res; + return 0; +} diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h Thu Sep 28 10:37:56 2006 +0200 @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2006 Tristan Gingold , Bull SAS + * + * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LINUX_XENCOMM_HCALL_H_ +#define _LINUX_XENCOMM_HCALL_H_ + +/* These function creates inline descriptor for the parameters and + calls the corresponding xencomm_arch_hypercall_X. + Architectures should defines HYPERVISOR_xxx as xencomm_hypercall_xxx unless + they want to use their own wrapper. */ +extern int xencomm_hypercall_console_io(int cmd, int count, char *str); + +extern int xencomm_hypercall_event_channel_op(int cmd, void *op); + +extern int xencomm_hypercall_xen_version(int cmd, void *arg); + +extern int xencomm_hypercall_physdev_op(int cmd, void *op); + +extern int xencomm_hypercall_grant_table_op(unsigned int cmd, void *op, + unsigned int count); + +extern int xencomm_hypercall_sched_op(int cmd, void *arg); + +extern int xencomm_hypercall_multicall(void *call_list, int nr_calls); + +extern int xencomm_hypercall_callback_op(int cmd, void *arg); + +extern int xencomm_hypercall_memory_op(unsigned int cmd, void *arg); + +extern unsigned long xencomm_hypercall_hvm_op(int cmd, void *arg); + + +/* Using mini xencomm. */ +extern int xencomm_mini_hypercall_console_io(int cmd, int count, char *str); + +extern int xencomm_mini_hypercall_event_channel_op(int cmd, void *op); + +extern int xencomm_mini_hypercall_xen_version(int cmd, void *arg); + +extern int xencomm_mini_hypercall_physdev_op(int cmd, void *op); + +extern int xencomm_mini_hypercall_grant_table_op(unsigned int cmd, void *op, + unsigned int count); + +extern int xencomm_mini_hypercall_sched_op(int cmd, void *arg); + +extern int xencomm_mini_hypercall_multicall(void *call_list, int nr_calls); + +extern int xencomm_mini_hypercall_callback_op(int cmd, void *arg); + +extern int xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg); + +/* For privcmd. Locally declare argument type to avoid include storm. + Type coherency will be checked within privcmd.c */ +struct privcmd_hypercall; +extern int privcmd_hypercall(struct privcmd_hypercall *hypercall); + +#endif /* _LINUX_XENCOMM_HCALL_H_ */ diff -r f34e37d0742d -r e62f8f7fce90 linux-2.6-xen-sparse/include/asm-ia64/xen/xencomm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/linux-2.6-xen-sparse/include/asm-ia64/xen/xencomm.h Thu Sep 28 10:37:56 2006 +0200 @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2006 Hollis Blanchard , IBM Corporation + * + * 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, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LINUX_XENCOMM_H_ +#define _LINUX_XENCOMM_H_ + +#include + +#define XENCOMM_MINI_ADDRS 3 +struct xencomm_mini { + struct xencomm_desc _desc; + uint64_t address[XENCOMM_MINI_ADDRS]; +}; + +/* To avoid additionnal virt to phys conversion, an opaque structure is + presented. */ +struct xencomm_handle; + +extern int xencomm_create(void *buffer, unsigned long bytes, + struct xencomm_handle **desc, gfp_t type); +extern void xencomm_free(struct xencomm_handle *desc); + +extern int xencomm_create_mini(struct xencomm_mini *area, int *nbr_area, + void *buffer, unsigned long bytes, + struct xencomm_handle **ret); + +/* Translate virtual address to physical address. */ +extern unsigned long xencomm_vaddr_to_paddr(unsigned long vaddr); + +/* Inline version. To be used only on linear space (kernel space). */ +static inline struct xencomm_handle *xencomm_create_inline(void *buffer) +{ + unsigned long paddr; + + paddr = xencomm_vaddr_to_paddr((unsigned long)buffer); + return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG); +} + +#define xen_guest_handle(hnd) ((hnd).p) + +#endif /* _LINUX_XENCOMM_H_ */ diff -r f34e37d0742d -r e62f8f7fce90 xen/arch/ia64/xen/xencomm.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xen/arch/ia64/xen/xencomm.c Thu Sep 28 10:37:56 2006 +0200 @@ -0,0 +1,403 @@ +/* + * 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 + * Tristan Gingold + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +static int xencomm_debug = 1; /* extremely verbose */ +#else +#define xencomm_debug 0 +#endif + +static int +xencomm_copy_chunk_from( + unsigned long to, + unsigned long paddr, + unsigned int len) +{ + unsigned long maddr; + struct page_info *page; + + while ( 1 ) + { + maddr = xencomm_paddr_to_maddr(paddr); + if ( xencomm_debug > 1 ) + printk("%lx[%d] -> %lx\n", maddr, len, to); + if ( maddr == 0 ) + return -EFAULT; + + page = virt_to_page(maddr); + if (get_page(page, current->domain) == 0) + { + if (page_get_owner(page) != current->domain) + { + /* This page might be a page granted by another domain */ + panic_domain(NULL, "copy_from_guest from foreign domain\n"); + } + /* Try again. */ + continue; + } + memcpy((void *)to, (void *)maddr, len); + put_page(page); + return 0; + } +} + +/** + * 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 int bytes; + int res; + + chunksz = PAGE_SIZE - (src_paddr % PAGE_SIZE); + + bytes = min(chunksz, n); + + res = xencomm_copy_chunk_from((unsigned long)to, src_paddr, bytes); + if ( res != 0 ) + return -EFAULT; + 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 int bytes = min(chunksz, n - to_pos); + int res; + + if ( xencomm_debug > 1 ) + printf ("src_paddr=%lx i=%d, skip=%d\n", + src_paddr, i, chunk_skip); + + res = xencomm_copy_chunk_from + ((unsigned long)to + to_pos, src_paddr + chunk_skip, bytes); + if ( res != 0 ) + return -EFAULT; + + from_pos += bytes; + to_pos += bytes; + } + + i++; + } + + return n - to_pos; +} + +static int +xencomm_copy_chunk_to( + unsigned long paddr, + unsigned long from, + unsigned int len) +{ + unsigned long maddr; + struct page_info *page; + + while ( 1 ) + { + maddr = xencomm_paddr_to_maddr(paddr); + if ( xencomm_debug > 1 ) + printk("%lx[%d] -> %lx\n", from, len, maddr); + if ( maddr == 0 ) + return -EFAULT; + + page = virt_to_page(maddr); + if (get_page(page, current->domain) == 0) + { + if (page_get_owner(page) != current->domain) + { + /* This page might be a page granted by another domain */ + panic_domain(NULL, "copy_to_guest to foreign domain\n"); + } + /* Try again. */ + continue; + } + memcpy((void *)maddr, (void *)from, len); + put_page(page); + return 0; + } +} + +/** + * 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 int bytes; + int res; + + chunksz = PAGE_SIZE - (dest_paddr % PAGE_SIZE); + + bytes = min(chunksz, n); + + res = xencomm_copy_chunk_to + (dest_paddr, (unsigned long)from, bytes); + if ( res != 0 ) + return res; + + 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; + dest_paddr += chunk_skip; + + if ( skip == 0 ) + { + unsigned int bytes = min(chunksz, n - from_pos); + int res; + + res = xencomm_copy_chunk_to + (dest_paddr, (unsigned long)from + from_pos, bytes); + if ( res != 0 ) + return res; + + 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); + } +}