1 /*
2 * This library is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation;
5 * version 2.1 of the License.
6 *
7 * This library 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 GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
14 *
15 * Split out from xc_linus_osdep.c:
16 *
17 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
18 */
19
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <unistd.h>
23
24 #include <stdlib.h>
25 #include <assert.h>
26 #include <stdio.h>
27
28 #include <sys/mman.h>
29 #include <sys/ioctl.h>
30
31 #include "private.h"
32
33 #ifndef O_CLOEXEC
34 #define O_CLOEXEC 0
35 #endif
36
osdep_xencall_open(xencall_handle * xcall)37 int osdep_xencall_open(xencall_handle *xcall)
38 {
39 int fd;
40
41 /*
42 * Prefer the newer interface.
43 */
44 fd = open("/dev/xen/privcmd", O_RDWR|O_CLOEXEC);
45
46 if ( fd == -1 && ( errno == ENOENT || errno == ENXIO || errno == ENODEV ))
47 {
48 /* Fallback to /proc/xen/privcmd */
49 fd = open("/proc/xen/privcmd", O_RDWR|O_CLOEXEC);
50 }
51
52 if ( fd == -1 )
53 {
54 PERROR("Could not obtain handle on privileged command interface");
55 return -1;
56 }
57
58 xcall->fd = fd;
59 return 0;
60 }
61
osdep_xencall_close(xencall_handle * xcall)62 int osdep_xencall_close(xencall_handle *xcall)
63 {
64 int fd = xcall->fd;
65 if (fd == -1)
66 return 0;
67 return close(fd);
68 }
69
osdep_hypercall(xencall_handle * xcall,privcmd_hypercall_t * hypercall)70 int osdep_hypercall(xencall_handle *xcall, privcmd_hypercall_t *hypercall)
71 {
72 return ioctl(xcall->fd, IOCTL_PRIVCMD_HYPERCALL, hypercall);
73 }
74
osdep_alloc_pages(xencall_handle * xcall,size_t npages)75 void *osdep_alloc_pages(xencall_handle *xcall, size_t npages)
76 {
77 size_t size = npages * PAGE_SIZE;
78 void *p;
79 int rc, i, saved_errno;
80
81 /* Address returned by mmap is page aligned. */
82 p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_LOCKED, -1, 0);
83 if ( p == MAP_FAILED )
84 {
85 PERROR("alloc_pages: mmap failed");
86 return NULL;
87 }
88
89 /* Do not copy the VMA to child process on fork. Avoid the page being COW
90 on hypercall. */
91 rc = madvise(p, npages * PAGE_SIZE, MADV_DONTFORK);
92 if ( rc < 0 )
93 {
94 PERROR("alloc_pages: madvise failed");
95 goto out;
96 }
97
98 /*
99 * Touch each page in turn to force them to be un-CoWed, in case a
100 * fork happened in another thread at an inopportune moment
101 * above. The madvise() will prevent any subsequent fork calls from
102 * causing the same problem.
103 */
104 for ( i = 0; i < npages ; i++ )
105 {
106 char *c = (char *)p + (i*PAGE_SIZE);
107 *c = 0;
108 }
109
110 return p;
111
112 out:
113 saved_errno = errno;
114 (void)munmap(p, size);
115 errno = saved_errno;
116 return NULL;
117 }
118
osdep_free_pages(xencall_handle * xcall,void * ptr,size_t npages)119 void osdep_free_pages(xencall_handle *xcall, void *ptr, size_t npages)
120 {
121 int saved_errno = errno;
122 /* Recover the VMA flags. Maybe it's not necessary */
123 madvise(ptr, npages * PAGE_SIZE, MADV_DOFORK);
124
125 munmap(ptr, npages * PAGE_SIZE);
126 /* We MUST propagate the hypercall errno, not unmap call's. */
127 errno = saved_errno;
128 }
129
130 /*
131 * Local variables:
132 * mode: C
133 * c-file-style: "BSD"
134 * c-basic-offset: 4
135 * tab-width: 4
136 * indent-tabs-mode: nil
137 * End:
138 */
139