diff -r bbf2db4ddf54 arch/powerpc/platforms/xen/gnttab.c --- a/arch/powerpc/platforms/xen/gnttab.c Tue Dec 19 09:22:37 2006 -0500 +++ b/arch/powerpc/platforms/xen/gnttab.c Wed Jan 26 01:06:39 2028 -0600 @@ -263,8 +263,10 @@ int HYPERVISOR_grant_table_op(unsigned i memcpy(&setup, op, sizeof(setup)); argsize = sizeof(setup); - frame_list = xencomm_create_inline( - xen_guest_handle(setup.frame_list)); + frame_list = xencomm_map( + xen_guest_handle(setup.frame_list), + (sizeof(*xen_guest_handle(setup.frame_list)) + * setup.nr_frames)); set_xen_guest_handle(setup.frame_list, frame_list); memcpy(op, &setup, sizeof(setup)); @@ -286,7 +288,7 @@ int HYPERVISOR_grant_table_op(unsigned i return -ENOSYS; } - desc = xencomm_create_inline(op); + desc = xencomm_map_early(op, argsize); ret = plpar_hcall_norets(XEN_MARK(__HYPERVISOR_grant_table_op), cmd, desc, count); diff -r bbf2db4ddf54 arch/powerpc/platforms/xen/hcall.c --- a/arch/powerpc/platforms/xen/hcall.c Tue Dec 19 09:22:37 2006 -0500 +++ b/arch/powerpc/platforms/xen/hcall.c Wed Jan 26 02:53:15 2028 -0600 @@ -54,7 +54,7 @@ int HYPERVISOR_console_io(int cmd, int count, char *str) { - void *desc = xencomm_create_inline(str); + void *desc = xencomm_map_early(str, count); return plpar_hcall_norets(XEN_MARK(__HYPERVISOR_console_io), cmd, count, desc); @@ -63,14 +63,14 @@ EXPORT_SYMBOL(HYPERVISOR_console_io); int HYPERVISOR_event_channel_op(int cmd, void *op) { - void *desc = xencomm_create_inline(op); + void *desc = xencomm_map_early(op, sizeof(evtchn_op_t)); return plpar_hcall_norets(XEN_MARK(__HYPERVISOR_event_channel_op), cmd, desc); } EXPORT_SYMBOL(HYPERVISOR_event_channel_op); -int HYPERVISOR_xen_version_userspace(int cmd, void *arg) +int HYPERVISOR_xen_version(int cmd, void *arg) { struct xencomm_desc *desc; const unsigned long hcall = __HYPERVISOR_xen_version; @@ -107,29 +107,20 @@ int HYPERVISOR_xen_version_userspace(int return -ENOSYS; } - rc = xencomm_create(arg, argsize, &desc, GFP_KERNEL); - if (rc) - return rc; - - rc = plpar_hcall_norets(XEN_MARK(hcall), cmd, xencomm_pa(desc)); - - xencomm_free(desc); + desc = xencomm_map_early(arg, argsize); + if (desc == NULL) + return -1; + + rc = plpar_hcall_norets(XEN_MARK(hcall), cmd, desc); + return rc; } EXPORT_SYMBOL(HYPERVISOR_xen_version); -int HYPERVISOR_xen_version(int cmd, void *arg) -{ - if (is_kernel_addr((unsigned long)arg)) { - void *desc = xencomm_create_inline(arg); - return plpar_hcall_norets(XEN_MARK(__HYPERVISOR_xen_version), cmd, desc); - } - return HYPERVISOR_xen_version_userspace(cmd, arg); -} int HYPERVISOR_physdev_op(int cmd, void *op) { - void *desc = xencomm_create_inline(op); + void *desc = xencomm_map_early(op, sizeof(physdev_op_t)); return plpar_hcall_norets(XEN_MARK(__HYPERVISOR_physdev_op), cmd, desc); @@ -138,6 +129,7 @@ EXPORT_SYMBOL(HYPERVISOR_physdev_op); int HYPERVISOR_sched_op(int cmd, void *arg) { + int argsize = 0; struct xencomm_desc *desc; switch (cmd) { @@ -151,24 +143,30 @@ int HYPERVISOR_sched_op(int cmd, void *a evtchn_port_t *ports; struct sched_poll sched_poll; + argsize = sizeof(struct sched_poll); + memcpy(&sched_poll, arg, sizeof(sched_poll)); - ports = xencomm_create_inline( - xen_guest_handle(sched_poll.ports)); + ports = xencomm_map( + xen_guest_handle(sched_poll.ports), + (sizeof(evtchn_port_t) * sched_poll.nr_ports)); set_xen_guest_handle(sched_poll.ports, ports); memcpy(arg, &sched_poll, sizeof(sched_poll)); } break; case SCHEDOP_shutdown: + argsize = sizeof(struct sched_shutdown); + break; case SCHEDOP_remote_shutdown: + argsize = sizeof(struct sched_remote_shutdown); break; default: printk(KERN_ERR "%s: unknown sched op %d\n", __func__, cmd); return -ENOSYS; } - desc = xencomm_create_inline(arg); + desc = xencomm_map_early(arg, argsize); return plpar_hcall_norets(XEN_MARK(__HYPERVISOR_sched_op), cmd, desc); @@ -234,7 +232,7 @@ static int xenppc_privcmd_domctl(privcmd xen_domctl_t kern_op; xen_domctl_t __user *user_op = (xen_domctl_t __user *)hypercall->arg[0]; struct xencomm_desc *op_desc; - struct xencomm_desc *desc = NULL; + void *desc = NULL; int ret = 0; if (copy_from_user(&kern_op, user_op, sizeof(xen_domctl_t))) @@ -246,9 +244,9 @@ static int xenppc_privcmd_domctl(privcmd return -EACCES; } - ret = xencomm_create(&kern_op, sizeof(xen_domctl_t), &op_desc, GFP_KERNEL); - if (ret) - return ret; + op_desc = xencomm_map(&kern_op, sizeof(xen_domctl_t)); + if (op_desc) + return -1; switch (kern_op.cmd) { case XEN_DOMCTL_createdomain: @@ -258,52 +256,67 @@ static int xenppc_privcmd_domctl(privcmd case XEN_DOMCTL_getdomaininfo: break; case XEN_DOMCTL_getmemlist: - ret = xencomm_create( + desc = xencomm_map( xen_guest_handle(kern_op.u.getmemlist.buffer), - kern_op.u.getmemlist.max_pfns * sizeof(unsigned long), - &desc, GFP_KERNEL); + kern_op.u.getmemlist.max_pfns * sizeof(unsigned long)); + + if (desc == NULL) + ret = -1; + set_xen_guest_handle(kern_op.u.getmemlist.buffer, - xencomm_pa(desc)); + desc); break; case XEN_DOMCTL_getpageframeinfo: break; case XEN_DOMCTL_getpageframeinfo2: - ret = xencomm_create( + desc = xencomm_map( xen_guest_handle(kern_op.u.getpageframeinfo2.array), - kern_op.u.getpageframeinfo2.num, - &desc, GFP_KERNEL); + kern_op.u.getpageframeinfo2.num); + + if (desc == NULL) + ret = -1; + set_xen_guest_handle(kern_op.u.getpageframeinfo2.array, - xencomm_pa(desc)); + desc); break; case XEN_DOMCTL_shadow_op: - ret = xencomm_create( + desc = xencomm_map( xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap), - kern_op.u.shadow_op.pages * sizeof(unsigned long), - &desc, GFP_KERNEL); + kern_op.u.shadow_op.pages * sizeof(unsigned long)); + + if (desc == NULL) + ret = -1; + set_xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap, - xencomm_pa(desc)); + desc); break; case XEN_DOMCTL_max_mem: break; case XEN_DOMCTL_setvcpucontext: case XEN_DOMCTL_getvcpucontext: - ret = xencomm_create( + desc = xencomm_map( xen_guest_handle(kern_op.u.vcpucontext.ctxt), - sizeof(vcpu_guest_context_t), - &desc, GFP_KERNEL); + sizeof(vcpu_guest_context_t)); + + if (desc == NULL) + ret = -1; + set_xen_guest_handle(kern_op.u.vcpucontext.ctxt, - xencomm_pa(desc)); + desc); break; case XEN_DOMCTL_getvcpuinfo: break; case XEN_DOMCTL_setvcpuaffinity: case XEN_DOMCTL_getvcpuaffinity: - ret = xencomm_create( + desc = xencomm_map( xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap), - (kern_op.u.vcpuaffinity.cpumap.nr_cpus + 7) / 8, - &desc, GFP_KERNEL); + (kern_op.u.vcpuaffinity.cpumap.nr_cpus + 7) / 8); + + if (desc == NULL) + ret = -1; + set_xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap, - xencomm_pa(desc)); + desc); break; case XEN_DOMCTL_max_vcpus: case XEN_DOMCTL_scheduler_op: @@ -325,7 +338,7 @@ static int xenppc_privcmd_domctl(privcmd if (ret) goto out; /* error mapping the nested pointer */ - ret = plpar_hcall_norets(XEN_MARK(hypercall->op), xencomm_pa(op_desc)); + ret = plpar_hcall_norets(XEN_MARK(hypercall->op),op_desc); if (copy_to_user(user_op, &kern_op, sizeof(xen_domctl_t))) ret = -EFAULT; @@ -341,7 +354,7 @@ static int xenppc_privcmd_sysctl(privcmd xen_sysctl_t kern_op; xen_sysctl_t __user *user_op = (xen_sysctl_t __user *)hypercall->arg[0]; struct xencomm_desc *op_desc; - struct xencomm_desc *desc = NULL; + void *desc = NULL; int ret = 0; if (copy_from_user(&kern_op, user_op, sizeof(xen_sysctl_t))) @@ -353,18 +366,20 @@ static int xenppc_privcmd_sysctl(privcmd return -EACCES; } - ret = xencomm_create(&kern_op, sizeof(xen_sysctl_t), &op_desc, GFP_KERNEL); - if (ret) - return ret; + op_desc = xencomm_map(&kern_op, sizeof(xen_sysctl_t)); + if (op_desc == NULL) + return -1; switch (kern_op.cmd) { case XEN_SYSCTL_readconsole: - ret = xencomm_create( + desc = xencomm_map( xen_guest_handle(kern_op.u.readconsole.buffer), - kern_op.u.readconsole.count, - &desc, GFP_KERNEL); + kern_op.u.readconsole.count); + if (desc == NULL) + ret = -1; + set_xen_guest_handle(kern_op.u.readconsole.buffer, - xencomm_pa(desc)); + desc); break; case XEN_SYSCTL_tbuf_op: case XEN_SYSCTL_physinfo: @@ -376,13 +391,16 @@ static int xenppc_privcmd_sysctl(privcmd printk(KERN_ERR "%s: unknown sysctl cmd %d\n", __func__, kern_op.cmd); return -ENOSYS; case XEN_SYSCTL_getdomaininfolist: - ret = xencomm_create( + desc = xencomm_map( xen_guest_handle(kern_op.u.getdomaininfolist.buffer), kern_op.u.getdomaininfolist.max_domains * - sizeof(xen_domctl_getdomaininfo_t), - &desc, GFP_KERNEL); + sizeof(xen_domctl_getdomaininfo_t)); + + if (desc == NULL) + ret = -1; + set_xen_guest_handle(kern_op.u.getdomaininfolist.buffer, - xencomm_pa(desc)); + desc); break; default: printk(KERN_ERR "%s: unknown sysctl cmd %d\n", __func__, kern_op.cmd); @@ -392,7 +410,7 @@ static int xenppc_privcmd_sysctl(privcmd if (ret) goto out; /* error mapping the nested pointer */ - ret = plpar_hcall_norets(XEN_MARK(hypercall->op), xencomm_pa(op_desc)); + ret = plpar_hcall_norets(XEN_MARK(hypercall->op), op_desc); if (copy_to_user(user_op, &kern_op, sizeof(xen_sysctl_t))) ret = -EFAULT; @@ -421,10 +439,9 @@ static int xenppc_privcmd_platform_op(pr return -EACCES; } - ret = xencomm_create(&kern_op, sizeof(xen_platform_op_t), &op_desc, - GFP_KERNEL); - if (ret) - return ret; + op_desc = xencomm_map(&kern_op, sizeof(xen_platform_op_t)); + if (op_desc == NULL) + return -1; switch (kern_op.cmd) { case XENPF_settime: @@ -443,7 +460,7 @@ static int xenppc_privcmd_platform_op(pr if (ret) goto out; /* error mapping the nested pointer */ - ret = plpar_hcall_norets(XEN_MARK(hypercall->op), xencomm_pa(op_desc)); + ret = plpar_hcall_norets(XEN_MARK(hypercall->op), op_desc); if (copy_to_user(user_op, &kern_op, sizeof(xen_platform_op_t))) ret = -EFAULT; @@ -462,32 +479,31 @@ int HYPERVISOR_memory_op(unsigned int cm mop = (xen_memory_reservation_t *)arg; - ret = xencomm_create(mop, sizeof(xen_memory_reservation_t), - &op_desc, GFP_KERNEL); - if (ret) - return ret; + op_desc = xencomm_map(mop, sizeof(xen_memory_reservation_t)); + if (op_desc == NULL) + return -1; switch (cmd) { case XENMEM_increase_reservation: case XENMEM_decrease_reservation: { - struct xencomm_desc *desc = NULL; + void *desc = NULL; if (xen_guest_handle(mop->extent_start)) { - ret = xencomm_create( + desc = xencomm_map( xen_guest_handle(mop->extent_start), mop->nr_extents * - sizeof(*xen_guest_handle(mop->extent_start)), - &desc, GFP_KERNEL); - if (ret) - return ret; + sizeof(*xen_guest_handle(mop->extent_start))); + + if (desc == NULL) + return -1; set_xen_guest_handle(mop->extent_start, - xencomm_pa(desc)); + desc); } ret = plpar_hcall_norets(XEN_MARK(__HYPERVISOR_memory_op), - cmd, xencomm_pa(op_desc)); + cmd, op_desc); xencomm_free(desc); } @@ -556,12 +572,12 @@ static int xenppc_privcmd_event_channel_ return -EINVAL; } - ret = xencomm_create((void *)hypercall->arg[1], argsize, &desc, GFP_KERNEL); - if (ret) - return ret; + desc = xencomm_map((void *)hypercall->arg[1], argsize); + if (desc == NULL) + return -1; ret = plpar_hcall_norets(XEN_MARK(hypercall->op), hypercall->arg[0], - xencomm_pa(desc)); + desc); xencomm_free(desc); return ret; diff -r bbf2db4ddf54 drivers/xen/core/xencomm.c --- a/drivers/xen/core/xencomm.c Tue Dec 19 09:22:37 2006 -0500 +++ b/drivers/xen/core/xencomm.c Wed Jan 26 02:59:31 2028 -0600 @@ -82,11 +82,11 @@ static struct xencomm_desc *xencomm_allo void xencomm_free(struct xencomm_desc *desc) { - if (desc) + if (desc && !((ulong)desc & XENCOMM_INLINE_FLAG)) free_page((unsigned long)desc); } -int xencomm_create(void *buffer, unsigned long bytes, struct xencomm_desc **ret, gfp_t gfp_mask) +static int xencomm_create(void *buffer, unsigned long bytes, struct xencomm_desc **ret, gfp_t gfp_mask) { struct xencomm_desc *desc; int rc; @@ -119,13 +119,68 @@ int xencomm_create(void *buffer, unsigne return 0; } -void *xencomm_create_inline(void *ptr) +static void *xencomm_create_inline(void *ptr) { unsigned long paddr; - BUG_ON(!is_kernel_addr((unsigned long)ptr)); + BUG_ON(!is_phys_contiguous((unsigned long)ptr)); paddr = (unsigned long)xencomm_pa(ptr); BUG_ON(paddr & XENCOMM_INLINE_FLAG); return (void *)(paddr | XENCOMM_INLINE_FLAG); } + +/* "mini" routine, for stack-based communications: */ +static int xencomm_create_mini(int arealen, void *buffer, + unsigned long bytes, struct xencomm_desc **ret) +{ + struct xencomm_desc desc; + int rc = 0; + + desc.nr_addrs = XENCOMM_MINI_ADDRS; + + if (! (rc = xencomm_init(&desc, buffer, bytes))); + *ret = &desc; + + return rc; +} + +void *xencomm_map(void *ptr, unsigned long bytes) +{ + int rc; + struct xencomm_desc *desc; + + if (is_phys_contiguous((unsigned long)ptr)) + return xencomm_create_inline(ptr); + + rc = xencomm_create(ptr, bytes, &desc, GFP_KERNEL); + + if (rc) + return NULL; + + return xencomm_pa(desc); +} + +void *__xencomm_map_early(void *ptr, unsigned long bytes, + struct xencomm_mini *xc_area) +{ + int rc; + struct xencomm_desc *desc = NULL; + + if (is_phys_contiguous((unsigned long)ptr)) + return xencomm_create_inline(ptr); + + rc = xencomm_create_mini(XENCOMM_MINI_AREA,ptr, bytes, + &desc); + + if (rc) + return NULL; + + return (void*)__pa(desc); +} + +/* check if is physically contiguous memory */ +int is_phys_contiguous(unsigned long addr) +{ + return (addr < VMALLOC_START) || (addr >= VMALLOC_END); +} diff -r bbf2db4ddf54 include/xen/xencomm.h --- a/include/xen/xencomm.h Tue Dec 19 09:22:37 2006 -0500 +++ b/include/xen/xencomm.h Wed Jan 26 02:17:31 2028 -0600 @@ -16,6 +16,7 @@ * Copyright (C) IBM Corp. 2006 * * Authors: Hollis Blanchard + * Jerone Young */ #ifndef _LINUX_XENCOMM_H_ @@ -23,10 +24,23 @@ #include -extern int xencomm_create(void *buffer, unsigned long bytes, - struct xencomm_desc **desc, gfp_t type); +#define XENCOMM_MINI_ADDRS 3 +struct xencomm_mini { + struct xencomm_desc _desc; + uint64_t address[XENCOMM_MINI_ADDRS]; +}; +#define XENCOMM_MINI_AREA (sizeof(struct xencomm_mini) * 2) + extern void xencomm_free(struct xencomm_desc *desc); -extern void *xencomm_create_inline(void *ptr); +extern void *xencomm_map(void *ptr, unsigned long bytes); +extern void *__xencomm_map_early(void *ptr, unsigned long bytes, + struct xencomm_mini *xc_area); +extern int is_phys_contiguous(unsigned long addr); + +#define xencomm_map_early(ptr, bytes) \ + ({struct xencomm_mini xc_area\ + __attribute__((__aligned__(sizeof(struct xencomm_mini))));\ + __xencomm_map_early(ptr, bytes, &xc_area);}) /* provided by architecture code: */ extern unsigned long xencomm_vtop(unsigned long vaddr);