direct-io.hg

view xen/arch/ia64/xen/xencomm.c @ 13457:eb40e07b867f

[IA64] Fix calling xencomm_copy_chunk_{to, from} with len = 0

Originally debugged by Kazuhiro Suzuki

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author awilliam@xenbuild2.aw
date Thu Jan 04 16:10:25 2007 -0700 (2007-01-04)
parents 3713ea43e636
children
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 <asm/current.h>
26 #include <asm/guest_access.h>
27 #include <public/xen.h>
28 #include <public/xencomm.h>
29 #include <xen/errno.h>
31 #undef DEBUG
32 #ifdef DEBUG
33 static int xencomm_debug = 1; /* extremely verbose */
34 #else
35 #define xencomm_debug 0
36 #endif
38 static int
39 xencomm_copy_chunk_from(
40 unsigned long to,
41 unsigned long paddr,
42 unsigned int len)
43 {
44 unsigned long maddr;
45 struct page_info *page;
47 while (1) {
48 maddr = xencomm_paddr_to_maddr(paddr);
49 if (xencomm_debug > 1)
50 printk("%lx[%d] -> %lx\n", maddr, len, to);
51 if (maddr == 0)
52 return -EFAULT;
54 page = virt_to_page(maddr);
55 if (get_page(page, current->domain) == 0) {
56 if (page_get_owner(page) != current->domain) {
57 /* This page might be a page granted by another domain */
58 panic_domain(NULL, "copy_from_guest from foreign domain\n");
59 }
60 /* Try again. */
61 continue;
62 }
63 memcpy((void *)to, (void *)maddr, len);
64 put_page(page);
65 return 0;
66 }
67 }
69 /**
70 * xencomm_copy_from_guest: Copy a block of data from domain space.
71 * @to: Machine address.
72 * @from: Physical address to a xencomm buffer descriptor.
73 * @n: Number of bytes to copy.
74 * @skip: Number of bytes from the start to skip.
75 *
76 * Copy data from domain to hypervisor.
77 *
78 * Returns number of bytes that could not be copied.
79 * On success, this will be zero.
80 */
81 unsigned long
82 xencomm_copy_from_guest(
83 void *to,
84 const void *from,
85 unsigned int n,
86 unsigned int skip)
87 {
88 struct xencomm_desc *desc;
89 unsigned long desc_addr;
90 unsigned int from_pos = 0;
91 unsigned int to_pos = 0;
92 unsigned int i = 0;
94 if (xencomm_debug)
95 printk("xencomm_copy_from_guest: from=%lx+%u n=%u\n",
96 (unsigned long)from, skip, n);
98 if (XENCOMM_IS_INLINE(from)) {
99 unsigned long src_paddr = XENCOMM_INLINE_ADDR(from);
101 src_paddr += skip;
103 while (n > 0) {
104 unsigned int chunksz;
105 unsigned int bytes;
106 int res;
108 chunksz = PAGE_SIZE - (src_paddr % PAGE_SIZE);
110 bytes = min(chunksz, n);
112 res = xencomm_copy_chunk_from((unsigned long)to, src_paddr, bytes);
113 if (res != 0)
114 return -EFAULT;
115 src_paddr += bytes;
116 to += bytes;
117 n -= bytes;
118 }
120 /* Always successful. */
121 return 0;
122 }
124 /* first we need to access the descriptor */
125 desc_addr = xencomm_paddr_to_maddr((unsigned long)from);
126 if (desc_addr == 0)
127 return -EFAULT;
129 desc = (struct xencomm_desc *)desc_addr;
130 if (desc->magic != XENCOMM_MAGIC) {
131 printk("%s: error: %p magic was 0x%x\n",
132 __func__, desc, desc->magic);
133 return -EFAULT;
134 }
136 /* iterate through the descriptor, copying up to a page at a time */
137 while ((to_pos < n) && (i < desc->nr_addrs)) {
138 unsigned long src_paddr = desc->address[i];
139 unsigned int pgoffset;
140 unsigned int chunksz;
141 unsigned int chunk_skip;
143 if (src_paddr == XENCOMM_INVALID) {
144 i++;
145 continue;
146 }
148 pgoffset = src_paddr % PAGE_SIZE;
149 chunksz = PAGE_SIZE - pgoffset;
151 chunk_skip = min(chunksz, skip);
152 from_pos += chunk_skip;
153 chunksz -= chunk_skip;
154 skip -= chunk_skip;
156 if (skip == 0 && chunksz > 0) {
157 unsigned int bytes = min(chunksz, n - to_pos);
158 int res;
160 if (xencomm_debug > 1)
161 printk ("src_paddr=%lx i=%d, skip=%d\n",
162 src_paddr, i, chunk_skip);
164 res = xencomm_copy_chunk_from((unsigned long)to + to_pos,
165 src_paddr + chunk_skip, bytes);
166 if (res != 0)
167 return -EFAULT;
169 from_pos += bytes;
170 to_pos += bytes;
171 }
173 i++;
174 }
176 return n - to_pos;
177 }
179 static int
180 xencomm_copy_chunk_to(
181 unsigned long paddr,
182 unsigned long from,
183 unsigned int len)
184 {
185 unsigned long maddr;
186 struct page_info *page;
188 while (1) {
189 maddr = xencomm_paddr_to_maddr(paddr);
190 if (xencomm_debug > 1)
191 printk("%lx[%d] -> %lx\n", from, len, maddr);
192 if (maddr == 0)
193 return -EFAULT;
195 page = virt_to_page(maddr);
196 if (get_page(page, current->domain) == 0) {
197 if (page_get_owner(page) != current->domain) {
198 /* This page might be a page granted by another domain */
199 panic_domain(NULL, "copy_to_guest to foreign domain\n");
200 }
201 /* Try again. */
202 continue;
203 }
204 memcpy((void *)maddr, (void *)from, len);
205 put_page(page);
206 return 0;
207 }
208 }
210 /**
211 * xencomm_copy_to_guest: Copy a block of data to domain space.
212 * @to: Physical address to xencomm buffer descriptor.
213 * @from: Machine address.
214 * @n: Number of bytes to copy.
215 * @skip: Number of bytes from the start to skip.
216 *
217 * Copy data from hypervisor to domain.
218 *
219 * Returns number of bytes that could not be copied.
220 * On success, this will be zero.
221 */
222 unsigned long
223 xencomm_copy_to_guest(
224 void *to,
225 const void *from,
226 unsigned int n,
227 unsigned int skip)
228 {
229 struct xencomm_desc *desc;
230 unsigned long desc_addr;
231 unsigned int from_pos = 0;
232 unsigned int to_pos = 0;
233 unsigned int i = 0;
235 if (xencomm_debug)
236 printk ("xencomm_copy_to_guest: to=%lx+%u n=%u\n",
237 (unsigned long)to, skip, n);
239 if (XENCOMM_IS_INLINE(to)) {
240 unsigned long dest_paddr = XENCOMM_INLINE_ADDR(to);
242 dest_paddr += skip;
244 while (n > 0) {
245 unsigned int chunksz;
246 unsigned int bytes;
247 int res;
249 chunksz = PAGE_SIZE - (dest_paddr % PAGE_SIZE);
251 bytes = min(chunksz, n);
253 res = xencomm_copy_chunk_to(dest_paddr, (unsigned long)from, bytes);
254 if (res != 0)
255 return res;
257 dest_paddr += bytes;
258 from += bytes;
259 n -= bytes;
260 }
262 /* Always successful. */
263 return 0;
264 }
266 /* first we need to access the descriptor */
267 desc_addr = xencomm_paddr_to_maddr((unsigned long)to);
268 if (desc_addr == 0)
269 return -EFAULT;
271 desc = (struct xencomm_desc *)desc_addr;
272 if (desc->magic != XENCOMM_MAGIC) {
273 printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic);
274 return -EFAULT;
275 }
277 /* iterate through the descriptor, copying up to a page at a time */
278 while ((from_pos < n) && (i < desc->nr_addrs)) {
279 unsigned long dest_paddr = desc->address[i];
280 unsigned int pgoffset;
281 unsigned int chunksz;
282 unsigned int chunk_skip;
284 if (dest_paddr == XENCOMM_INVALID) {
285 i++;
286 continue;
287 }
289 pgoffset = dest_paddr % PAGE_SIZE;
290 chunksz = PAGE_SIZE - pgoffset;
292 chunk_skip = min(chunksz, skip);
293 to_pos += chunk_skip;
294 chunksz -= chunk_skip;
295 skip -= chunk_skip;
296 dest_paddr += chunk_skip;
298 if (skip == 0 && chunksz > 0) {
299 unsigned int bytes = min(chunksz, n - from_pos);
300 int res;
302 res = xencomm_copy_chunk_to(dest_paddr,
303 (unsigned long)from + from_pos, bytes);
304 if (res != 0)
305 return res;
307 from_pos += bytes;
308 to_pos += bytes;
309 }
311 i++;
312 }
313 return n - from_pos;
314 }
316 /* Offset page addresses in 'handle' to skip 'bytes' bytes. Set completely
317 * exhausted pages to XENCOMM_INVALID. */
318 void *
319 xencomm_add_offset(
320 void *handle,
321 unsigned int bytes)
322 {
323 struct xencomm_desc *desc;
324 unsigned long desc_addr;
325 int i = 0;
327 if (XENCOMM_IS_INLINE(handle))
328 return (void *)((unsigned long)handle + bytes);
330 /* first we need to access the descriptor */
331 desc_addr = xencomm_paddr_to_maddr((unsigned long)handle);
332 if (desc_addr == 0)
333 return NULL;
335 desc = (struct xencomm_desc *)desc_addr;
336 if (desc->magic != XENCOMM_MAGIC) {
337 printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic);
338 return NULL;
339 }
341 /* iterate through the descriptor incrementing addresses */
342 while ((bytes > 0) && (i < desc->nr_addrs)) {
343 unsigned long dest_paddr = desc->address[i];
344 unsigned int pgoffset;
345 unsigned int chunksz;
346 unsigned int chunk_skip;
348 if (dest_paddr == XENCOMM_INVALID) {
349 i++;
350 continue;
351 }
353 pgoffset = dest_paddr % PAGE_SIZE;
354 chunksz = PAGE_SIZE - pgoffset;
356 chunk_skip = min(chunksz, bytes);
357 if (chunk_skip == chunksz) {
358 /* exhausted this page */
359 desc->address[i] = XENCOMM_INVALID;
360 } else {
361 desc->address[i] += chunk_skip;
362 }
363 bytes -= chunk_skip;
365 i++;
366 }
367 return handle;
368 }
370 int
371 xencomm_handle_is_null(
372 void *ptr)
373 {
374 if (XENCOMM_IS_INLINE(ptr))
375 return XENCOMM_INLINE_ADDR(ptr) == 0;
376 else {
377 struct xencomm_desc *desc;
378 unsigned long desc_addr;
380 desc_addr = xencomm_paddr_to_maddr((unsigned long)ptr);
381 if (desc_addr == 0)
382 return 1;
384 desc = (struct xencomm_desc *)desc_addr;
385 return (desc->nr_addrs == 0);
386 }
387 }