# HG changeset patch # User hollisb@xxxxxxxxxxxxxxxxxxx # Node ID 7bdf08c84776c0d0aae262bdc09e48b55addac7f # Parent b358c816a0ca672c1802e4dc4ee4577fb89aca78 Add "xencomm" shared memory area for parameter passing between userspace and hypervisor. Update various comments and whitespace along the way. tools/libxc/xc_domain.c: convert a few hcalls used for domU creation to use new xencomm_alloc() tools/libxc/xc_private.h: remove mlock/munlock from do_dom0_op xen/arch/ppc/hcalls.c: when dom0_op or memory_op hcalls are made, store the xencomm area into 'current' for use by copy_to/from_user() xen/arch/ppc/usercopy.c: adapt copy_to/from_user() to expect virtual addresses in the xencomm area (rather than physical addresses the kernel translated for us) xen/arch/ppc/usercopy.c: remove lots of unused code. Change access_ok() prototype to match x86 access_ok(). diff -r b358c816a0ca -r 7bdf08c84776 tools/domctrl/Makefile --- a/tools/domctrl/Makefile Wed Nov 16 21:10:58 2005 +++ b/tools/domctrl/Makefile Wed Nov 16 22:39:35 2005 @@ -17,6 +17,7 @@ -static OBJS := \ + xencomm_ppc.o \ xc_domain.o \ xc_bvtsched.o \ xc_misc.o \ diff -r b358c816a0ca -r 7bdf08c84776 tools/domctrl/create.c --- a/tools/domctrl/create.c Wed Nov 16 21:10:58 2005 +++ b/tools/domctrl/create.c Wed Nov 16 22:39:35 2005 @@ -97,8 +97,8 @@ static int init_domain(int domid, const char *kernel_path) { - struct load_funcs load_funcs; - struct domain_setup_info dsi; + struct load_funcs load_funcs; + struct domain_setup_info dsi; unsigned long *page_array = NULL; uint8_t *kernel_img = NULL; unsigned long kernel_size; @@ -106,9 +106,9 @@ int rc; int i; - DEBUG(printf("xc_get_tot_pages: ")); + DEBUG(printf("xc_get_tot_pages\n")); nr_pages = xc_get_tot_pages(xc_handle, domid); - DEBUG(printf("0x%x\n", nr_pages)); + DEBUG(printf(" 0x%x\n", nr_pages)); page_array = malloc(nr_pages * sizeof(unsigned long)); if (page_array == NULL) { diff -r b358c816a0ca -r 7bdf08c84776 tools/domctrl/list.c --- a/tools/domctrl/list.c Wed Nov 16 21:10:58 2005 +++ b/tools/domctrl/list.c Wed Nov 16 22:39:35 2005 @@ -17,6 +17,7 @@ int rc; int i; + DEBUG(printf("xc_domain_getinfo\n")); rc = xc_domain_getinfo(xc_handle, 0, max_nr_doms, dominfo); if (rc == -1) { perror("xc_domain_getinfo"); diff -r b358c816a0ca -r 7bdf08c84776 tools/libxc/Makefile --- a/tools/libxc/Makefile Wed Nov 16 21:10:58 2005 +++ b/tools/libxc/Makefile Wed Nov 16 22:39:35 2005 @@ -23,9 +23,11 @@ SRCS += xc_physdev.c SRCS += xc_private.c SRCS += xc_sedf.c +SRCS += xencomm_ppc.c BUILD_SRCS += xc_linux_build.c BUILD_SRCS += xc_load_bin.c BUILD_SRCS += xc_load_elf.c +BUILD_SRCS += xencomm_ppc.c ifeq ($(XEN_TARGET_ARCH),ia64) BUILD_SRCS += xc_ia64_stubs.c diff -r b358c816a0ca -r 7bdf08c84776 tools/libxc/xc_domain.c --- a/tools/libxc/xc_domain.c Wed Nov 16 21:10:58 2005 +++ b/tools/libxc/xc_domain.c Wed Nov 16 22:39:35 2005 @@ -7,6 +7,7 @@ */ #include "xc_private.h" +#include "xencomm.h" #include int xc_domain_create(int xc_handle, @@ -14,15 +15,16 @@ uint32_t *pdomid) { int err; - dom0_op_t op; - - op.cmd = DOM0_CREATEDOMAIN; - op.u.createdomain.domain = (domid_t)*pdomid; - op.u.createdomain.ssidref = ssidref; - if ( (err = do_dom0_op(xc_handle, &op)) != 0 ) + dom0_op_t *op = xencomm_alloc(sizeof(dom0_op_t)); + + op->cmd = DOM0_CREATEDOMAIN; + op->u.createdomain.domain = (domid_t)*pdomid; + op->u.createdomain.ssidref = ssidref; + if ( (err = do_dom0_op(xc_handle, op)) != 0 ) return err; - *pdomid = (uint16_t)op.u.createdomain.domain; + *pdomid = (uint16_t)op->u.createdomain.domain; + xencomm_free(op); return 0; } @@ -77,27 +79,27 @@ { unsigned int nr_doms; uint32_t next_domid = first_domid; - dom0_op_t op; + dom0_op_t *op = xencomm_alloc(sizeof(dom0_op_t)); int rc = 0; memset(info, 0, max_doms*sizeof(xc_dominfo_t)); for ( nr_doms = 0; nr_doms < max_doms; nr_doms++ ) { - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = (domid_t)next_domid; - if ( (rc = do_dom0_op(xc_handle, &op)) < 0 ) + op->cmd = DOM0_GETDOMAININFO; + op->u.getdomaininfo.domain = (domid_t)next_domid; + if ( (rc = do_dom0_op(xc_handle, op)) < 0 ) break; - info->domid = (uint16_t)op.u.getdomaininfo.domain; - - info->dying = !!(op.u.getdomaininfo.flags & DOMFLAGS_DYING); - info->shutdown = !!(op.u.getdomaininfo.flags & DOMFLAGS_SHUTDOWN); - info->paused = !!(op.u.getdomaininfo.flags & DOMFLAGS_PAUSED); - info->blocked = !!(op.u.getdomaininfo.flags & DOMFLAGS_BLOCKED); - info->running = !!(op.u.getdomaininfo.flags & DOMFLAGS_RUNNING); + info->domid = (uint16_t)op->u.getdomaininfo.domain; + + info->dying = !!(op->u.getdomaininfo.flags & DOMFLAGS_DYING); + info->shutdown = !!(op->u.getdomaininfo.flags & DOMFLAGS_SHUTDOWN); + info->paused = !!(op->u.getdomaininfo.flags & DOMFLAGS_PAUSED); + info->blocked = !!(op->u.getdomaininfo.flags & DOMFLAGS_BLOCKED); + info->running = !!(op->u.getdomaininfo.flags & DOMFLAGS_RUNNING); info->shutdown_reason = - (op.u.getdomaininfo.flags>>DOMFLAGS_SHUTDOWNSHIFT) & + (op->u.getdomaininfo.flags>>DOMFLAGS_SHUTDOWNSHIFT) & DOMFLAGS_SHUTDOWNMASK; if ( info->shutdown && (info->shutdown_reason == SHUTDOWN_crash) ) @@ -106,20 +108,22 @@ info->crashed = 1; } - info->ssidref = op.u.getdomaininfo.ssidref; - info->nr_pages = op.u.getdomaininfo.tot_pages; - info->max_memkb = op.u.getdomaininfo.max_pages << (PAGE_SHIFT - 10); - info->shared_info_frame = op.u.getdomaininfo.shared_info_frame; - info->cpu_time = op.u.getdomaininfo.cpu_time; - info->vcpus = op.u.getdomaininfo.n_vcpu; - memcpy(&info->vcpu_to_cpu, &op.u.getdomaininfo.vcpu_to_cpu, + info->ssidref = op->u.getdomaininfo.ssidref; + info->nr_pages = op->u.getdomaininfo.tot_pages; + info->max_memkb = op->u.getdomaininfo.max_pages << (PAGE_SHIFT - 10); + info->shared_info_frame = op->u.getdomaininfo.shared_info_frame; + info->cpu_time = op->u.getdomaininfo.cpu_time; + info->vcpus = op->u.getdomaininfo.n_vcpu; + memcpy(&info->vcpu_to_cpu, &op->u.getdomaininfo.vcpu_to_cpu, sizeof(info->vcpu_to_cpu)); - memcpy(&info->cpumap, &op.u.getdomaininfo.cpumap, + memcpy(&info->cpumap, &op->u.getdomaininfo.cpumap, sizeof(info->cpumap)); - next_domid = (uint16_t)op.u.getdomaininfo.domain + 1; + next_domid = (uint16_t)op->u.getdomaininfo.domain + 1; info++; } + + xencomm_free(op); if( !nr_doms ) return rc; @@ -253,11 +257,15 @@ uint32_t domid, unsigned int max_memkb) { - dom0_op_t op; - op.cmd = DOM0_SETDOMAINMAXMEM; - op.u.setdomainmaxmem.domain = (domid_t)domid; - op.u.setdomainmaxmem.max_memkb = max_memkb; - return do_dom0_op(xc_handle, &op); + dom0_op_t *op = xencomm_alloc(sizeof(dom0_op_t)); + int rc; + + op->cmd = DOM0_SETDOMAINMAXMEM; + op->u.setdomainmaxmem.domain = (domid_t)domid; + op->u.setdomainmaxmem.max_memkb = max_memkb; + rc = do_dom0_op(xc_handle, op); + xencomm_free(op); + return rc; } int xc_domain_memory_increase_reservation(int xc_handle, @@ -268,15 +276,17 @@ unsigned long *extent_start) { int err; - struct xen_memory_reservation reservation = { - .extent_start = extent_start, /* may be NULL */ - .nr_extents = nr_extents, - .extent_order = extent_order, - .address_bits = address_bits, - .domid = domid - }; - - err = xc_memory_op(xc_handle, XENMEM_increase_reservation, &reservation); + struct xen_memory_reservation *reservation; + + reservation = xencomm_alloc(sizeof(struct xen_memory_reservation)); + reservation->extent_start = extent_start; /* may be NULL */ + reservation->nr_extents = nr_extents; + reservation->extent_order = extent_order; + reservation->address_bits = address_bits; + reservation->domid = domid; + + err = xc_memory_op(xc_handle, XENMEM_increase_reservation, reservation); + xencomm_free(reservation); if ( err == nr_extents ) return 0; diff -r b358c816a0ca -r 7bdf08c84776 tools/libxc/xc_private.c --- a/tools/libxc/xc_private.c Wed Nov 16 21:10:58 2005 +++ b/tools/libxc/xc_private.c Wed Nov 16 22:39:35 2005 @@ -5,6 +5,7 @@ */ #include "xc_private.h" +#include "xencomm.h" #include void *xc_map_foreign_batch(int xc_handle, uint32_t dom, int prot, @@ -363,11 +364,20 @@ long xc_get_tot_pages(int xc_handle, uint32_t domid) { - dom0_op_t op; - op.cmd = DOM0_GETDOMAININFO; - op.u.getdomaininfo.domain = (domid_t)domid; - return (do_dom0_op(xc_handle, &op) < 0) ? - -1 : op.u.getdomaininfo.tot_pages; + dom0_op_t *op = xencomm_alloc(sizeof(dom0_op_t)); + long ret; + + op->cmd = DOM0_GETDOMAININFO; + op->u.getdomaininfo.domain = (domid_t)domid; + + if (do_dom0_op(xc_handle, op) < 0) + ret = -1; + else + ret = op->u.getdomaininfo.tot_pages; + + xencomm_free(op); + + return ret; } int xc_copy_to_domain_page(int xc_handle, diff -r b358c816a0ca -r 7bdf08c84776 tools/libxc/xc_private.h --- a/tools/libxc/xc_private.h Wed Nov 16 21:10:58 2005 +++ b/tools/libxc/xc_private.h Wed Nov 16 22:39:35 2005 @@ -80,12 +80,6 @@ hypercall.op = __HYPERVISOR_dom0_op; hypercall.arg[0] = (unsigned long)op; - if ( mlock(op, sizeof(*op)) != 0 ) - { - PERROR("Could not lock memory for Xen hypercall"); - goto out1; - } - if ( (ret = do_xen_hypercall(xc_handle, &hypercall)) < 0 ) { if ( errno == EACCES ) @@ -93,9 +87,6 @@ " rebuild the user-space tool set?\n"); } - safe_munlock(op, sizeof(*op)); - - out1: return ret; } diff -r b358c816a0ca -r 7bdf08c84776 xen/arch/ppc/hcalls.c --- a/xen/arch/ppc/hcalls.c Wed Nov 16 21:10:58 2005 +++ b/xen/arch/ppc/hcalls.c Wed Nov 16 22:39:35 2005 @@ -80,11 +80,23 @@ ulong num = regs->gprs[3]; if ((num & XEN_MARK(0)) == XEN_MARK(0)) { - /* its a Xen call */ + /* it's a Xen call */ + int rc; + num &= ~XEN_MARK(0); + + rc = set_xlate_info(num, regs); + if (rc < 0) { + /* bad xencomm area */ + printf("bad xencomm area\n"); + regs->gprs[3] = rc; + return; + } + hcall_xen(num, regs); + unset_xlate_info(); } else { - /* its a PAPR call */ + /* it's a PAPR call */ hcall_papr(num, regs); } } @@ -101,13 +113,13 @@ } /* store low 32 bits of 64-bit address in hcall table (this is safe because we - * know we will not link above 4GB). */ + * know we will not link above 4GB). We don't need to preserve the TOC + * because that only changes when calling dynamically linked objects. */ static void register_papr_hcall(ulong num, hcall_handler_t handler) { int index = num/4; papr_hcalls[index] = (u32)(*(u64 *)handler); - /* XXX remind me why we don't need to worry about TOC? */ } static void init_papr_hcalls(void) diff -r b358c816a0ca -r 7bdf08c84776 xen/arch/ppc/usercopy.c --- a/xen/arch/ppc/usercopy.c Wed Nov 16 21:10:58 2005 +++ b/xen/arch/ppc/usercopy.c Wed Nov 16 22:39:35 2005 @@ -10,6 +10,46 @@ #include #include #include +#include + +int set_xlate_info(ulong num, struct cpu_user_regs *regs) +{ + ulong *ptr = NULL; + + switch (num) { + case __HYPERVISOR_dom0_op: + ptr = ®s->gprs[4]; + break; + case __HYPERVISOR_memory_op: + ptr = ®s->gprs[5]; + break; + } + + if (ptr) { + struct xencomm *xencomm; + ulong offset; + + xencomm = (struct xencomm *)(*ptr & PAGE_MASK); + offset = *ptr & ~PAGE_MASK; + + /* save machine pointer to xencomm in vcpu */ + current->arch.xencomm = pfn2mfn_addr(xencomm); + if ((current->arch.xencomm->magic != XENCOMM_KERNEL_MAGIC) + || (current->arch.xencomm->bytes == 0)) { + return -EINVAL; + } + + /* convert physical xencomm ptr to virtual data ptr */ + *ptr = current->arch.xencomm->virt_addr + offset; + } + + return 0; +} + +void unset_xlate_info(void) +{ + current->arch.xencomm = NULL; +} void *pfn2mfn_addr(const void __user *paddr) { @@ -25,13 +65,13 @@ pa = pfn2mfn(d, pfn, &mtype); switch (mtype) { - case PFN_TYPE_RMO: - case PFN_TYPE_LOGICAL: - break; - default: - panic("%s: called with bad memory address type: %p\n", - __func__, paddr); - break; + case PFN_TYPE_RMO: + case PFN_TYPE_LOGICAL: + break; + default: + panic("%s: called with bad memory address type: %p\n", + __func__, paddr); + break; } pa <<= PAGE_SHIFT; pa |= offset; @@ -40,36 +80,47 @@ } /** - * copy_from_user: - Copy a block of data from user space. - * @to: Destination (machine) address - * @from: Source (physical) address + * copy_from_user: Copy a block of data from domain space. (misnamed) + * @to: Destination address (machine). + * @from: Source address (virtual). This address must be within a "xencomm" + * area. * @n: Number of bytes to copy. * - * Copy data from kernel space to hypervisor space. + * Copy data from domain space to hypervisor space. * * Returns number of bytes that could not be copied. * On success, this will be zero. - * - * If some data could not be copied, this function will pad the copied - * data to the requested size using zero bytes. */ unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) { - if (access_ok(VERIFY_READ, from, n)) { - from = pfn2mfn_addr(from); - memcpy(to, from, n); + struct xencomm *xencomm = current->arch.xencomm; + const void __user *paddr; + void *maddr; - return 0; + if (!access_ok(from, n)) + return n; + + if (xencomm) { + /* calculate the offset into the xencomm area */ + ulong offset = (ulong)from - xencomm->virt_addr; + /* apply offset to physical address */ + paddr = (const void __user *)(xencomm->phys_addr + offset); + } else { + paddr = from; } - memset(to, 0, n); - return n; + + maddr = pfn2mfn_addr(paddr); + memcpy(to, maddr, n); + + return 0; } /** - * copy_to_user: - Copy a block of data into user space. - * @to: Destination (physical) address. - * @from: Source (machine) address. + * copy_to_user: Copy a block of data to domain space. (misnamed) + * @to: Destination address (virtual). This address must be within a + * "xencomm" area. + * @from: Source address (machine). * @n: Number of bytes to copy. * * Copy data from hypervisor space to kernel space. @@ -80,9 +131,24 @@ unsigned long copy_to_user(void __user *to, const void *from, unsigned long n) { - if (access_ok(VERIFY_WRITE, to, n)) { - to = pfn2mfn_addr(to); - memcpy(to, from, n); + struct xencomm *xencomm = current->arch.xencomm; + const void __user *paddr; + void *maddr; + + if (!access_ok(to, n)) + return n; + + if (xencomm) { + /* calculate the offset into the xencomm area */ + ulong offset = (ulong)to - xencomm->virt_addr; + /* apply offset to physical address */ + paddr = (const void __user *)(xencomm->phys_addr + offset); + } else { + paddr = to; } + + maddr = pfn2mfn_addr(paddr); + memcpy(maddr, from, n); + return 0; } diff -r b358c816a0ca -r 7bdf08c84776 xen/include/asm-ppc/domain.h --- a/xen/include/asm-ppc/domain.h Wed Nov 16 21:10:58 2005 +++ b/xen/include/asm-ppc/domain.h Wed Nov 16 22:39:35 2005 @@ -69,6 +69,8 @@ ulong slb_esid; }; +struct xencomm; + struct arch_vcpu { cpu_user_regs_t ctxt; /* User-level CPU registers */ @@ -95,6 +97,7 @@ u32 dec; struct cpu_vcpu cpu; /* CPU-specific bits */ + struct xencomm *xencomm; int switched; } __cacheline_aligned; diff -r b358c816a0ca -r 7bdf08c84776 xen/include/asm-ppc/uaccess.h --- a/xen/include/asm-ppc/uaccess.h Wed Nov 16 21:10:58 2005 +++ b/xen/include/asm-ppc/uaccess.h Wed Nov 16 22:39:35 2005 @@ -13,39 +13,24 @@ #include #include -#define VERIFY_READ 0 -#define VERIFY_WRITE 1 - -#define __addr_ok(addr) (1) -#define access_ok(type,addr,size) (1) -#define array_access_ok(addr,count,size) (1) - -static inline int verify_area(int type, const void *addr, unsigned long size) +#define XENCOMM_KERNEL_MAGIC 0x0dd1371533333333 +#define XENCOMM_USER_MAGIC 0x0dd1371555555555 +struct xencomm { - return access_ok(type,addr,size) ? 0 : -EFAULT; -} - - -/* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ - -struct exception_table_entry -{ - unsigned long insn, fixup; + uint64_t magic; /* kernel-supplied */ + uint64_t phys_addr; /* kernel-supplied */ + uint64_t virt_addr; /* user-supplied */ + uint32_t bytes; /* user-supplied */ + uint8_t *avail; /* private to userspace allocator */ }; -/* Returns 0 if exception not found and fixup otherwise. */ -extern unsigned long search_exception_table(unsigned long); +extern int set_xlate_info(ulong num, struct cpu_user_regs *regs); +extern void unset_xlate_info(void); + +/* XXX add checking. use current->arch.xencomm->bytes */ +#define __addr_ok(addr) (1UL) +#define access_ok(addr,size) (1UL) +#define array_access_ok(addr,count,size) access_ok(addr,count*size) /* * These are the main single-value transfer routines. They automatically @@ -91,7 +76,7 @@ ({ \ long __pu_err = -EFAULT; \ void *__pu_addr = (ptr); \ - if (access_ok(VERIFY_WRITE,__pu_addr,size)) \ + if (access_ok(__pu_addr,size)) \ __put_user_size((x),__pu_addr,(size),__pu_err,-EFAULT); \ __pu_err; \ }) @@ -196,56 +181,6 @@ return copy_to_user(to, from, n); } -#define __copy_in_user(to, from, size) \ - __copy_tofrom_user((to), (from), (size)) - -extern unsigned long copy_in_user(void *to, const void *from, - unsigned long n); - -extern unsigned long __clear_user(void *addr, unsigned long size); - -#define __copy_to_user_inatomic __copy_to_user -#define __copy_from_user_inatomic __copy_from_user - -static inline unsigned long -clear_user(void *addr, unsigned long size) -{ - if (likely(access_ok(VERIFY_WRITE, addr, size))) - size = __clear_user(addr, size); - return size; -} - -extern int __strncpy_from_user(char *dst, const char *src, long count); - -static inline long -strncpy_from_user(char *dst, const char *src, long count) -{ - if (likely(access_ok(VERIFY_READ, src, 1))) - return __strncpy_from_user(dst, src, count); - return -EFAULT; -} - -/* - * Return the size of a string (including the ending 0) - * - * Return 0 for error - */ -extern int __strnlen_user(const char *str, long len); - -/* - * Returns the length of the string at str (including the null byte), - * or 0 if we hit a page we can't access, - * or something > len if we didn't find a null byte. - */ -static inline int strnlen_user(const char *str, long len) -{ - if (likely(access_ok(VERIFY_READ, str, 1))) - return __strnlen_user(str, len); - return 0; -} - -#define strlen_user(str) strnlen_user((str), 0x7ffffffe) - #endif /* __ASSEMBLY__ */ #endif /* _PPC64_UACCESS_H */ diff -r b358c816a0ca -r 7bdf08c84776 tools/libxc/xencomm.h --- /dev/null Wed Nov 16 21:10:58 2005 +++ b/tools/libxc/xencomm.h Wed Nov 16 22:39:35 2005 @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2005 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 + * + */ + +/* API to allocate memory for hypervisor communication */ + +#ifndef XENCOMM_H +#define XENCOMM_H + +extern void *xencomm_alloc(size_t bytes); +extern void xencomm_free(void *address); + +#endif diff -r b358c816a0ca -r 7bdf08c84776 tools/libxc/xencomm_ppc.c --- /dev/null Wed Nov 16 21:10:58 2005 +++ b/tools/libxc/xencomm_ppc.c Wed Nov 16 22:39:35 2005 @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2005 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 + * + */ + +/* API to allocate memory for hypervisor communication */ + +#include +#include +#include + +#define XENCOMM_KERNEL_MAGIC 0x0dd1371533333333 +#define XENCOMM_USER_MAGIC 0x0dd1371555555555 +struct xencomm +{ + uint64_t magic; /* kernel-supplied */ + uint64_t phys_addr; /* kernel-supplied */ + uint64_t virt_addr; /* user-supplied */ + uint32_t bytes; /* user-supplied */ + uint8_t *avail; /* private to userspace allocator */ +}; + +static struct xencomm *current; + +static int new_xencomm(size_t bytes) +{ + int num_bytes = getpagesize(); + void *page; + + if (bytes > num_bytes) + /* we only handle single-page areas for now */ + return -1; + + page = mmap(NULL, num_bytes, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_LOCKED | MAP_ANONYMOUS, -1, 0); + if (page == MAP_FAILED) + return -1; + + current = page; + current->virt_addr = (uint64_t)current; + current->bytes = num_bytes; + current->avail = ((char *)page) + sizeof(struct xencomm); + + return 0; +} + +static void del_xencomm(void) +{ + munmap(current, current->bytes); + current = NULL; +} + +void *xencomm_alloc(size_t new_bytes) +{ + void *available; + int used_bytes; + + if (current == NULL) { + if (new_xencomm(new_bytes) < 0) + return NULL; + } + + used_bytes = (unsigned long)current->avail - (unsigned long)current; + if ((used_bytes + new_bytes) > current->bytes) + return NULL; + + available = current->avail; + current->avail += new_bytes; + current->magic = XENCOMM_USER_MAGIC; + return available; +} + +void xencomm_free(void *address) +{ + /* first free deletes the whole thing */ + del_xencomm(); +}