source: trunk/packages/xen-3.1/xen-3.1/tools/libxc/xc_linux.c @ 34

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

Add xen and xen-common

File size: 12.5 KB
Line 
1/******************************************************************************
2 *
3 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
4 * Use is subject to license terms.
5 *
6 * xc_gnttab functions:
7 * Copyright (c) 2007, D G Murray <Derek.Murray@cl.cam.ac.uk>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation, version 2 of the
12 * License.
13 */
14
15#include "xc_private.h"
16
17#include <xen/memory.h>
18#include <xen/sys/evtchn.h>
19#include <xen/sys/gntdev.h>
20#include <unistd.h>
21#include <fcntl.h>
22
23int xc_interface_open(void)
24{
25    int flags, saved_errno;
26    int fd = open("/proc/xen/privcmd", O_RDWR);
27
28    if ( fd == -1 )
29    {
30        PERROR("Could not obtain handle on privileged command interface");
31        return -1;
32    }
33
34    /* Although we return the file handle as the 'xc handle' the API
35       does not specify / guarentee that this integer is in fact
36       a file handle. Thus we must take responsiblity to ensure
37       it doesn't propagate (ie leak) outside the process */
38    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
39    {
40        PERROR("Could not get file handle flags");
41        goto error;
42    }
43    flags |= FD_CLOEXEC;
44    if ( fcntl(fd, F_SETFD, flags) < 0 )
45    {
46        PERROR("Could not set file handle flags");
47        goto error;
48    }
49
50    return fd;
51
52 error:
53    saved_errno = errno;
54    close(fd);
55    errno = saved_errno;
56    return -1;
57}
58
59int xc_interface_close(int xc_handle)
60{
61    return close(xc_handle);
62}
63
64void *xc_map_foreign_batch(int xc_handle, uint32_t dom, int prot,
65                           xen_pfn_t *arr, int num)
66{
67    privcmd_mmapbatch_t ioctlx;
68    void *addr;
69    addr = mmap(NULL, num*PAGE_SIZE, prot, MAP_SHARED, xc_handle, 0);
70    if ( addr == MAP_FAILED )
71        return NULL;
72
73    ioctlx.num=num;
74    ioctlx.dom=dom;
75    ioctlx.addr=(unsigned long)addr;
76    ioctlx.arr=arr;
77    if ( ioctl(xc_handle, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx) < 0 )
78    {
79        int saved_errno = errno;
80        perror("XXXXXXXX");
81        (void)munmap(addr, num*PAGE_SIZE);
82        errno = saved_errno;
83        return NULL;
84    }
85    return addr;
86
87}
88
89void *xc_map_foreign_range(int xc_handle, uint32_t dom,
90                           int size, int prot,
91                           unsigned long mfn)
92{
93    privcmd_mmap_t ioctlx;
94    privcmd_mmap_entry_t entry;
95    void *addr;
96    addr = mmap(NULL, size, prot, MAP_SHARED, xc_handle, 0);
97    if ( addr == MAP_FAILED )
98        return NULL;
99
100    ioctlx.num=1;
101    ioctlx.dom=dom;
102    ioctlx.entry=&entry;
103    entry.va=(unsigned long) addr;
104    entry.mfn=mfn;
105    entry.npages=(size+PAGE_SIZE-1)>>PAGE_SHIFT;
106    if ( ioctl(xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx) < 0 )
107    {
108        int saved_errno = errno;
109        (void)munmap(addr, size);
110        errno = saved_errno;
111        return NULL;
112    }
113    return addr;
114}
115
116int xc_map_foreign_ranges(int xc_handle, uint32_t dom,
117                          privcmd_mmap_entry_t *entries, int nr)
118{
119    privcmd_mmap_t ioctlx;
120
121    ioctlx.num   = nr;
122    ioctlx.dom   = dom;
123    ioctlx.entry = entries;
124
125    return ioctl(xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx);
126}
127
128static int do_privcmd(int xc_handle, unsigned int cmd, unsigned long data)
129{
130    return ioctl(xc_handle, cmd, data);
131}
132
133int do_xen_hypercall(int xc_handle, privcmd_hypercall_t *hypercall)
134{
135    return do_privcmd(xc_handle,
136                      IOCTL_PRIVCMD_HYPERCALL,
137                      (unsigned long)hypercall);
138}
139
140#define MTAB "/proc/mounts"
141#define MAX_PATH 255
142#define _STR(x) #x
143#define STR(x) _STR(x)
144
145static int find_sysfsdir(char *sysfsdir)
146{
147    FILE *fp;
148    char type[MAX_PATH + 1];
149
150    if ( (fp = fopen(MTAB, "r")) == NULL )
151        return -1;
152
153    while ( fscanf(fp, "%*s %"
154                   STR(MAX_PATH)
155                   "s %"
156                   STR(MAX_PATH)
157                   "s %*s %*d %*d\n",
158                   sysfsdir, type) == 2 )
159    {
160        if ( strncmp(type, "sysfs", 5) == 0 )
161            break;
162    }
163
164    fclose(fp);
165
166    return ((strncmp(type, "sysfs", 5) == 0) ? 0 : -1);
167}
168
169int xc_find_device_number(const char *name)
170{
171    FILE *fp;
172    int i, major, minor;
173    char sysfsdir[MAX_PATH + 1];
174    static char *classlist[] = { "xen", "misc" };
175
176    for ( i = 0; i < (sizeof(classlist) / sizeof(classlist[0])); i++ )
177    {
178        if ( find_sysfsdir(sysfsdir) < 0 )
179            goto not_found;
180
181        /* <base>/class/<classname>/<devname>/dev */
182        strncat(sysfsdir, "/class/", MAX_PATH);
183        strncat(sysfsdir, classlist[i], MAX_PATH);
184        strncat(sysfsdir, "/", MAX_PATH);
185        strncat(sysfsdir, name, MAX_PATH);
186        strncat(sysfsdir, "/dev", MAX_PATH);
187
188        if ( (fp = fopen(sysfsdir, "r")) != NULL )
189            goto found;
190    }
191
192 not_found:
193    errno = -ENOENT;
194    return -1;
195
196 found:
197    if ( fscanf(fp, "%d:%d", &major, &minor) != 2 )
198    {
199        fclose(fp);
200        goto not_found;
201    }
202
203    fclose(fp);
204
205    return makedev(major, minor);
206}
207
208#define EVTCHN_DEV_NAME  "/dev/xen/evtchn"
209
210int xc_evtchn_open(void)
211{
212    struct stat st;
213    int fd;
214    int devnum;
215
216    devnum = xc_find_device_number("evtchn");
217
218    /* Make sure any existing device file links to correct device. */
219    if ( (lstat(EVTCHN_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
220         (st.st_rdev != devnum) )
221        (void)unlink(EVTCHN_DEV_NAME);
222
223 reopen:
224    if ( (fd = open(EVTCHN_DEV_NAME, O_RDWR)) == -1 )
225    {
226        if ( (errno == ENOENT) &&
227            ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
228             (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600, devnum) == 0) )
229            goto reopen;
230
231        PERROR("Could not open event channel interface");
232        return -1;
233    }
234
235    return fd;
236}
237
238int xc_evtchn_close(int xce_handle)
239{
240    return close(xce_handle);
241}
242
243int xc_evtchn_fd(int xce_handle)
244{
245    return xce_handle;
246}
247
248int xc_evtchn_notify(int xce_handle, evtchn_port_t port)
249{
250    struct ioctl_evtchn_notify notify;
251
252    notify.port = port;
253
254    return ioctl(xce_handle, IOCTL_EVTCHN_NOTIFY, &notify);
255}
256
257evtchn_port_t xc_evtchn_bind_unbound_port(int xce_handle, int domid)
258{
259    struct ioctl_evtchn_bind_unbound_port bind;
260
261    bind.remote_domain = domid;
262
263    return ioctl(xce_handle, IOCTL_EVTCHN_BIND_UNBOUND_PORT, &bind);
264}
265
266evtchn_port_t xc_evtchn_bind_interdomain(int xce_handle, int domid,
267    evtchn_port_t remote_port)
268{
269    struct ioctl_evtchn_bind_interdomain bind;
270
271    bind.remote_domain = domid;
272    bind.remote_port = remote_port;
273
274    return ioctl(xce_handle, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
275}
276
277int xc_evtchn_unbind(int xce_handle, evtchn_port_t port)
278{
279    struct ioctl_evtchn_unbind unbind;
280
281    unbind.port = port;
282
283    return ioctl(xce_handle, IOCTL_EVTCHN_UNBIND, &unbind);
284}
285
286evtchn_port_t xc_evtchn_bind_virq(int xce_handle, unsigned int virq)
287{
288    struct ioctl_evtchn_bind_virq bind;
289
290    bind.virq = virq;
291
292    return ioctl(xce_handle, IOCTL_EVTCHN_BIND_VIRQ, &bind);
293}
294
295static int dorw(int fd, char *data, size_t size, int do_write)
296{
297    size_t offset = 0;
298    ssize_t len;
299
300    while ( offset < size )
301    {
302        if (do_write)
303            len = write(fd, data + offset, size - offset);
304        else
305            len = read(fd, data + offset, size - offset);
306
307        if ( len == -1 )
308        {
309             if ( errno == EINTR )
310                 continue;
311             return -1;
312        }
313
314        offset += len;
315    }
316
317    return 0;
318}
319
320evtchn_port_t xc_evtchn_pending(int xce_handle)
321{
322    evtchn_port_t port;
323
324    if ( dorw(xce_handle, (char *)&port, sizeof(port), 0) == -1 )
325        return -1;
326
327    return port;
328}
329
330int xc_evtchn_unmask(int xce_handle, evtchn_port_t port)
331{
332    return dorw(xce_handle, (char *)&port, sizeof(port), 1);
333}
334
335/* Optionally flush file to disk and discard page cache */
336void discard_file_cache(int fd, int flush) 
337{
338    off_t cur = 0;
339    int saved_errno = errno;
340
341    if ( flush && (fsync(fd) < 0) )
342    {
343        /*PERROR("Failed to flush file: %s", strerror(errno));*/
344        goto out;
345    }
346
347    /*
348     * Calculate last page boundary of amount written so far
349     * unless we are flushing in which case entire cache
350     * is discarded.
351     */
352    if ( !flush )
353    {
354        if ( (cur = lseek(fd, 0, SEEK_CUR)) == (off_t)-1 )
355            cur = 0;
356        cur &= ~(PAGE_SIZE-1);
357    }
358
359    /* Discard from the buffer cache. */
360    if ( posix_fadvise64(fd, 0, cur, POSIX_FADV_DONTNEED) < 0 )
361    {
362        /*PERROR("Failed to discard cache: %s", strerror(errno));*/
363        goto out;
364    }
365
366 out:
367    errno = saved_errno;
368}
369
370#define GNTTAB_DEV_NAME "/dev/xen/gntdev"
371
372int xc_gnttab_open(void)
373{
374    struct stat st;
375    int fd;
376    int devnum;
377   
378    devnum = xc_find_device_number("gntdev");
379   
380    /* Make sure any existing device file links to correct device. */
381    if ( (lstat(GNTTAB_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
382         (st.st_rdev != devnum) )
383        (void)unlink(GNTTAB_DEV_NAME);
384   
385reopen:
386    if ( (fd = open(GNTTAB_DEV_NAME, O_RDWR)) == -1 )
387    {
388        if ( (errno == ENOENT) &&
389             ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
390             (mknod(GNTTAB_DEV_NAME, S_IFCHR|0600, devnum) == 0) )
391            goto reopen;
392       
393        PERROR("Could not open grant table interface");
394        return -1;
395    }
396   
397    return fd;
398}
399
400int xc_gnttab_close(int xcg_handle)
401{
402    return close(xcg_handle);
403}
404
405void *xc_gnttab_map_grant_ref(int xcg_handle,
406                              uint32_t domid,
407                              uint32_t ref,
408                              int prot)
409{
410    struct ioctl_gntdev_map_grant_ref map;
411    void *addr;
412   
413    map.count = 1;
414    map.refs[0].domid = domid;
415    map.refs[0].ref   = ref;
416
417    if ( ioctl(xcg_handle, IOCTL_GNTDEV_MAP_GRANT_REF, &map) )
418        return NULL;
419   
420    addr = mmap(NULL, PAGE_SIZE, prot, MAP_SHARED, xcg_handle, map.index);
421    if ( addr == MAP_FAILED )
422    {
423        int saved_errno = errno;
424        struct ioctl_gntdev_unmap_grant_ref unmap_grant;
425        /* Unmap the driver slots used to store the grant information. */
426        unmap_grant.index = map.index;
427        unmap_grant.count = 1;
428        ioctl(xcg_handle, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant);
429        errno = saved_errno;
430        return NULL;
431    }
432   
433    return addr;
434}
435
436void *xc_gnttab_map_grant_refs(int xcg_handle,
437                               uint32_t count,
438                               uint32_t *domids,
439                               uint32_t *refs,
440                               int prot)
441{
442    struct ioctl_gntdev_map_grant_ref *map;
443    void *addr = NULL;
444    int i;
445   
446    map = malloc(sizeof(*map) +
447                 (count-1) * sizeof(struct ioctl_gntdev_map_grant_ref));
448    if ( map == NULL )
449        return NULL;
450
451    for ( i = 0; i < count; i++ )
452    {
453        map->refs[i].domid = domids[i];
454        map->refs[i].ref   = refs[i];
455    }
456
457    map->count = count;
458   
459    if ( ioctl(xcg_handle, IOCTL_GNTDEV_MAP_GRANT_REF, &map) )
460        goto out;
461
462    addr = mmap(NULL, PAGE_SIZE * count, prot, MAP_SHARED, xcg_handle,
463                map->index);
464    if ( addr == MAP_FAILED )
465    {
466        int saved_errno = errno;
467        struct ioctl_gntdev_unmap_grant_ref unmap_grant;
468        /* Unmap the driver slots used to store the grant information. */
469        unmap_grant.index = map->index;
470        unmap_grant.count = count;
471        ioctl(xcg_handle, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant);
472        errno = saved_errno;
473        addr = NULL;
474    }
475
476 out:
477    free(map);
478    return addr;
479}
480
481int xc_gnttab_munmap(int xcg_handle,
482                     void *start_address,
483                     uint32_t count)
484{
485    struct ioctl_gntdev_get_offset_for_vaddr get_offset;
486    struct ioctl_gntdev_unmap_grant_ref unmap_grant;
487    int rc;
488
489    if ( start_address == NULL )
490    {
491        errno = EINVAL;
492        return -1;
493    }
494
495    /* First, it is necessary to get the offset which was initially used to
496     * mmap() the pages.
497     */
498    get_offset.vaddr = (unsigned long)start_address;
499    if ( (rc = ioctl(xcg_handle, IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR, 
500                     &get_offset)) )
501        return rc;
502
503    if ( get_offset.count != count )
504    {
505        errno = EINVAL;
506        return -1;
507    }
508
509    /* Next, unmap the memory. */
510    if ( (rc = munmap(start_address, count * getpagesize())) )
511        return rc;
512   
513    /* Finally, unmap the driver slots used to store the grant information. */
514    unmap_grant.index = get_offset.offset;
515    unmap_grant.count = count;
516    if ( (rc = ioctl(xcg_handle, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant)) )
517        return rc;
518
519    return 0;
520}
521
522/*
523 * Local variables:
524 * mode: C
525 * c-set-style: "BSD"
526 * c-basic-offset: 4
527 * tab-width: 4
528 * indent-tabs-mode: nil
529 * End:
530 */
Note: See TracBrowser for help on using the repository browser.