VirtualBox

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

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

The Big Sun Rebranding Header Change

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