VirtualBox

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

Last change on this file since 1959 was 1890, checked in by vboxsync, 18 years ago

Attempt to fix ALSA on Linux kernels <= 2.6.17: use mmap not memalign for allocating pages. Use madvise or mprotect to separater VM area structs inside the kernel. Most SUP* functions work on cPages now (not cBytes anymore). The free functions take a cPages parameter which is used for munmap on Linux.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.8 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 InnoTek Systemberatung 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 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <sys/fcntl.h>
28#include <sys/ioctl.h>
29#include <sys/mman.h>
30#include <errno.h>
31#include <unistd.h>
32#include <stdlib.h>
33#include <malloc.h>
34#include <string.h>
35
36#include <VBox/sup.h>
37#include <VBox/types.h>
38#include <VBox/log.h>
39#include <iprt/path.h>
40#include <iprt/assert.h>
41#include <VBox/err.h>
42#include <VBox/param.h>
43#include "SUPLibInternal.h"
44#include "SUPDRVIOC.h"
45
46
47/*******************************************************************************
48* Defined Constants And Macros *
49*******************************************************************************/
50/** Unix Device name. */
51#define DEVICE_NAME "/dev/vboxdrv"
52
53#ifndef MADV_DONTFORK
54#define MADV_DONTFORK 10
55#endif
56
57
58/*******************************************************************************
59* Global Variables *
60*******************************************************************************/
61/** Handle to the open device. */
62static int g_hDevice = -1;
63/** Flags whether or not we've loaded the kernel module. */
64static bool g_fLoadedModule = false;
65/** Checks */
66static bool g_fSysMadviseWorks = false;
67
68
69/*******************************************************************************
70* Internal Functions *
71*******************************************************************************/
72
73
74/**
75 * Initialize the OS specific part of the library.
76 * On Linux this involves:
77 * - loading the module.
78 * - open driver.
79 *
80 * @returns 0 on success.
81 * @returns current -1 on failure but this must be changed to proper error codes.
82 * @param cbReserved Ignored on linux.
83 */
84int suplibOsInit(size_t cbReserve)
85{
86 /*
87 * Check if already initialized.
88 */
89 if (g_hDevice >= 0)
90 return 0;
91
92 /*
93 * Try open the device.
94 */
95 g_hDevice = open(DEVICE_NAME, O_RDWR, 0);
96 if (g_hDevice < 0)
97 {
98 /*
99 * Try load the device.
100 */
101 //todo suplibOsLoadKernelModule();
102 g_hDevice = open(DEVICE_NAME, O_RDWR, 0);
103 if (g_hDevice < 0)
104 {
105 switch (errno)
106 {
107 case ENXIO: /* see man 2 open, ENODEV is actually a kernel bug */
108 case ENODEV: return VERR_VM_DRIVER_LOAD_ERROR;
109 case EPERM:
110 case EACCES: return VERR_VM_DRIVER_NOT_ACCESSIBLE;
111 case ENOENT: return VERR_VM_DRIVER_NOT_INSTALLED;
112 default:
113 return VERR_VM_DRIVER_OPEN_ERROR;
114 }
115 }
116 }
117
118 /*
119 * Mark the file handle close on exec.
120 */
121 if (fcntl(g_hDevice, F_SETFD, FD_CLOEXEC) == -1)
122 {
123 close(g_hDevice);
124 g_hDevice = -1;
125 return RTErrConvertFromErrno(errno);
126 }
127
128 /*
129 * Check driver version.
130 */
131 /** @todo implement driver version checking. */
132
133 /*
134 * Check if madvise works.
135 */
136 void *pv = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
137 if (!pv)
138 return VERR_NO_MEMORY;
139 g_fSysMadviseWorks = (0 == madvise(pv, PAGE_SIZE, MADV_DONTFORK));
140 munmap(pv, PAGE_SIZE);
141
142 /*
143 * We're done.
144 */
145 NOREF(cbReserve);
146 return 0;
147}
148
149
150int suplibOsTerm(void)
151{
152 /*
153 * Check if we're initited at all.
154 */
155 if (g_hDevice >= 0)
156 {
157 if (close(g_hDevice))
158 AssertFailed();
159 g_hDevice = -1;
160 }
161
162 /*
163 * If we started the service we might consider stopping it too.
164 *
165 * Since this won't work unless the the process starting it is the
166 * last user we might wanna skip this...
167 */
168 if (g_fLoadedModule)
169 {
170 //todo kernel module unloading.
171 //suplibOsStopService();
172 //g_fStartedService = false;
173 }
174
175 return 0;
176}
177
178
179/**
180 * Installs anything required by the support library.
181 *
182 * @returns 0 on success.
183 * @returns error code on failure.
184 */
185int suplibOsInstall(void)
186{
187 // nothing to do on Linux
188 return VERR_NOT_IMPLEMENTED;
189}
190
191
192/**
193 * Installs anything required by the support library.
194 *
195 * @returns 0 on success.
196 * @returns error code on failure.
197 */
198int suplibOsUninstall(void)
199{
200 // nothing to do on Linux
201 return VERR_NOT_IMPLEMENTED;
202}
203
204
205/**
206 * Send a I/O Control request to the device.
207 *
208 * @returns 0 on success.
209 * @returns VBOX error code on failure.
210 * @param uFunction IO Control function.
211 * @param pvIn Input data buffer.
212 * @param cbIn Size of input data.
213 * @param pvOut Output data buffer.
214 * @param cbOut Size of output data.
215 */
216int suplibOsIOCtl(unsigned uFunction, void *pvIn, size_t cbIn, void *pvOut, size_t cbOut)
217{
218 AssertMsg(g_hDevice != -1, ("SUPLIB not initiated successfully!\n"));
219 /*
220 * Issue device iocontrol.
221 */
222 SUPDRVIOCTLDATA Args;
223 Args.pvIn = pvIn;
224 Args.cbIn = cbIn;
225 Args.pvOut = pvOut;
226 Args.cbOut = cbOut;
227
228 if (ioctl(g_hDevice, uFunction, &Args) >= 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 }
244
245 return RTErrConvertFromErrno(errno);
246}
247
248
249/**
250 * Allocate a number of zero-filled pages in user space.
251 *
252 * @returns VBox status code.
253 * @param cPages Number of pages to allocate.
254 * @param ppvPages Where to return the base pointer.
255 */
256int suplibOsPageAlloc(size_t cPages, void **ppvPages)
257{
258#if 0
259 int rc = posix_memalign(ppvPages, PAGE_SIZE, cPages << PAGE_SHIFT)
260 if (!rc)
261 {
262 memset(*ppvPages, 0, cPages << PAGE_SHIFT);
263 return VINF_SUCCESS;
264 }
265 return RTErrConvertFromErrno(rc);
266#else
267 size_t cbMmap = (g_fSysMadviseWorks ? cPages : cPages + 2) << PAGE_SHIFT;
268 char *pvPages = (char*)mmap(NULL, cbMmap, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
269 if (pvPages)
270 {
271 if (g_fSysMadviseWorks)
272 {
273 /*
274 * It is not fatal if we fail here but a forked child (e.g. the ALSA sound server)
275 * could crash. Linux < 2.6.16 does not implement madvise(MADV_DONTFORK) but the
276 * kernel seems to split bigger VMAs and that is all that we want -- later we set the
277 * VM_DONTCOPY attribute in supdrvOSLockMemOne().
278 */
279 if (madvise (pvPages, cbMmap, MADV_DONTFORK))
280 LogRel(("SUPLib: madvise %p-%p failed\n", pvPages, cbMmap));
281 *ppvPages = pvPages;
282 }
283 else
284 {
285 /*
286 * madvise(MADV_DONTFORK) is not available (most probably Linux 2.4). Enclose any
287 * mmapped region by two unmapped pages to guarantee that there is exactly one VM
288 * area struct of the very same size as the mmap area.
289 */
290 mprotect(pvPages, PAGE_SIZE, PROT_NONE);
291 mprotect(pvPages + cbMmap - PAGE_SIZE, PAGE_SIZE, PROT_NONE);
292 *ppvPages = pvPages + PAGE_SIZE;
293 }
294 memset(*ppvPages, 0, cPages << PAGE_SHIFT);
295 return VINF_SUCCESS;
296 }
297 return VERR_NO_MEMORY;
298#endif
299}
300
301
302/**
303 * Frees pages allocated by suplibOsPageAlloc().
304 *
305 * @returns VBox status code.
306 * @param pvPages Pointer to pages.
307 */
308int suplibOsPageFree(void *pvPages, size_t cPages)
309{
310 munmap(pvPages, cPages << PAGE_SHIFT);
311 return VINF_SUCCESS;
312}
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