aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIsaku Yamahata <yamahata@valinux.co.jp>2008-04-02 13:54:01 -0400
committerIngo Molnar <mingo@elte.hu>2008-04-24 17:57:32 -0400
commitb15993fcc1bf15f717fb4414b32e4a11534dfdc4 (patch)
treec904acfa6b7670e37c8ebd329b3a2dcf71305dfd
parent8d3d2106c19f4e69f208f59fe484ca113fbb48b3 (diff)
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>
-rw-r--r--drivers/xen/Makefile1
-rw-r--r--drivers/xen/xencomm.c232
-rw-r--r--include/xen/interface/xencomm.h41
-rw-r--r--include/xen/xencomm.h77
4 files changed, 351 insertions, 0 deletions
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 823ce788b14b..43f014cfb458 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -1,2 +1,3 @@
1obj-y += grant-table.o features.o events.o 1obj-y += grant-table.o features.o events.o
2obj-y += xenbus/ 2obj-y += xenbus/
3obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
diff --git a/drivers/xen/xencomm.c b/drivers/xen/xencomm.c
new file mode 100644
index 000000000000..797cb4e31f07
--- /dev/null
+++ b/drivers/xen/xencomm.c
@@ -0,0 +1,232 @@
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
34static 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
76static 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
112void 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
126static 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 */
161static 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
169static 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: */
181static 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
200struct 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
216struct 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}
diff --git a/include/xen/interface/xencomm.h b/include/xen/interface/xencomm.h
new file mode 100644
index 000000000000..ac45e0712afa
--- /dev/null
+++ b/include/xen/interface/xencomm.h
@@ -0,0 +1,41 @@
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
35struct 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_ */
diff --git a/include/xen/xencomm.h b/include/xen/xencomm.h
new file mode 100644
index 000000000000..e43b039be112
--- /dev/null
+++ b/include/xen/xencomm.h
@@ -0,0 +1,77 @@
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
28struct 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. */
35struct xencomm_handle;
36
37extern void xencomm_free(struct xencomm_handle *desc);
38extern struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes);
39extern 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: */
68extern unsigned long xencomm_vtop(unsigned long vaddr);
69
70static 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_ */