VirtualBox

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

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

pass VERR_IDT_FAILED correctly to userland

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.9 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/* define MADV_DONTFORK if it's missing from the system headers. */
54#ifndef MADV_DONTFORK
55# define MADV_DONTFORK 10
56#endif
57
58
59/*******************************************************************************
60* Global Variables *
61*******************************************************************************/
62/** Handle to the open device. */
63static int g_hDevice = -1;
64/** Flags whether or not we've loaded the kernel module. */
65static bool g_fLoadedModule = false;
66/** Indicates whether madvise(,,MADV_DONTFORK) works. */
67static bool g_fSysMadviseWorks = false;
68
69
70/*******************************************************************************
71* Internal Functions *
72*******************************************************************************/
73
74
75/**
76 * Initialize the OS specific part of the library.
77 * On Linux this involves:
78 * - loading the module.
79 * - open driver.
80 *
81 * @returns 0 on success.
82 * @returns current -1 on failure but this must be changed to proper error codes.
83 * @param cbReserved Ignored on linux.
84 */
85int suplibOsInit(size_t cbReserve)
86{
87 /*
88 * Check if already initialized.
89 */
90 if (g_hDevice >= 0)
91 return 0;
92
93 /*
94 * Try open the device.
95 */
96 g_hDevice = open(DEVICE_NAME, O_RDWR, 0);
97 if (g_hDevice < 0)
98 {
99 /*
100 * Try load the device.
101 */
102 //todo suplibOsLoadKernelModule();
103 g_hDevice = open(DEVICE_NAME, O_RDWR, 0);
104 if (g_hDevice < 0)
105 {
106 switch (errno)
107 {
108 case ENXIO: /* see man 2 open, ENODEV is actually a kernel bug */
109 case ENODEV: return VERR_VM_DRIVER_LOAD_ERROR;
110 case EPERM:
111 case EACCES: return VERR_VM_DRIVER_NOT_ACCESSIBLE;
112 case ENOENT: return VERR_VM_DRIVER_NOT_INSTALLED;
113 default:
114 return VERR_VM_DRIVER_OPEN_ERROR;
115 }
116 }
117 }
118
119 /*
120 * Mark the file handle close on exec.
121 */
122 if (fcntl(g_hDevice, F_SETFD, FD_CLOEXEC) == -1)
123 {
124 close(g_hDevice);
125 g_hDevice = -1;
126 return RTErrConvertFromErrno(errno);
127 }
128
129 /*
130 * Check if madvise works.
131 */
132 void *pv = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
133 if (!pv)
134 return VERR_NO_MEMORY;
135 g_fSysMadviseWorks = (0 == madvise(pv, PAGE_SIZE, MADV_DONTFORK));
136 munmap(pv, PAGE_SIZE);
137
138 /*
139 * We're done.
140 */
141 NOREF(cbReserve);
142 return 0;
143}
144
145
146int suplibOsTerm(void)
147{
148 /*
149 * Check if we're initited at all.
150 */
151 if (g_hDevice >= 0)
152 {
153 if (close(g_hDevice))
154 AssertFailed();
155 g_hDevice = -1;
156 }
157
158 /*
159 * If we started the service we might consider stopping it too.
160 *
161 * Since this won't work unless the the process starting it is the
162 * last user we might wanna skip this...
163 */
164 if (g_fLoadedModule)
165 {
166 //todo kernel module unloading.
167 //suplibOsStopService();
168 //g_fStartedService = false;
169 }
170
171 return 0;
172}
173
174
175/**
176 * Installs anything required by the support library.
177 *
178 * @returns 0 on success.
179 * @returns error code on failure.
180 */
181int suplibOsInstall(void)
182{
183 // nothing to do on Linux
184 return VERR_NOT_IMPLEMENTED;
185}
186
187
188/**
189 * Installs anything required by the support library.
190 *
191 * @returns 0 on success.
192 * @returns error code on failure.
193 */
194int suplibOsUninstall(void)
195{
196 // nothing to do on Linux
197 return VERR_NOT_IMPLEMENTED;
198}
199
200
201/**
202 * Send a I/O Control request to the device.
203 *
204 * @returns 0 on success.
205 * @returns VBOX error code on failure.
206 * @param uFunction IO Control function.
207 * @param pvIn Input data buffer.
208 * @param cbIn Size of input data.
209 * @param pvOut Output data buffer.
210 * @param cbOut Size of output data.
211 */
212int suplibOsIOCtl(unsigned uFunction, void *pvIn, size_t cbIn, void *pvOut, size_t cbOut)
213{
214 AssertMsg(g_hDevice != -1, ("SUPLIB not initiated successfully!\n"));
215 /*
216 * Issue device iocontrol.
217 */
218 SUPDRVIOCTLDATA Args;
219 Args.pvIn = pvIn;
220 Args.cbIn = cbIn;
221 Args.pvOut = pvOut;
222 Args.cbOut = cbOut;
223
224 if (ioctl(g_hDevice, uFunction, &Args) >= 0)
225 return VINF_SUCCESS;
226
227 /* This is the reverse operation of the one found in SUPDrv-linux.c */
228 switch (errno)
229 {
230 case EACCES: return VERR_GENERAL_FAILURE;
231 case EINVAL: return VERR_INVALID_PARAMETER;
232 case EILSEQ: return VERR_INVALID_MAGIC;
233 case ENXIO: return VERR_INVALID_HANDLE;
234 case EFAULT: return VERR_INVALID_POINTER;
235 case ENOLCK: return VERR_LOCK_FAILED;
236 case EEXIST: return VERR_ALREADY_LOADED;
237 case EPERM: return VERR_PERMISSION_DENIED;
238 case ENOSYS: return VERR_VERSION_MISMATCH;
239 case 1000: return VERR_IDT_FAILED;
240 }
241
242 return RTErrConvertFromErrno(errno);
243}
244
245
246/**
247 * Allocate a number of zero-filled pages in user space.
248 *
249 * @returns VBox status code.
250 * @param cPages Number of pages to allocate.
251 * @param ppvPages Where to return the base pointer.
252 */
253int suplibOsPageAlloc(size_t cPages, void **ppvPages)
254{
255#if 0
256 int rc = posix_memalign(ppvPages, PAGE_SIZE, cPages << PAGE_SHIFT)
257 if (!rc)
258 {
259 memset(*ppvPages, 0, cPages << PAGE_SHIFT);
260 return VINF_SUCCESS;
261 }
262 return RTErrConvertFromErrno(rc);
263#else
264 size_t cbMmap = (g_fSysMadviseWorks ? cPages : cPages + 2) << PAGE_SHIFT;
265 char *pvPages = (char *)mmap(NULL, cbMmap, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
266 if (pvPages)
267 {
268 if (g_fSysMadviseWorks)
269 {
270 /*
271 * It is not fatal if we fail here but a forked child (e.g. the ALSA sound server)
272 * could crash. Linux < 2.6.16 does not implement madvise(MADV_DONTFORK) but the
273 * kernel seems to split bigger VMAs and that is all that we want -- later we set the
274 * VM_DONTCOPY attribute in supdrvOSLockMemOne().
275 */
276 if (madvise (pvPages, cbMmap, MADV_DONTFORK))
277 LogRel(("SUPLib: madvise %p-%p failed\n", pvPages, cbMmap));
278 *ppvPages = pvPages;
279 }
280 else
281 {
282 /*
283 * madvise(MADV_DONTFORK) is not available (most probably Linux 2.4). Enclose any
284 * mmapped region by two unmapped pages to guarantee that there is exactly one VM
285 * area struct of the very same size as the mmap area.
286 */
287 mprotect(pvPages, PAGE_SIZE, PROT_NONE);
288 mprotect(pvPages + cbMmap - PAGE_SIZE, PAGE_SIZE, PROT_NONE);
289 *ppvPages = pvPages + PAGE_SIZE;
290 }
291 memset(*ppvPages, 0, cPages << PAGE_SHIFT);
292 return VINF_SUCCESS;
293 }
294 return VERR_NO_MEMORY;
295#endif
296}
297
298
299/**
300 * Frees pages allocated by suplibOsPageAlloc().
301 *
302 * @returns VBox status code.
303 * @param pvPages Pointer to pages.
304 */
305int suplibOsPageFree(void *pvPages, size_t cPages)
306{
307 munmap(pvPages, cPages << PAGE_SHIFT);
308 return VINF_SUCCESS;
309}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use