VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/linux/SUPLib-linux.cpp@ 4925

Last change on this file since 4925 was 4925, checked in by vboxsync, 17 years ago

Added a LogRel with additional driver open info. Return the VERR_VM_DRIVER_* stuff on Solaris, Darwin, FreeBSD and OS/2 as well.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.4 KB
Line 
1/** @file
2 *
3 * VBox host drivers - Ring-0 support drivers - Linux host:
4 * Linux implementations for driver support library
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#include <sys/fcntl.h>
24#include <sys/ioctl.h>
25#include <sys/mman.h>
26#include <errno.h>
27#include <unistd.h>
28#include <stdlib.h>
29#include <malloc.h>
30#include <string.h>
31
32#include <VBox/sup.h>
33#include <VBox/types.h>
34#include <VBox/log.h>
35#include <iprt/path.h>
36#include <iprt/assert.h>
37#include <VBox/err.h>
38#include <VBox/param.h>
39#include "SUPLibInternal.h"
40#include "SUPDRVIOC.h"
41
42
43/*******************************************************************************
44* Defined Constants And Macros *
45*******************************************************************************/
46/** Unix Device name. */
47#define DEVICE_NAME "/dev/vboxdrv"
48
49/* define MADV_DONTFORK if it's missing from the system headers. */
50#ifndef MADV_DONTFORK
51# define MADV_DONTFORK 10
52#endif
53
54
55/*******************************************************************************
56* Global Variables *
57*******************************************************************************/
58/** Handle to the open device. */
59static int g_hDevice = -1;
60/** Flags whether or not we've loaded the kernel module. */
61static bool g_fLoadedModule = false;
62/** Indicates whether madvise(,,MADV_DONTFORK) works. */
63static bool g_fSysMadviseWorks = false;
64
65
66/*******************************************************************************
67* Internal Functions *
68*******************************************************************************/
69
70
71/**
72 * Initialize the OS specific part of the library.
73 * On Linux this involves:
74 * - loading the module.
75 * - open driver.
76 *
77 * @returns 0 on success.
78 * @returns current -1 on failure but this must be changed to proper error codes.
79 * @param cbReserved Ignored on linux.
80 */
81int suplibOsInit(size_t cbReserve)
82{
83 /*
84 * Check if already initialized.
85 */
86 if (g_hDevice >= 0)
87 return 0;
88
89 /*
90 * Try open the device.
91 */
92 g_hDevice = open(DEVICE_NAME, O_RDWR, 0);
93 if (g_hDevice < 0)
94 {
95 /*
96 * Try load the device.
97 */
98 //todo suplibOsLoadKernelModule();
99 g_hDevice = open(DEVICE_NAME, O_RDWR, 0);
100 if (g_hDevice < 0)
101 {
102 int rc;
103 switch (errno)
104 {
105 case ENXIO: /* see man 2 open, ENODEV is actually a kernel bug */
106 case ENODEV: rc = VERR_VM_DRIVER_LOAD_ERROR; break;
107 case EPERM:
108 case EACCES: rc = VERR_VM_DRIVER_NOT_ACCESSIBLE; break;
109 case ENOENT: rc = VERR_VM_DRIVER_NOT_INSTALLED; break;
110 default: rc = VERR_VM_DRIVER_OPEN_ERROR; break;
111 }
112 LogRel(("Failed to open \"%s\", errno=%d, rc=%Vrc\n", DEVICE_NAME, errno, rc));
113 return rc;
114 }
115 }
116
117 /*
118 * Mark the file handle close on exec.
119 */
120 if (fcntl(g_hDevice, F_SETFD, FD_CLOEXEC) == -1)
121 {
122 close(g_hDevice);
123 g_hDevice = -1;
124 return RTErrConvertFromErrno(errno);
125 }
126
127 /*
128 * Check if madvise works.
129 */
130 void *pv = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
131 if (pv == MAP_FAILED)
132 return VERR_NO_MEMORY;
133 g_fSysMadviseWorks = (0 == madvise(pv, PAGE_SIZE, MADV_DONTFORK));
134 munmap(pv, PAGE_SIZE);
135
136 /*
137 * We're done.
138 */
139 NOREF(cbReserve);
140 return 0;
141}
142
143
144int suplibOsTerm(void)
145{
146 /*
147 * Check if we're initited at all.
148 */
149 if (g_hDevice >= 0)
150 {
151 if (close(g_hDevice))
152 AssertFailed();
153 g_hDevice = -1;
154 }
155
156 /*
157 * If we started the service we might consider stopping it too.
158 *
159 * Since this won't work unless the the process starting it is the
160 * last user we might wanna skip this...
161 */
162 if (g_fLoadedModule)
163 {
164 //todo kernel module unloading.
165 //suplibOsStopService();
166 //g_fStartedService = false;
167 }
168
169 return 0;
170}
171
172
173/**
174 * Installs anything required by the support library.
175 *
176 * @returns 0 on success.
177 * @returns error code on failure.
178 */
179int suplibOsInstall(void)
180{
181 // nothing to do on Linux
182 return VERR_NOT_IMPLEMENTED;
183}
184
185
186/**
187 * Installs anything required by the support library.
188 *
189 * @returns 0 on success.
190 * @returns error code on failure.
191 */
192int suplibOsUninstall(void)
193{
194 // nothing to do on Linux
195 return VERR_NOT_IMPLEMENTED;
196}
197
198
199/**
200 * Send a I/O Control request to the device.
201 *
202 * @returns 0 on success.
203 * @returns VBOX error code on failure.
204 * @param uFunction IO Control function.
205 * @param pvReq The request buffer.
206 * @param cbReq The size of the request buffer.
207 */
208int suplibOsIOCtl(uintptr_t uFunction, void *pvReq, size_t cbReq)
209{
210 AssertMsg(g_hDevice != -1, ("SUPLIB not initiated successfully!\n"));
211
212 /*
213 * Issue device iocontrol.
214 */
215 if (RT_LIKELY(ioctl(g_hDevice, uFunction, pvReq) >= 0))
216 return VINF_SUCCESS;
217
218 /* This is the reverse operation of the one found in SUPDrv-linux.c */
219 switch (errno)
220 {
221 case EACCES: return VERR_GENERAL_FAILURE;
222 case EINVAL: return VERR_INVALID_PARAMETER;
223 case EILSEQ: return VERR_INVALID_MAGIC;
224 case ENXIO: return VERR_INVALID_HANDLE;
225 case EFAULT: return VERR_INVALID_POINTER;
226 case ENOLCK: return VERR_LOCK_FAILED;
227 case EEXIST: return VERR_ALREADY_LOADED;
228 case EPERM: return VERR_PERMISSION_DENIED;
229 case ENOSYS: return VERR_VERSION_MISMATCH;
230 case 1000: return VERR_IDT_FAILED;
231 }
232
233 return RTErrConvertFromErrno(errno);
234}
235
236
237/**
238 * Fast I/O Control path, no buffers.
239 *
240 * @returns VBox status code.
241 * @param uFunction The operation.
242 */
243int suplibOsIOCtlFast(uintptr_t uFunction)
244{
245 int rc = ioctl(g_hDevice, uFunction, NULL);
246 if (rc == -1)
247 rc = -errno;
248 return rc;
249}
250
251
252/**
253 * Allocate a number of zero-filled pages in user space.
254 *
255 * @returns VBox status code.
256 * @param cPages Number of pages to allocate.
257 * @param ppvPages Where to return the base pointer.
258 */
259int suplibOsPageAlloc(size_t cPages, void **ppvPages)
260{
261 size_t cbMmap = (g_fSysMadviseWorks ? cPages : cPages + 2) << PAGE_SHIFT;
262 char *pvPages = (char *)mmap(NULL, cbMmap, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
263 if (pvPages == MAP_FAILED)
264 return VERR_NO_MEMORY;
265
266 if (g_fSysMadviseWorks)
267 {
268 /*
269 * It is not fatal if we fail here but a forked child (e.g. the ALSA sound server)
270 * could crash. Linux < 2.6.16 does not implement madvise(MADV_DONTFORK) but the
271 * kernel seems to split bigger VMAs and that is all that we want -- later we set the
272 * VM_DONTCOPY attribute in supdrvOSLockMemOne().
273 */
274 if (madvise (pvPages, cbMmap, MADV_DONTFORK))
275 LogRel(("SUPLib: madvise %p-%p failed\n", pvPages, cbMmap));
276 *ppvPages = pvPages;
277 }
278 else
279 {
280 /*
281 * madvise(MADV_DONTFORK) is not available (most probably Linux 2.4). Enclose any
282 * mmapped region by two unmapped pages to guarantee that there is exactly one VM
283 * area struct of the very same size as the mmap area.
284 */
285 mprotect(pvPages, PAGE_SIZE, PROT_NONE);
286 mprotect(pvPages + cbMmap - PAGE_SIZE, PAGE_SIZE, PROT_NONE);
287 *ppvPages = pvPages + PAGE_SIZE;
288 }
289 memset(*ppvPages, 0, cPages << PAGE_SHIFT);
290 return VINF_SUCCESS;
291}
292
293
294/**
295 * Frees pages allocated by suplibOsPageAlloc().
296 *
297 * @returns VBox status code.
298 * @param pvPages Pointer to pages.
299 */
300int suplibOsPageFree(void *pvPages, size_t cPages)
301{
302 munmap(pvPages, cPages << PAGE_SHIFT);
303 return VINF_SUCCESS;
304}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette