debuggers.hg

view tools/libxc/xc_linux.c @ 16715:c5deb251b9dc

Update version to 3.2.0-rc4
author Keir Fraser <keir.fraser@citrix.com>
date Sat Dec 29 17:57:37 2007 +0000 (2007-12-29)
parents e948f402c356
children c978ecfc4f41
line source
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 */
15 #include "xc_private.h"
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>
23 int xc_interface_open(void)
24 {
25 int flags, saved_errno;
26 int fd = open("/proc/xen/privcmd", O_RDWR);
28 if ( fd == -1 )
29 {
30 PERROR("Could not obtain handle on privileged command interface");
31 return -1;
32 }
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 }
50 return fd;
52 error:
53 saved_errno = errno;
54 close(fd);
55 errno = saved_errno;
56 return -1;
57 }
59 int xc_interface_close(int xc_handle)
60 {
61 return close(xc_handle);
62 }
64 void *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 perror("xc_map_foreign_batch: mmap failed");
72 return NULL;
73 }
75 ioctlx.num=num;
76 ioctlx.dom=dom;
77 ioctlx.addr=(unsigned long)addr;
78 ioctlx.arr=arr;
79 if ( ioctl(xc_handle, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx) < 0 )
80 {
81 int saved_errno = errno;
82 perror("xc_map_foreign_batch: ioctl failed");
83 (void)munmap(addr, num*PAGE_SIZE);
84 errno = saved_errno;
85 return NULL;
86 }
87 return addr;
89 }
91 void *xc_map_foreign_range(int xc_handle, uint32_t dom,
92 int size, int prot,
93 unsigned long mfn)
94 {
95 privcmd_mmap_t ioctlx;
96 privcmd_mmap_entry_t entry;
97 void *addr;
98 addr = mmap(NULL, size, prot, MAP_SHARED, xc_handle, 0);
99 if ( addr == MAP_FAILED ) {
100 perror("xc_map_foreign_range: mmap failed");
101 return NULL;
102 }
104 ioctlx.num=1;
105 ioctlx.dom=dom;
106 ioctlx.entry=&entry;
107 entry.va=(unsigned long) addr;
108 entry.mfn=mfn;
109 entry.npages=(size+PAGE_SIZE-1)>>PAGE_SHIFT;
110 if ( ioctl(xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx) < 0 )
111 {
112 int saved_errno = errno;
113 perror("xc_map_foreign_range: ioctl failed");
114 (void)munmap(addr, size);
115 errno = saved_errno;
116 return NULL;
117 }
118 return addr;
119 }
121 int xc_map_foreign_ranges(int xc_handle, uint32_t dom,
122 privcmd_mmap_entry_t *entries, int nr)
123 {
124 privcmd_mmap_t ioctlx;
126 ioctlx.num = nr;
127 ioctlx.dom = dom;
128 ioctlx.entry = entries;
130 return ioctl(xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx);
131 }
133 static int do_privcmd(int xc_handle, unsigned int cmd, unsigned long data)
134 {
135 return ioctl(xc_handle, cmd, data);
136 }
138 int do_xen_hypercall(int xc_handle, privcmd_hypercall_t *hypercall)
139 {
140 return do_privcmd(xc_handle,
141 IOCTL_PRIVCMD_HYPERCALL,
142 (unsigned long)hypercall);
143 }
145 #define MTAB "/proc/mounts"
146 #define MAX_PATH 255
147 #define _STR(x) #x
148 #define STR(x) _STR(x)
150 static int find_sysfsdir(char *sysfsdir)
151 {
152 FILE *fp;
153 char type[MAX_PATH + 1];
155 if ( (fp = fopen(MTAB, "r")) == NULL )
156 return -1;
158 while ( fscanf(fp, "%*s %"
159 STR(MAX_PATH)
160 "s %"
161 STR(MAX_PATH)
162 "s %*s %*d %*d\n",
163 sysfsdir, type) == 2 )
164 {
165 if ( strncmp(type, "sysfs", 5) == 0 )
166 break;
167 }
169 fclose(fp);
171 return ((strncmp(type, "sysfs", 5) == 0) ? 0 : -1);
172 }
174 int xc_find_device_number(const char *name)
175 {
176 FILE *fp;
177 int i, major, minor;
178 char sysfsdir[MAX_PATH + 1];
179 static char *classlist[] = { "xen", "misc" };
181 for ( i = 0; i < (sizeof(classlist) / sizeof(classlist[0])); i++ )
182 {
183 if ( find_sysfsdir(sysfsdir) < 0 )
184 goto not_found;
186 /* <base>/class/<classname>/<devname>/dev */
187 strncat(sysfsdir, "/class/", MAX_PATH);
188 strncat(sysfsdir, classlist[i], MAX_PATH);
189 strncat(sysfsdir, "/", MAX_PATH);
190 strncat(sysfsdir, name, MAX_PATH);
191 strncat(sysfsdir, "/dev", MAX_PATH);
193 if ( (fp = fopen(sysfsdir, "r")) != NULL )
194 goto found;
195 }
197 not_found:
198 errno = -ENOENT;
199 return -1;
201 found:
202 if ( fscanf(fp, "%d:%d", &major, &minor) != 2 )
203 {
204 fclose(fp);
205 goto not_found;
206 }
208 fclose(fp);
210 return makedev(major, minor);
211 }
213 #define EVTCHN_DEV_NAME "/dev/xen/evtchn"
215 int xc_evtchn_open(void)
216 {
217 struct stat st;
218 int fd;
219 int devnum;
221 devnum = xc_find_device_number("evtchn");
223 /* Make sure any existing device file links to correct device. */
224 if ( (lstat(EVTCHN_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
225 (st.st_rdev != devnum) )
226 (void)unlink(EVTCHN_DEV_NAME);
228 reopen:
229 if ( (fd = open(EVTCHN_DEV_NAME, O_RDWR)) == -1 )
230 {
231 if ( (errno == ENOENT) &&
232 ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
233 (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600, devnum) == 0) )
234 goto reopen;
236 PERROR("Could not open event channel interface");
237 return -1;
238 }
240 return fd;
241 }
243 int xc_evtchn_close(int xce_handle)
244 {
245 return close(xce_handle);
246 }
248 int xc_evtchn_fd(int xce_handle)
249 {
250 return xce_handle;
251 }
253 int xc_evtchn_notify(int xce_handle, evtchn_port_t port)
254 {
255 struct ioctl_evtchn_notify notify;
257 notify.port = port;
259 return ioctl(xce_handle, IOCTL_EVTCHN_NOTIFY, &notify);
260 }
262 evtchn_port_or_error_t
263 xc_evtchn_bind_unbound_port(int xce_handle, int domid)
264 {
265 struct ioctl_evtchn_bind_unbound_port bind;
267 bind.remote_domain = domid;
269 return ioctl(xce_handle, IOCTL_EVTCHN_BIND_UNBOUND_PORT, &bind);
270 }
272 evtchn_port_or_error_t
273 xc_evtchn_bind_interdomain(int xce_handle, int domid,
274 evtchn_port_t remote_port)
275 {
276 struct ioctl_evtchn_bind_interdomain bind;
278 bind.remote_domain = domid;
279 bind.remote_port = remote_port;
281 return ioctl(xce_handle, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
282 }
284 evtchn_port_or_error_t
285 xc_evtchn_bind_virq(int xce_handle, unsigned int virq)
286 {
287 struct ioctl_evtchn_bind_virq bind;
289 bind.virq = virq;
291 return ioctl(xce_handle, IOCTL_EVTCHN_BIND_VIRQ, &bind);
292 }
294 int xc_evtchn_unbind(int xce_handle, evtchn_port_t port)
295 {
296 struct ioctl_evtchn_unbind unbind;
298 unbind.port = port;
300 return ioctl(xce_handle, IOCTL_EVTCHN_UNBIND, &unbind);
301 }
303 evtchn_port_or_error_t
304 xc_evtchn_pending(int xce_handle)
305 {
306 evtchn_port_t port;
308 if ( read_exact(xce_handle, (char *)&port, sizeof(port)) == -1 )
309 return -1;
311 return port;
312 }
314 int xc_evtchn_unmask(int xce_handle, evtchn_port_t port)
315 {
316 return write_exact(xce_handle, (char *)&port, sizeof(port));
317 }
319 /* Optionally flush file to disk and discard page cache */
320 void discard_file_cache(int fd, int flush)
321 {
322 off_t cur = 0;
323 int saved_errno = errno;
325 if ( flush && (fsync(fd) < 0) )
326 {
327 /*PERROR("Failed to flush file: %s", strerror(errno));*/
328 goto out;
329 }
331 /*
332 * Calculate last page boundary of amount written so far
333 * unless we are flushing in which case entire cache
334 * is discarded.
335 */
336 if ( !flush )
337 {
338 if ( (cur = lseek(fd, 0, SEEK_CUR)) == (off_t)-1 )
339 cur = 0;
340 cur &= ~(PAGE_SIZE-1);
341 }
343 /* Discard from the buffer cache. */
344 if ( posix_fadvise64(fd, 0, cur, POSIX_FADV_DONTNEED) < 0 )
345 {
346 /*PERROR("Failed to discard cache: %s", strerror(errno));*/
347 goto out;
348 }
350 out:
351 errno = saved_errno;
352 }
354 #define GNTTAB_DEV_NAME "/dev/xen/gntdev"
356 int xc_gnttab_open(void)
357 {
358 struct stat st;
359 int fd;
360 int devnum;
362 devnum = xc_find_device_number("gntdev");
364 /* Make sure any existing device file links to correct device. */
365 if ( (lstat(GNTTAB_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
366 (st.st_rdev != devnum) )
367 (void)unlink(GNTTAB_DEV_NAME);
369 reopen:
370 if ( (fd = open(GNTTAB_DEV_NAME, O_RDWR)) == -1 )
371 {
372 if ( (errno == ENOENT) &&
373 ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
374 (mknod(GNTTAB_DEV_NAME, S_IFCHR|0600, devnum) == 0) )
375 goto reopen;
377 PERROR("Could not open grant table interface");
378 return -1;
379 }
381 return fd;
382 }
384 int xc_gnttab_close(int xcg_handle)
385 {
386 return close(xcg_handle);
387 }
389 void *xc_gnttab_map_grant_ref(int xcg_handle,
390 uint32_t domid,
391 uint32_t ref,
392 int prot)
393 {
394 struct ioctl_gntdev_map_grant_ref map;
395 void *addr;
397 map.count = 1;
398 map.refs[0].domid = domid;
399 map.refs[0].ref = ref;
401 if ( ioctl(xcg_handle, IOCTL_GNTDEV_MAP_GRANT_REF, &map) )
402 return NULL;
404 addr = mmap(NULL, PAGE_SIZE, prot, MAP_SHARED, xcg_handle, map.index);
405 if ( addr == MAP_FAILED )
406 {
407 int saved_errno = errno;
408 struct ioctl_gntdev_unmap_grant_ref unmap_grant;
409 /* Unmap the driver slots used to store the grant information. */
410 perror("xc_gnttab_map_grant_ref: mmap failed");
411 unmap_grant.index = map.index;
412 unmap_grant.count = 1;
413 ioctl(xcg_handle, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant);
414 errno = saved_errno;
415 return NULL;
416 }
418 return addr;
419 }
421 void *xc_gnttab_map_grant_refs(int xcg_handle,
422 uint32_t count,
423 uint32_t *domids,
424 uint32_t *refs,
425 int prot)
426 {
427 struct ioctl_gntdev_map_grant_ref *map;
428 void *addr = NULL;
429 int i;
431 map = malloc(sizeof(*map) +
432 (count-1) * sizeof(struct ioctl_gntdev_map_grant_ref));
433 if ( map == NULL )
434 return NULL;
436 for ( i = 0; i < count; i++ )
437 {
438 map->refs[i].domid = domids[i];
439 map->refs[i].ref = refs[i];
440 }
442 map->count = count;
444 if ( ioctl(xcg_handle, IOCTL_GNTDEV_MAP_GRANT_REF, map) )
445 goto out;
447 addr = mmap(NULL, PAGE_SIZE * count, prot, MAP_SHARED, xcg_handle,
448 map->index);
449 if ( addr == MAP_FAILED )
450 {
451 int saved_errno = errno;
452 struct ioctl_gntdev_unmap_grant_ref unmap_grant;
453 /* Unmap the driver slots used to store the grant information. */
454 perror("xc_gnttab_map_grant_refs: mmap failed");
455 unmap_grant.index = map->index;
456 unmap_grant.count = count;
457 ioctl(xcg_handle, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant);
458 errno = saved_errno;
459 addr = NULL;
460 }
462 out:
463 free(map);
464 return addr;
465 }
467 int xc_gnttab_munmap(int xcg_handle,
468 void *start_address,
469 uint32_t count)
470 {
471 struct ioctl_gntdev_get_offset_for_vaddr get_offset;
472 struct ioctl_gntdev_unmap_grant_ref unmap_grant;
473 int rc;
475 if ( start_address == NULL )
476 {
477 errno = EINVAL;
478 return -1;
479 }
481 /* First, it is necessary to get the offset which was initially used to
482 * mmap() the pages.
483 */
484 get_offset.vaddr = (unsigned long)start_address;
485 if ( (rc = ioctl(xcg_handle, IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR,
486 &get_offset)) )
487 return rc;
489 if ( get_offset.count != count )
490 {
491 errno = EINVAL;
492 return -1;
493 }
495 /* Next, unmap the memory. */
496 if ( (rc = munmap(start_address, count * getpagesize())) )
497 return rc;
499 /* Finally, unmap the driver slots used to store the grant information. */
500 unmap_grant.index = get_offset.offset;
501 unmap_grant.count = count;
502 if ( (rc = ioctl(xcg_handle, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant)) )
503 return rc;
505 return 0;
506 }
508 /*
509 * Local variables:
510 * mode: C
511 * c-set-style: "BSD"
512 * c-basic-offset: 4
513 * tab-width: 4
514 * indent-tabs-mode: nil
515 * End:
516 */