ia64/xen-unstable

view xen/common/xencomm.c @ 15647:cc48264ed647

Merge
author Tim Deegan <Tim.Deegan@xensource.com>
date Tue Jul 24 14:53:06 2007 +0100 (2007-07-24)
parents 6a53d3abe7f8
children 0d367c186e8c
line source
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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * Copyright (C) IBM Corp. 2006
17 *
18 * Authors: Hollis Blanchard <hollisb@us.ibm.com>
19 * Tristan Gingold <tristan.gingold@bull.net>
20 */
22 #include <xen/config.h>
23 #include <xen/mm.h>
24 #include <xen/sched.h>
25 #include <xen/xencomm.h>
26 #include <public/xen.h>
27 #include <public/xencomm.h>
30 #undef DEBUG
31 #ifdef DEBUG
32 static int xencomm_debug = 1; /* extremely verbose */
33 #else
34 #define xencomm_debug 0
35 #endif
37 static unsigned long
38 xencomm_inline_from_guest(void *to, const void *from, unsigned int n,
39 unsigned int skip)
40 {
41 unsigned long src_paddr = xencomm_inline_addr(from);
43 src_paddr += skip;
45 while (n > 0) {
46 unsigned int chunksz;
47 unsigned long src_maddr;
48 unsigned int bytes;
50 chunksz = PAGE_SIZE - (src_paddr % PAGE_SIZE);
52 bytes = min(chunksz, n);
54 src_maddr = paddr_to_maddr(src_paddr);
55 if (xencomm_debug)
56 printk("%lx[%d] -> %lx\n", src_maddr, bytes, (unsigned long)to);
57 memcpy(to, (void *)src_maddr, bytes);
58 src_paddr += bytes;
59 to += bytes;
60 n -= bytes;
61 }
63 /* Always successful. */
64 return 0;
65 }
67 /**
68 * xencomm_copy_from_guest: Copy a block of data from domain space.
69 * @to: Machine address.
70 * @from: Physical address to a xencomm buffer descriptor.
71 * @n: Number of bytes to copy.
72 * @skip: Number of bytes from the start to skip.
73 *
74 * Copy data from domain to hypervisor.
75 *
76 * Returns number of bytes that could not be copied.
77 * On success, this will be zero.
78 */
79 unsigned long
80 xencomm_copy_from_guest(void *to, const void *from, unsigned int n,
81 unsigned int skip)
82 {
83 struct xencomm_desc *desc;
84 unsigned int from_pos = 0;
85 unsigned int to_pos = 0;
86 unsigned int i = 0;
88 if (xencomm_is_inline(from))
89 return xencomm_inline_from_guest(to, from, n, skip);
91 /* first we need to access the descriptor */
92 desc = (struct xencomm_desc *)paddr_to_maddr((unsigned long)from);
93 if (desc == NULL)
94 return n;
96 if (desc->magic != XENCOMM_MAGIC) {
97 printk("%s: error: %p magic was 0x%x\n",
98 __func__, desc, desc->magic);
99 return n;
100 }
102 /* iterate through the descriptor, copying up to a page at a time */
103 while ((to_pos < n) && (i < desc->nr_addrs)) {
104 unsigned long src_paddr = desc->address[i];
105 unsigned int pgoffset;
106 unsigned int chunksz;
107 unsigned int chunk_skip;
109 if (src_paddr == XENCOMM_INVALID) {
110 i++;
111 continue;
112 }
114 pgoffset = src_paddr % PAGE_SIZE;
115 chunksz = PAGE_SIZE - pgoffset;
117 chunk_skip = min(chunksz, skip);
118 from_pos += chunk_skip;
119 chunksz -= chunk_skip;
120 skip -= chunk_skip;
122 if (skip == 0 && chunksz > 0) {
123 unsigned long src_maddr;
124 unsigned long dest = (unsigned long)to + to_pos;
125 unsigned int bytes = min(chunksz, n - to_pos);
127 src_maddr = paddr_to_maddr(src_paddr + chunk_skip);
128 if (src_maddr == 0)
129 return n - to_pos;
131 if (xencomm_debug)
132 printk("%lx[%d] -> %lx\n", src_maddr, bytes, dest);
133 memcpy((void *)dest, (void *)src_maddr, bytes);
134 from_pos += bytes;
135 to_pos += bytes;
136 }
138 i++;
139 }
141 return n - to_pos;
142 }
144 static unsigned long
145 xencomm_inline_to_guest(void *to, const void *from, unsigned int n,
146 unsigned int skip)
147 {
148 unsigned long dest_paddr = xencomm_inline_addr(to);
150 dest_paddr += skip;
152 while (n > 0) {
153 unsigned int chunksz;
154 unsigned long dest_maddr;
155 unsigned int bytes;
157 chunksz = PAGE_SIZE - (dest_paddr % PAGE_SIZE);
159 bytes = min(chunksz, n);
161 dest_maddr = paddr_to_maddr(dest_paddr);
162 if (xencomm_debug)
163 printk("%lx[%d] -> %lx\n", (unsigned long)from, bytes, dest_maddr);
164 memcpy((void *)dest_maddr, (void *)from, bytes);
165 dest_paddr += bytes;
166 from += bytes;
167 n -= bytes;
168 }
170 /* Always successful. */
171 return 0;
172 }
174 /**
175 * xencomm_copy_to_guest: Copy a block of data to domain space.
176 * @to: Physical address to xencomm buffer descriptor.
177 * @from: Machine address.
178 * @n: Number of bytes to copy.
179 * @skip: Number of bytes from the start to skip.
180 *
181 * Copy data from hypervisor to domain.
182 *
183 * Returns number of bytes that could not be copied.
184 * On success, this will be zero.
185 */
186 unsigned long
187 xencomm_copy_to_guest(void *to, const void *from, unsigned int n,
188 unsigned int skip)
189 {
190 struct xencomm_desc *desc;
191 unsigned int from_pos = 0;
192 unsigned int to_pos = 0;
193 unsigned int i = 0;
195 if (xencomm_is_inline(to))
196 return xencomm_inline_to_guest(to, from, n, skip);
198 /* first we need to access the descriptor */
199 desc = (struct xencomm_desc *)paddr_to_maddr((unsigned long)to);
200 if (desc == NULL)
201 return n;
203 if (desc->magic != XENCOMM_MAGIC) {
204 printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic);
205 return n;
206 }
208 /* iterate through the descriptor, copying up to a page at a time */
209 while ((from_pos < n) && (i < desc->nr_addrs)) {
210 unsigned long dest_paddr = desc->address[i];
211 unsigned int pgoffset;
212 unsigned int chunksz;
213 unsigned int chunk_skip;
215 if (dest_paddr == XENCOMM_INVALID) {
216 i++;
217 continue;
218 }
220 pgoffset = dest_paddr % PAGE_SIZE;
221 chunksz = PAGE_SIZE - pgoffset;
223 chunk_skip = min(chunksz, skip);
224 to_pos += chunk_skip;
225 chunksz -= chunk_skip;
226 skip -= chunk_skip;
228 if (skip == 0 && chunksz > 0) {
229 unsigned long dest_maddr;
230 unsigned long source = (unsigned long)from + from_pos;
231 unsigned int bytes = min(chunksz, n - from_pos);
233 dest_maddr = paddr_to_maddr(dest_paddr + chunk_skip);
234 if (dest_maddr == 0)
235 return -1;
237 if (xencomm_debug)
238 printk("%lx[%d] -> %lx\n", source, bytes, dest_maddr);
239 memcpy((void *)dest_maddr, (void *)source, bytes);
240 from_pos += bytes;
241 to_pos += bytes;
242 }
244 i++;
245 }
247 return n - from_pos;
248 }
250 static int xencomm_inline_add_offset(void **handle, unsigned int bytes)
251 {
252 *handle += bytes;
253 return 0;
254 }
256 /* Offset page addresses in 'handle' to skip 'bytes' bytes. Set completely
257 * exhausted pages to XENCOMM_INVALID. */
258 int xencomm_add_offset(void **handle, unsigned int bytes)
259 {
260 struct xencomm_desc *desc;
261 int i = 0;
263 if (xencomm_is_inline(*handle))
264 return xencomm_inline_add_offset(handle, bytes);
266 /* first we need to access the descriptor */
267 desc = (struct xencomm_desc *)paddr_to_maddr((unsigned long)*handle);
268 if (desc == NULL)
269 return -1;
271 if (desc->magic != XENCOMM_MAGIC) {
272 printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic);
273 return -1;
274 }
276 /* iterate through the descriptor incrementing addresses */
277 while ((bytes > 0) && (i < desc->nr_addrs)) {
278 unsigned long dest_paddr = desc->address[i];
279 unsigned int pgoffset;
280 unsigned int chunksz;
281 unsigned int chunk_skip;
283 pgoffset = dest_paddr % PAGE_SIZE;
284 chunksz = PAGE_SIZE - pgoffset;
286 chunk_skip = min(chunksz, bytes);
287 if (chunk_skip == chunksz) {
288 /* exhausted this page */
289 desc->address[i] = XENCOMM_INVALID;
290 } else {
291 desc->address[i] += chunk_skip;
292 }
293 bytes -= chunk_skip;
294 }
295 return 0;
296 }
298 int xencomm_handle_is_null(void *handle)
299 {
300 struct xencomm_desc *desc;
301 int i;
303 if (xencomm_is_inline(handle))
304 return xencomm_inline_addr(handle) == 0;
306 desc = (struct xencomm_desc *)paddr_to_maddr((unsigned long)handle);
307 if (desc == NULL)
308 return 1;
310 for (i = 0; i < desc->nr_addrs; i++)
311 if (desc->address[i] != XENCOMM_INVALID)
312 return 0;
314 return 1;
315 }