Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xen: import arch generic part of xencomm

On xen/ia64 and xen/powerpc hypercall arguments are passed by pseudo
physical address (guest physical address) so that it's necessary to
convert from virtual address into pseudo physical address. The frame
work is called xencomm.
Import arch generic part of xencomm.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

authored by

Isaku Yamahata and committed by
Ingo Molnar
b15993fc 8d3d2106

+351
+1
drivers/xen/Makefile
··· 1 1 obj-y += grant-table.o features.o events.o 2 2 obj-y += xenbus/ 3 + obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
+232
drivers/xen/xencomm.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License as published by 4 + * the Free Software Foundation; either version 2 of the License, or 5 + * (at your option) any later version. 6 + * 7 + * This program is distributed in the hope that it will be useful, 8 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 + * GNU General Public License for more details. 11 + * 12 + * You should have received a copy of the GNU General Public License 13 + * along with this program; if not, write to the Free Software 14 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 + * 16 + * Copyright (C) IBM Corp. 2006 17 + * 18 + * Authors: Hollis Blanchard <hollisb@us.ibm.com> 19 + */ 20 + 21 + #include <linux/gfp.h> 22 + #include <linux/mm.h> 23 + #include <asm/page.h> 24 + #include <xen/xencomm.h> 25 + #include <xen/interface/xen.h> 26 + #ifdef __ia64__ 27 + #include <asm/xen/xencomm.h> /* for is_kern_addr() */ 28 + #endif 29 + 30 + #ifdef HAVE_XEN_PLATFORM_COMPAT_H 31 + #include <xen/platform-compat.h> 32 + #endif 33 + 34 + static int xencomm_init(struct xencomm_desc *desc, 35 + void *buffer, unsigned long bytes) 36 + { 37 + unsigned long recorded = 0; 38 + int i = 0; 39 + 40 + while ((recorded < bytes) && (i < desc->nr_addrs)) { 41 + unsigned long vaddr = (unsigned long)buffer + recorded; 42 + unsigned long paddr; 43 + int offset; 44 + int chunksz; 45 + 46 + offset = vaddr % PAGE_SIZE; /* handle partial pages */ 47 + chunksz = min(PAGE_SIZE - offset, bytes - recorded); 48 + 49 + paddr = xencomm_vtop(vaddr); 50 + if (paddr == ~0UL) { 51 + printk(KERN_DEBUG "%s: couldn't translate vaddr %lx\n", 52 + __func__, vaddr); 53 + return -EINVAL; 54 + } 55 + 56 + desc->address[i++] = paddr; 57 + recorded += chunksz; 58 + } 59 + 60 + if (recorded < bytes) { 61 + printk(KERN_DEBUG 62 + "%s: could only translate %ld of %ld bytes\n", 63 + __func__, recorded, bytes); 64 + return -ENOSPC; 65 + } 66 + 67 + /* mark remaining addresses invalid (just for safety) */ 68 + while (i < desc->nr_addrs) 69 + desc->address[i++] = XENCOMM_INVALID; 70 + 71 + desc->magic = XENCOMM_MAGIC; 72 + 73 + return 0; 74 + } 75 + 76 + static struct xencomm_desc *xencomm_alloc(gfp_t gfp_mask, 77 + void *buffer, unsigned long bytes) 78 + { 79 + struct xencomm_desc *desc; 80 + unsigned long buffer_ulong = (unsigned long)buffer; 81 + unsigned long start = buffer_ulong & PAGE_MASK; 82 + unsigned long end = (buffer_ulong + bytes) | ~PAGE_MASK; 83 + unsigned long nr_addrs = (end - start + 1) >> PAGE_SHIFT; 84 + unsigned long size = sizeof(*desc) + 85 + sizeof(desc->address[0]) * nr_addrs; 86 + 87 + /* 88 + * slab allocator returns at least sizeof(void*) aligned pointer. 89 + * When sizeof(*desc) > sizeof(void*), struct xencomm_desc might 90 + * cross page boundary. 91 + */ 92 + if (sizeof(*desc) > sizeof(void *)) { 93 + unsigned long order = get_order(size); 94 + desc = (struct xencomm_desc *)__get_free_pages(gfp_mask, 95 + order); 96 + if (desc == NULL) 97 + return NULL; 98 + 99 + desc->nr_addrs = 100 + ((PAGE_SIZE << order) - sizeof(struct xencomm_desc)) / 101 + sizeof(*desc->address); 102 + } else { 103 + desc = kmalloc(size, gfp_mask); 104 + if (desc == NULL) 105 + return NULL; 106 + 107 + desc->nr_addrs = nr_addrs; 108 + } 109 + return desc; 110 + } 111 + 112 + void xencomm_free(struct xencomm_handle *desc) 113 + { 114 + if (desc && !((ulong)desc & XENCOMM_INLINE_FLAG)) { 115 + struct xencomm_desc *desc__ = (struct xencomm_desc *)desc; 116 + if (sizeof(*desc__) > sizeof(void *)) { 117 + unsigned long size = sizeof(*desc__) + 118 + sizeof(desc__->address[0]) * desc__->nr_addrs; 119 + unsigned long order = get_order(size); 120 + free_pages((unsigned long)__va(desc), order); 121 + } else 122 + kfree(__va(desc)); 123 + } 124 + } 125 + 126 + static int xencomm_create(void *buffer, unsigned long bytes, 127 + struct xencomm_desc **ret, gfp_t gfp_mask) 128 + { 129 + struct xencomm_desc *desc; 130 + int rc; 131 + 132 + pr_debug("%s: %p[%ld]\n", __func__, buffer, bytes); 133 + 134 + if (bytes == 0) { 135 + /* don't create a descriptor; Xen recognizes NULL. */ 136 + BUG_ON(buffer != NULL); 137 + *ret = NULL; 138 + return 0; 139 + } 140 + 141 + BUG_ON(buffer == NULL); /* 'bytes' is non-zero */ 142 + 143 + desc = xencomm_alloc(gfp_mask, buffer, bytes); 144 + if (!desc) { 145 + printk(KERN_DEBUG "%s failure\n", "xencomm_alloc"); 146 + return -ENOMEM; 147 + } 148 + 149 + rc = xencomm_init(desc, buffer, bytes); 150 + if (rc) { 151 + printk(KERN_DEBUG "%s failure: %d\n", "xencomm_init", rc); 152 + xencomm_free((struct xencomm_handle *)__pa(desc)); 153 + return rc; 154 + } 155 + 156 + *ret = desc; 157 + return 0; 158 + } 159 + 160 + /* check if memory address is within VMALLOC region */ 161 + static int is_phys_contiguous(unsigned long addr) 162 + { 163 + if (!is_kernel_addr(addr)) 164 + return 0; 165 + 166 + return (addr < VMALLOC_START) || (addr >= VMALLOC_END); 167 + } 168 + 169 + static struct xencomm_handle *xencomm_create_inline(void *ptr) 170 + { 171 + unsigned long paddr; 172 + 173 + BUG_ON(!is_phys_contiguous((unsigned long)ptr)); 174 + 175 + paddr = (unsigned long)xencomm_pa(ptr); 176 + BUG_ON(paddr & XENCOMM_INLINE_FLAG); 177 + return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG); 178 + } 179 + 180 + /* "mini" routine, for stack-based communications: */ 181 + static int xencomm_create_mini(void *buffer, 182 + unsigned long bytes, struct xencomm_mini *xc_desc, 183 + struct xencomm_desc **ret) 184 + { 185 + int rc = 0; 186 + struct xencomm_desc *desc; 187 + BUG_ON(((unsigned long)xc_desc) % sizeof(*xc_desc) != 0); 188 + 189 + desc = (void *)xc_desc; 190 + 191 + desc->nr_addrs = XENCOMM_MINI_ADDRS; 192 + 193 + rc = xencomm_init(desc, buffer, bytes); 194 + if (!rc) 195 + *ret = desc; 196 + 197 + return rc; 198 + } 199 + 200 + struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes) 201 + { 202 + int rc; 203 + struct xencomm_desc *desc; 204 + 205 + if (is_phys_contiguous((unsigned long)ptr)) 206 + return xencomm_create_inline(ptr); 207 + 208 + rc = xencomm_create(ptr, bytes, &desc, GFP_KERNEL); 209 + 210 + if (rc || desc == NULL) 211 + return NULL; 212 + 213 + return xencomm_pa(desc); 214 + } 215 + 216 + struct xencomm_handle *__xencomm_map_no_alloc(void *ptr, unsigned long bytes, 217 + struct xencomm_mini *xc_desc) 218 + { 219 + int rc; 220 + struct xencomm_desc *desc = NULL; 221 + 222 + if (is_phys_contiguous((unsigned long)ptr)) 223 + return xencomm_create_inline(ptr); 224 + 225 + rc = xencomm_create_mini(ptr, bytes, xc_desc, 226 + &desc); 227 + 228 + if (rc) 229 + return NULL; 230 + 231 + return xencomm_pa(desc); 232 + }
+41
include/xen/interface/xencomm.h
··· 1 + /* 2 + * Permission is hereby granted, free of charge, to any person obtaining a copy 3 + * of this software and associated documentation files (the "Software"), to 4 + * deal in the Software without restriction, including without limitation the 5 + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 6 + * sell copies of the Software, and to permit persons to whom the Software is 7 + * furnished to do so, subject to the following conditions: 8 + * 9 + * The above copyright notice and this permission notice shall be included in 10 + * all copies or substantial portions of the Software. 11 + * 12 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 18 + * DEALINGS IN THE SOFTWARE. 19 + * 20 + * Copyright (C) IBM Corp. 2006 21 + */ 22 + 23 + #ifndef _XEN_XENCOMM_H_ 24 + #define _XEN_XENCOMM_H_ 25 + 26 + /* A xencomm descriptor is a scatter/gather list containing physical 27 + * addresses corresponding to a virtually contiguous memory area. The 28 + * hypervisor translates these physical addresses to machine addresses to copy 29 + * to and from the virtually contiguous area. 30 + */ 31 + 32 + #define XENCOMM_MAGIC 0x58434F4D /* 'XCOM' */ 33 + #define XENCOMM_INVALID (~0UL) 34 + 35 + struct xencomm_desc { 36 + uint32_t magic; 37 + uint32_t nr_addrs; /* the number of entries in address[] */ 38 + uint64_t address[0]; 39 + }; 40 + 41 + #endif /* _XEN_XENCOMM_H_ */
+77
include/xen/xencomm.h
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify 3 + * it under the terms of the GNU General Public License as published by 4 + * the Free Software Foundation; either version 2 of the License, or 5 + * (at your option) any later version. 6 + * 7 + * This program is distributed in the hope that it will be useful, 8 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 + * GNU General Public License for more details. 11 + * 12 + * You should have received a copy of the GNU General Public License 13 + * along with this program; if not, write to the Free Software 14 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 + * 16 + * Copyright (C) IBM Corp. 2006 17 + * 18 + * Authors: Hollis Blanchard <hollisb@us.ibm.com> 19 + * Jerone Young <jyoung5@us.ibm.com> 20 + */ 21 + 22 + #ifndef _LINUX_XENCOMM_H_ 23 + #define _LINUX_XENCOMM_H_ 24 + 25 + #include <xen/interface/xencomm.h> 26 + 27 + #define XENCOMM_MINI_ADDRS 3 28 + struct xencomm_mini { 29 + struct xencomm_desc _desc; 30 + uint64_t address[XENCOMM_MINI_ADDRS]; 31 + }; 32 + 33 + /* To avoid additionnal virt to phys conversion, an opaque structure is 34 + presented. */ 35 + struct xencomm_handle; 36 + 37 + extern void xencomm_free(struct xencomm_handle *desc); 38 + extern struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes); 39 + extern struct xencomm_handle *__xencomm_map_no_alloc(void *ptr, 40 + unsigned long bytes, struct xencomm_mini *xc_area); 41 + 42 + #if 0 43 + #define XENCOMM_MINI_ALIGNED(xc_desc, n) \ 44 + struct xencomm_mini xc_desc ## _base[(n)] \ 45 + __attribute__((__aligned__(sizeof(struct xencomm_mini)))); \ 46 + struct xencomm_mini *xc_desc = &xc_desc ## _base[0]; 47 + #else 48 + /* 49 + * gcc bug workaround: 50 + * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16660 51 + * gcc doesn't handle properly stack variable with 52 + * __attribute__((__align__(sizeof(struct xencomm_mini)))) 53 + */ 54 + #define XENCOMM_MINI_ALIGNED(xc_desc, n) \ 55 + unsigned char xc_desc ## _base[((n) + 1 ) * \ 56 + sizeof(struct xencomm_mini)]; \ 57 + struct xencomm_mini *xc_desc = (struct xencomm_mini *) \ 58 + ((unsigned long)xc_desc ## _base + \ 59 + (sizeof(struct xencomm_mini) - \ 60 + ((unsigned long)xc_desc ## _base) % \ 61 + sizeof(struct xencomm_mini))); 62 + #endif 63 + #define xencomm_map_no_alloc(ptr, bytes) \ 64 + ({ XENCOMM_MINI_ALIGNED(xc_desc, 1); \ 65 + __xencomm_map_no_alloc(ptr, bytes, xc_desc); }) 66 + 67 + /* provided by architecture code: */ 68 + extern unsigned long xencomm_vtop(unsigned long vaddr); 69 + 70 + static inline void *xencomm_pa(void *ptr) 71 + { 72 + return (void *)xencomm_vtop((unsigned long)ptr); 73 + } 74 + 75 + #define xen_guest_handle(hnd) ((hnd).p) 76 + 77 + #endif /* _LINUX_XENCOMM_H_ */