[34] | 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 | |
---|
| 23 | int 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 | |
---|
| 59 | int xc_interface_close(int xc_handle) |
---|
| 60 | { |
---|
| 61 | return close(xc_handle); |
---|
| 62 | } |
---|
| 63 | |
---|
| 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; |
---|
| 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 | |
---|
| 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; |
---|
| 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 | |
---|
| 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; |
---|
| 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 | |
---|
| 128 | static int do_privcmd(int xc_handle, unsigned int cmd, unsigned long data) |
---|
| 129 | { |
---|
| 130 | return ioctl(xc_handle, cmd, data); |
---|
| 131 | } |
---|
| 132 | |
---|
| 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 | } |
---|
| 139 | |
---|
| 140 | #define MTAB "/proc/mounts" |
---|
| 141 | #define MAX_PATH 255 |
---|
| 142 | #define _STR(x) #x |
---|
| 143 | #define STR(x) _STR(x) |
---|
| 144 | |
---|
| 145 | static 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 | |
---|
| 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" }; |
---|
| 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 | |
---|
| 210 | int 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 | |
---|
| 238 | int xc_evtchn_close(int xce_handle) |
---|
| 239 | { |
---|
| 240 | return close(xce_handle); |
---|
| 241 | } |
---|
| 242 | |
---|
| 243 | int xc_evtchn_fd(int xce_handle) |
---|
| 244 | { |
---|
| 245 | return xce_handle; |
---|
| 246 | } |
---|
| 247 | |
---|
| 248 | int 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, ¬ify); |
---|
| 255 | } |
---|
| 256 | |
---|
| 257 | evtchn_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 | |
---|
| 266 | evtchn_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 | |
---|
| 277 | int 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 | |
---|
| 286 | evtchn_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 | |
---|
| 295 | static 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 | |
---|
| 320 | evtchn_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 | |
---|
| 330 | int 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 */ |
---|
| 336 | void 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 | |
---|
| 372 | int 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 | |
---|
| 385 | reopen: |
---|
| 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 | |
---|
| 400 | int xc_gnttab_close(int xcg_handle) |
---|
| 401 | { |
---|
| 402 | return close(xcg_handle); |
---|
| 403 | } |
---|
| 404 | |
---|
| 405 | void *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 | |
---|
| 436 | void *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 | |
---|
| 481 | int 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 | */ |
---|