debuggers.hg

view tools/libxc/xc_linux.c @ 16408:f669bf5c6720

libxc: Consolidate read()/write() syscall wrappers to read/write an
exact number of bytes. The consolidated versions are more watertight
than the various versions previously distributed around the library
source code.
Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Sun Nov 11 18:22:33 2007 +0000 (2007-11-11)
parents fdffab15499d
children e948f402c356
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 return NULL;
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;
87 }
89 void *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;
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 }
116 int xc_map_foreign_ranges(int xc_handle, uint32_t dom,
117 privcmd_mmap_entry_t *entries, int nr)
118 {
119 privcmd_mmap_t ioctlx;
121 ioctlx.num = nr;
122 ioctlx.dom = dom;
123 ioctlx.entry = entries;
125 return ioctl(xc_handle, IOCTL_PRIVCMD_MMAP, &ioctlx);
126 }
128 static int do_privcmd(int xc_handle, unsigned int cmd, unsigned long data)
129 {
130 return ioctl(xc_handle, cmd, data);
131 }
133 int 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 }
140 #define MTAB "/proc/mounts"
141 #define MAX_PATH 255
142 #define _STR(x) #x
143 #define STR(x) _STR(x)
145 static int find_sysfsdir(char *sysfsdir)
146 {
147 FILE *fp;
148 char type[MAX_PATH + 1];
150 if ( (fp = fopen(MTAB, "r")) == NULL )
151 return -1;
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 }
164 fclose(fp);
166 return ((strncmp(type, "sysfs", 5) == 0) ? 0 : -1);
167 }
169 int 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" };
176 for ( i = 0; i < (sizeof(classlist) / sizeof(classlist[0])); i++ )
177 {
178 if ( find_sysfsdir(sysfsdir) < 0 )
179 goto not_found;
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);
188 if ( (fp = fopen(sysfsdir, "r")) != NULL )
189 goto found;
190 }
192 not_found:
193 errno = -ENOENT;
194 return -1;
196 found:
197 if ( fscanf(fp, "%d:%d", &major, &minor) != 2 )
198 {
199 fclose(fp);
200 goto not_found;
201 }
203 fclose(fp);
205 return makedev(major, minor);
206 }
208 #define EVTCHN_DEV_NAME "/dev/xen/evtchn"
210 int xc_evtchn_open(void)
211 {
212 struct stat st;
213 int fd;
214 int devnum;
216 devnum = xc_find_device_number("evtchn");
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);
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;
231 PERROR("Could not open event channel interface");
232 return -1;
233 }
235 return fd;
236 }
238 int xc_evtchn_close(int xce_handle)
239 {
240 return close(xce_handle);
241 }
243 int xc_evtchn_fd(int xce_handle)
244 {
245 return xce_handle;
246 }
248 int xc_evtchn_notify(int xce_handle, evtchn_port_t port)
249 {
250 struct ioctl_evtchn_notify notify;
252 notify.port = port;
254 return ioctl(xce_handle, IOCTL_EVTCHN_NOTIFY, &notify);
255 }
257 evtchn_port_or_error_t
258 xc_evtchn_bind_unbound_port(int xce_handle, int domid)
259 {
260 struct ioctl_evtchn_bind_unbound_port bind;
262 bind.remote_domain = domid;
264 return ioctl(xce_handle, IOCTL_EVTCHN_BIND_UNBOUND_PORT, &bind);
265 }
267 evtchn_port_or_error_t
268 xc_evtchn_bind_interdomain(int xce_handle, int domid,
269 evtchn_port_t remote_port)
270 {
271 struct ioctl_evtchn_bind_interdomain bind;
273 bind.remote_domain = domid;
274 bind.remote_port = remote_port;
276 return ioctl(xce_handle, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
277 }
279 evtchn_port_or_error_t
280 xc_evtchn_bind_virq(int xce_handle, unsigned int virq)
281 {
282 struct ioctl_evtchn_bind_virq bind;
284 bind.virq = virq;
286 return ioctl(xce_handle, IOCTL_EVTCHN_BIND_VIRQ, &bind);
287 }
289 int xc_evtchn_unbind(int xce_handle, evtchn_port_t port)
290 {
291 struct ioctl_evtchn_unbind unbind;
293 unbind.port = port;
295 return ioctl(xce_handle, IOCTL_EVTCHN_UNBIND, &unbind);
296 }
298 evtchn_port_or_error_t
299 xc_evtchn_pending(int xce_handle)
300 {
301 evtchn_port_t port;
303 if ( read_exact(xce_handle, (char *)&port, sizeof(port)) == -1 )
304 return -1;
306 return port;
307 }
309 int xc_evtchn_unmask(int xce_handle, evtchn_port_t port)
310 {
311 return write_exact(xce_handle, (char *)&port, sizeof(port));
312 }
314 /* Optionally flush file to disk and discard page cache */
315 void discard_file_cache(int fd, int flush)
316 {
317 off_t cur = 0;
318 int saved_errno = errno;
320 if ( flush && (fsync(fd) < 0) )
321 {
322 /*PERROR("Failed to flush file: %s", strerror(errno));*/
323 goto out;
324 }
326 /*
327 * Calculate last page boundary of amount written so far
328 * unless we are flushing in which case entire cache
329 * is discarded.
330 */
331 if ( !flush )
332 {
333 if ( (cur = lseek(fd, 0, SEEK_CUR)) == (off_t)-1 )
334 cur = 0;
335 cur &= ~(PAGE_SIZE-1);
336 }
338 /* Discard from the buffer cache. */
339 if ( posix_fadvise64(fd, 0, cur, POSIX_FADV_DONTNEED) < 0 )
340 {
341 /*PERROR("Failed to discard cache: %s", strerror(errno));*/
342 goto out;
343 }
345 out:
346 errno = saved_errno;
347 }
349 #define GNTTAB_DEV_NAME "/dev/xen/gntdev"
351 int xc_gnttab_open(void)
352 {
353 struct stat st;
354 int fd;
355 int devnum;
357 devnum = xc_find_device_number("gntdev");
359 /* Make sure any existing device file links to correct device. */
360 if ( (lstat(GNTTAB_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
361 (st.st_rdev != devnum) )
362 (void)unlink(GNTTAB_DEV_NAME);
364 reopen:
365 if ( (fd = open(GNTTAB_DEV_NAME, O_RDWR)) == -1 )
366 {
367 if ( (errno == ENOENT) &&
368 ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
369 (mknod(GNTTAB_DEV_NAME, S_IFCHR|0600, devnum) == 0) )
370 goto reopen;
372 PERROR("Could not open grant table interface");
373 return -1;
374 }
376 return fd;
377 }
379 int xc_gnttab_close(int xcg_handle)
380 {
381 return close(xcg_handle);
382 }
384 void *xc_gnttab_map_grant_ref(int xcg_handle,
385 uint32_t domid,
386 uint32_t ref,
387 int prot)
388 {
389 struct ioctl_gntdev_map_grant_ref map;
390 void *addr;
392 map.count = 1;
393 map.refs[0].domid = domid;
394 map.refs[0].ref = ref;
396 if ( ioctl(xcg_handle, IOCTL_GNTDEV_MAP_GRANT_REF, &map) )
397 return NULL;
399 addr = mmap(NULL, PAGE_SIZE, prot, MAP_SHARED, xcg_handle, map.index);
400 if ( addr == MAP_FAILED )
401 {
402 int saved_errno = errno;
403 struct ioctl_gntdev_unmap_grant_ref unmap_grant;
404 /* Unmap the driver slots used to store the grant information. */
405 unmap_grant.index = map.index;
406 unmap_grant.count = 1;
407 ioctl(xcg_handle, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant);
408 errno = saved_errno;
409 return NULL;
410 }
412 return addr;
413 }
415 void *xc_gnttab_map_grant_refs(int xcg_handle,
416 uint32_t count,
417 uint32_t *domids,
418 uint32_t *refs,
419 int prot)
420 {
421 struct ioctl_gntdev_map_grant_ref *map;
422 void *addr = NULL;
423 int i;
425 map = malloc(sizeof(*map) +
426 (count-1) * sizeof(struct ioctl_gntdev_map_grant_ref));
427 if ( map == NULL )
428 return NULL;
430 for ( i = 0; i < count; i++ )
431 {
432 map->refs[i].domid = domids[i];
433 map->refs[i].ref = refs[i];
434 }
436 map->count = count;
438 if ( ioctl(xcg_handle, IOCTL_GNTDEV_MAP_GRANT_REF, map) )
439 goto out;
441 addr = mmap(NULL, PAGE_SIZE * count, prot, MAP_SHARED, xcg_handle,
442 map->index);
443 if ( addr == MAP_FAILED )
444 {
445 int saved_errno = errno;
446 struct ioctl_gntdev_unmap_grant_ref unmap_grant;
447 /* Unmap the driver slots used to store the grant information. */
448 unmap_grant.index = map->index;
449 unmap_grant.count = count;
450 ioctl(xcg_handle, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant);
451 errno = saved_errno;
452 addr = NULL;
453 }
455 out:
456 free(map);
457 return addr;
458 }
460 int xc_gnttab_munmap(int xcg_handle,
461 void *start_address,
462 uint32_t count)
463 {
464 struct ioctl_gntdev_get_offset_for_vaddr get_offset;
465 struct ioctl_gntdev_unmap_grant_ref unmap_grant;
466 int rc;
468 if ( start_address == NULL )
469 {
470 errno = EINVAL;
471 return -1;
472 }
474 /* First, it is necessary to get the offset which was initially used to
475 * mmap() the pages.
476 */
477 get_offset.vaddr = (unsigned long)start_address;
478 if ( (rc = ioctl(xcg_handle, IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR,
479 &get_offset)) )
480 return rc;
482 if ( get_offset.count != count )
483 {
484 errno = EINVAL;
485 return -1;
486 }
488 /* Next, unmap the memory. */
489 if ( (rc = munmap(start_address, count * getpagesize())) )
490 return rc;
492 /* Finally, unmap the driver slots used to store the grant information. */
493 unmap_grant.index = get_offset.offset;
494 unmap_grant.count = count;
495 if ( (rc = ioctl(xcg_handle, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant)) )
496 return rc;
498 return 0;
499 }
501 /*
502 * Local variables:
503 * mode: C
504 * c-set-style: "BSD"
505 * c-basic-offset: 4
506 * tab-width: 4
507 * indent-tabs-mode: nil
508 * End:
509 */