source: trunk/packages/xen-3.1/xen-3.1/xen/arch/ia64/xen/xencomm.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 10.0 KB
Line 
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 */
21
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>
30
31#undef DEBUG
32#ifdef DEBUG
33static int xencomm_debug = 1; /* extremely verbose */
34#else
35#define xencomm_debug 0
36#endif
37
38static int
39xencomm_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;
46
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;
53
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}
68
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 */
81unsigned long
82xencomm_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;
93
94    if (xencomm_debug)
95        printk("xencomm_copy_from_guest: from=%lx+%u n=%u\n",
96               (unsigned long)from, skip, n);
97
98    if (XENCOMM_IS_INLINE(from)) {
99        unsigned long src_paddr = XENCOMM_INLINE_ADDR(from);
100           
101        src_paddr += skip;
102
103        while (n > 0) {
104            unsigned int chunksz;
105            unsigned int bytes;
106            int res;
107           
108            chunksz = PAGE_SIZE - (src_paddr % PAGE_SIZE);
109           
110            bytes = min(chunksz, n);
111
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        }
119       
120        /* Always successful.  */
121        return 0;
122    }
123
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;
128
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    }
135
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;
142
143        if (src_paddr == XENCOMM_INVALID) {
144            i++;
145            continue;
146        }
147
148        pgoffset = src_paddr % PAGE_SIZE;
149        chunksz = PAGE_SIZE - pgoffset;
150
151        chunk_skip = min(chunksz, skip);
152        from_pos += chunk_skip;
153        chunksz -= chunk_skip;
154        skip -= chunk_skip;
155
156        if (skip == 0 && chunksz > 0) {
157            unsigned int bytes = min(chunksz, n - to_pos);
158            int res;
159
160            if (xencomm_debug > 1)
161                printk ("src_paddr=%lx i=%d, skip=%d\n",
162                        src_paddr, i, chunk_skip);
163
164            res = xencomm_copy_chunk_from((unsigned long)to + to_pos,
165                                          src_paddr + chunk_skip, bytes);
166            if (res != 0)
167                return -EFAULT;
168
169            from_pos += bytes;
170            to_pos += bytes;
171        }
172
173        i++;
174    }
175
176    return n - to_pos;
177}
178
179static int
180xencomm_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;
187
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;
194
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}
209
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 */
222unsigned long
223xencomm_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;
234
235    if (xencomm_debug)
236        printk ("xencomm_copy_to_guest: to=%lx+%u n=%u\n",
237                (unsigned long)to, skip, n);
238
239    if (XENCOMM_IS_INLINE(to)) {
240        unsigned long dest_paddr = XENCOMM_INLINE_ADDR(to);
241           
242        dest_paddr += skip;
243
244        while (n > 0) {
245            unsigned int chunksz;
246            unsigned int bytes;
247            int res;
248
249            chunksz = PAGE_SIZE - (dest_paddr % PAGE_SIZE);
250           
251            bytes = min(chunksz, n);
252
253            res = xencomm_copy_chunk_to(dest_paddr, (unsigned long)from, bytes);
254            if (res != 0)
255                return res;
256
257            dest_paddr += bytes;
258            from += bytes;
259            n -= bytes;
260        }
261
262        /* Always successful.  */
263        return 0;
264    }
265
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;
270
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    }
276
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;
283
284        if (dest_paddr == XENCOMM_INVALID) {
285            i++;
286            continue;
287        }
288
289        pgoffset = dest_paddr % PAGE_SIZE;
290        chunksz = PAGE_SIZE - pgoffset;
291
292        chunk_skip = min(chunksz, skip);
293        to_pos += chunk_skip;
294        chunksz -= chunk_skip;
295        skip -= chunk_skip;
296        dest_paddr += chunk_skip;
297
298        if (skip == 0 && chunksz > 0) {
299            unsigned int bytes = min(chunksz, n - from_pos);
300            int res;
301
302            res = xencomm_copy_chunk_to(dest_paddr,
303                                        (unsigned long)from + from_pos, bytes);
304            if (res != 0)
305                return res;
306
307            from_pos += bytes;
308            to_pos += bytes;
309        }
310
311        i++;
312    }
313    return n - from_pos;
314}
315
316/* Offset page addresses in 'handle' to skip 'bytes' bytes. Set completely
317 * exhausted pages to XENCOMM_INVALID. */
318void *
319xencomm_add_offset(
320    void         *handle,
321    unsigned int bytes)
322{
323    struct xencomm_desc *desc;
324    unsigned long desc_addr;
325    int i = 0;
326
327    if (XENCOMM_IS_INLINE(handle))
328        return (void *)((unsigned long)handle + bytes);
329
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;
334
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    }
340
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;
347
348        if (dest_paddr == XENCOMM_INVALID) {
349            i++;
350            continue;
351        }
352
353        pgoffset = dest_paddr % PAGE_SIZE;
354        chunksz = PAGE_SIZE - pgoffset;
355
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;
364       
365        i++;
366    }
367    return handle;
368}
369
370int
371xencomm_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;
379
380        desc_addr = xencomm_paddr_to_maddr((unsigned long)ptr);
381        if (desc_addr == 0)
382            return 1;
383
384        desc = (struct xencomm_desc *)desc_addr;
385        return (desc->nr_addrs == 0);
386    }
387}
Note: See TracBrowser for help on using the repository browser.