VirtualBox

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

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

Redid the supdrv interface. works on windows and linux while the other OSes still needs some adjusting/testing. internal networking is temporarily broken as the SUPCallVMMR0Ex interface is being reworked (this is what all this is really about).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.0 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.215389.xyz. 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 switch (errno)
103 {
104 case ENXIO: /* see man 2 open, ENODEV is actually a kernel bug */
105 case ENODEV: return VERR_VM_DRIVER_LOAD_ERROR;
106 case EPERM:
107 case EACCES: return VERR_VM_DRIVER_NOT_ACCESSIBLE;
108 case ENOENT: return VERR_VM_DRIVER_NOT_INSTALLED;
109 default:
110 return VERR_VM_DRIVER_OPEN_ERROR;
111 }
112 }
113 }
114
115 /*
116 * Mark the file handle close on exec.
117 */
118 if (fcntl(g_hDevice, F_SETFD, FD_CLOEXEC) == -1)
119 {
120 close(g_hDevice);
121 g_hDevice = -1;
122 return RTErrConvertFromErrno(errno);
123 }
124
125 /*
126 * Check if madvise works.
127 */
128 void *pv = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
129 if (pv == MAP_FAILED)
130 return VERR_NO_MEMORY;
131 g_fSysMadviseWorks = (0 == madvise(pv, PAGE_SIZE, MADV_DONTFORK));
132 munmap(pv, PAGE_SIZE);
133
134 /*
135 * We're done.
136 */
137 NOREF(cbReserve);
138 return 0;
139}
140
141
142int suplibOsTerm(void)
143{
144 /*
145 * Check if we're initited at all.
146 */
147 if (g_hDevice >= 0)
148 {
149 if (close(g_hDevice))
150 AssertFailed();
151 g_hDevice = -1;
152 }
153
154 /*
155 * If we started the service we might consider stopping it too.
156 *
157 * Since this won't work unless the the process starting it is the
158 * last user we might wanna skip this...
159 */
160 if (g_fLoadedModule)
161 {
162 //todo kernel module unloading.
163 //suplibOsStopService();
164 //g_fStartedService = false;
165 }
166
167 return 0;
168}
169
170
171/**
172 * Installs anything required by the support library.
173 *
174 * @returns 0 on success.
175 * @returns error code on failure.
176 */
177int suplibOsInstall(void)
178{
179 // nothing to do on Linux
180 return VERR_NOT_IMPLEMENTED;
181}
182
183
184/**
185 * Installs anything required by the support library.
186 *
187 * @returns 0 on success.
188 * @returns error code on failure.
189 */
190int suplibOsUninstall(void)
191{
192 // nothing to do on Linux
193 return VERR_NOT_IMPLEMENTED;
194}
195
196
197/**
198 * Send a I/O Control request to the device.
199 *
200 * @returns 0 on success.
201 * @returns VBOX error code on failure.
202 * @param uFunction IO Control function.
203 * @param pvReq The request buffer.
204 * @param cbReq The size of the request buffer.
205 */
206int suplibOsIOCtl(uintptr_t uFunction, void *pvReq, size_t cbReq)
207{
208 AssertMsg(g_hDevice != -1, ("SUPLIB not initiated successfully!\n"));
209
210 /*
211 * Issue device iocontrol.
212 */
213 if (RT_LIKELY(ioctl(g_hDevice, uFunction, pvReq) >= 0))
214 return VINF_SUCCESS;
215
216 /* This is the reverse operation of the one found in SUPDrv-linux.c */
217 switch (errno)
218 {
219 case EACCES: return VERR_GENERAL_FAILURE;
220 case EINVAL: return VERR_INVALID_PARAMETER;
221 case EILSEQ: return VERR_INVALID_MAGIC;
222 case ENXIO: return VERR_INVALID_HANDLE;
223 case EFAULT: return VERR_INVALID_POINTER;
224 case ENOLCK: return VERR_LOCK_FAILED;
225 case EEXIST: return VERR_ALREADY_LOADED;
226 case EPERM: return VERR_PERMISSION_DENIED;
227 case ENOSYS: return VERR_VERSION_MISMATCH;
228 case 1000: return VERR_IDT_FAILED;
229 }
230
231 return RTErrConvertFromErrno(errno);
232}
233
234
235/**
236 * Allocate a number of zero-filled pages in user space.
237 *
238 * @returns VBox status code.
239 * @param cPages Number of pages to allocate.
240 * @param ppvPages Where to return the base pointer.
241 */
242int suplibOsPageAlloc(size_t cPages, void **ppvPages)
243{
244 size_t cbMmap = (g_fSysMadviseWorks ? cPages : cPages + 2) << PAGE_SHIFT;
245 char *pvPages = (char *)mmap(NULL, cbMmap, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
246 if (pvPages == MAP_FAILED)
247 return VERR_NO_MEMORY;
248
249 if (g_fSysMadviseWorks)
250 {
251 /*
252 * It is not fatal if we fail here but a forked child (e.g. the ALSA sound server)
253 * could crash. Linux < 2.6.16 does not implement madvise(MADV_DONTFORK) but the
254 * kernel seems to split bigger VMAs and that is all that we want -- later we set the
255 * VM_DONTCOPY attribute in supdrvOSLockMemOne().
256 */
257 if (madvise (pvPages, cbMmap, MADV_DONTFORK))
258 LogRel(("SUPLib: madvise %p-%p failed\n", pvPages, cbMmap));
259 *ppvPages = pvPages;
260 }
261 else
262 {
263 /*
264 * madvise(MADV_DONTFORK) is not available (most probably Linux 2.4). Enclose any
265 * mmapped region by two unmapped pages to guarantee that there is exactly one VM
266 * area struct of the very same size as the mmap area.
267 */
268 mprotect(pvPages, PAGE_SIZE, PROT_NONE);
269 mprotect(pvPages + cbMmap - PAGE_SIZE, PAGE_SIZE, PROT_NONE);
270 *ppvPages = pvPages + PAGE_SIZE;
271 }
272 memset(*ppvPages, 0, cPages << PAGE_SHIFT);
273 return VINF_SUCCESS;
274}
275
276
277/**
278 * Frees pages allocated by suplibOsPageAlloc().
279 *
280 * @returns VBox status code.
281 * @param pvPages Pointer to pages.
282 */
283int suplibOsPageFree(void *pvPages, size_t cPages)
284{
285 munmap(pvPages, cPages << PAGE_SHIFT);
286 return VINF_SUCCESS;
287}
Note: See TracBrowser for help on using the repository browser.

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