VirtualBox

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

Last change on this file since 36796 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.3 KB
Line 
1/* $Id: SUPLib-linux.cpp 28800 2010-04-27 08:22:32Z vboxsync $ */
2/** @file
3 * VirtualBox Support Library - GNU/Linux specific parts.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#define LOG_GROUP LOG_GROUP_SUP
31#ifdef IN_SUP_HARDENED_R3
32# undef DEBUG /* Warning: disables RT_STRICT */
33# define LOG_DISABLED
34 /** @todo RTLOGREL_DISABLED */
35# include <iprt/log.h>
36# undef LogRelIt
37# define LogRelIt(pvInst, fFlags, iGroup, fmtargs) do { } while (0)
38#endif
39
40#include <sys/fcntl.h>
41#include <sys/ioctl.h>
42#include <sys/mman.h>
43#include <errno.h>
44#include <unistd.h>
45#include <stdlib.h>
46#include <malloc.h>
47
48#include <VBox/log.h>
49#include <VBox/sup.h>
50#include <iprt/path.h>
51#include <iprt/assert.h>
52#include <VBox/types.h>
53#include <iprt/string.h>
54#include <iprt/system.h>
55#include <VBox/err.h>
56#include <VBox/param.h>
57#include "../SUPLibInternal.h"
58#include "../SUPDrvIOC.h"
59
60
61/*******************************************************************************
62* Defined Constants And Macros *
63*******************************************************************************/
64/** Unix Device name. */
65#define DEVICE_NAME "/dev/vboxdrv"
66
67/* define MADV_DONTFORK if it's missing from the system headers. */
68#ifndef MADV_DONTFORK
69# define MADV_DONTFORK 10
70#endif
71
72
73
74int suplibOsInit(PSUPLIBDATA pThis, bool fPreInited)
75{
76 /*
77 * Nothing to do if pre-inited.
78 */
79 if (fPreInited)
80 return VINF_SUCCESS;
81 Assert(pThis->hDevice == NIL_RTFILE);
82
83 /*
84 * Check if madvise works.
85 */
86 void *pv = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
87 if (pv == MAP_FAILED)
88 return VERR_NO_MEMORY;
89 pThis->fSysMadviseWorks = (0 == madvise(pv, PAGE_SIZE, MADV_DONTFORK));
90 munmap(pv, PAGE_SIZE);
91
92 /*
93 * Try open the device.
94 */
95 int hDevice = open(DEVICE_NAME, O_RDWR, 0);
96 if (hDevice < 0)
97 {
98 /*
99 * Try load the device.
100 */
101 hDevice = open(DEVICE_NAME, O_RDWR, 0);
102 if (hDevice < 0)
103 {
104 int rc;
105 switch (errno)
106 {
107 case ENXIO: /* see man 2 open, ENODEV is actually a kernel bug */
108 case ENODEV: rc = VERR_VM_DRIVER_LOAD_ERROR; break;
109 case EPERM:
110 case EACCES: rc = VERR_VM_DRIVER_NOT_ACCESSIBLE; break;
111 case ENOENT: rc = VERR_VM_DRIVER_NOT_INSTALLED; break;
112 default: rc = VERR_VM_DRIVER_OPEN_ERROR; break;
113 }
114 LogRel(("Failed to open \"%s\", errno=%d, rc=%Rrc\n", DEVICE_NAME, errno, rc));
115 return rc;
116 }
117 }
118
119 /*
120 * Mark the file handle close on exec.
121 */
122 if (fcntl(hDevice, F_SETFD, FD_CLOEXEC) == -1)
123 {
124 close(hDevice);
125#ifdef IN_SUP_HARDENED_R3
126 return VERR_INTERNAL_ERROR;
127#else
128 return RTErrConvertFromErrno(errno);
129#endif
130 }
131
132 /*
133 * We're done.
134 */
135 pThis->hDevice = hDevice;
136 return VINF_SUCCESS;
137}
138
139
140#ifndef IN_SUP_HARDENED_R3
141
142int suplibOsTerm(PSUPLIBDATA pThis)
143{
144 /*
145 * Close the device if it's actually open.
146 */
147 if (pThis->hDevice != NIL_RTFILE)
148 {
149 if (close(pThis->hDevice))
150 AssertFailed();
151 pThis->hDevice = NIL_RTFILE;
152 }
153
154 return 0;
155}
156
157
158int suplibOsInstall(void)
159{
160 // nothing to do on Linux
161 return VERR_NOT_IMPLEMENTED;
162}
163
164
165int suplibOsUninstall(void)
166{
167 // nothing to do on Linux
168 return VERR_NOT_IMPLEMENTED;
169}
170
171
172int suplibOsIOCtl(PSUPLIBDATA pThis, uintptr_t uFunction, void *pvReq, size_t cbReq)
173{
174 AssertMsg(pThis->hDevice != NIL_RTFILE, ("SUPLIB not initiated successfully!\n"));
175
176 /*
177 * Issue device iocontrol.
178 */
179 if (RT_LIKELY(ioctl(pThis->hDevice, uFunction, pvReq) >= 0))
180 return VINF_SUCCESS;
181
182 /* This is the reverse operation of the one found in SUPDrv-linux.c */
183 switch (errno)
184 {
185 case EACCES: return VERR_GENERAL_FAILURE;
186 case EINVAL: return VERR_INVALID_PARAMETER;
187 case EILSEQ: return VERR_INVALID_MAGIC;
188 case ENXIO: return VERR_INVALID_HANDLE;
189 case EFAULT: return VERR_INVALID_POINTER;
190 case ENOLCK: return VERR_LOCK_FAILED;
191 case EEXIST: return VERR_ALREADY_LOADED;
192 case EPERM: return VERR_PERMISSION_DENIED;
193 case ENOSYS: return VERR_VERSION_MISMATCH;
194 case 1000: return VERR_IDT_FAILED;
195 }
196
197 return RTErrConvertFromErrno(errno);
198}
199
200
201int suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
202{
203 int rc = ioctl(pThis->hDevice, uFunction, idCpu);
204 if (rc == -1)
205 rc = -errno;
206 return rc;
207}
208
209
210int suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages)
211{
212 size_t cbMmap = (pThis->fSysMadviseWorks ? cPages : cPages + 2) << PAGE_SHIFT;
213 char *pvPages = (char *)mmap(NULL, cbMmap, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
214 if (pvPages == MAP_FAILED)
215 return VERR_NO_MEMORY;
216
217 if (pThis->fSysMadviseWorks)
218 {
219 /*
220 * It is not fatal if we fail here but a forked child (e.g. the ALSA sound server)
221 * could crash. Linux < 2.6.16 does not implement madvise(MADV_DONTFORK) but the
222 * kernel seems to split bigger VMAs and that is all that we want -- later we set the
223 * VM_DONTCOPY attribute in supdrvOSLockMemOne().
224 */
225 if (madvise (pvPages, cbMmap, MADV_DONTFORK))
226 LogRel(("SUPLib: madvise %p-%p failed\n", pvPages, cbMmap));
227 *ppvPages = pvPages;
228 }
229 else
230 {
231 /*
232 * madvise(MADV_DONTFORK) is not available (most probably Linux 2.4). Enclose any
233 * mmapped region by two unmapped pages to guarantee that there is exactly one VM
234 * area struct of the very same size as the mmap area.
235 */
236 mprotect(pvPages, PAGE_SIZE, PROT_NONE);
237 mprotect(pvPages + cbMmap - PAGE_SIZE, PAGE_SIZE, PROT_NONE);
238 *ppvPages = pvPages + PAGE_SIZE;
239 }
240 memset(*ppvPages, 0, cPages << PAGE_SHIFT);
241 return VINF_SUCCESS;
242}
243
244
245int suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t cPages)
246{
247 munmap(pvPages, cPages << PAGE_SHIFT);
248 return VINF_SUCCESS;
249}
250
251
252/** Check if the host kernel supports VT-x or not.
253 *
254 * Older Linux kernels clear the VMXE bit in the CR4 register (function
255 * tlb_flush_all()) leading to a host kernel panic.
256 */
257int suplibOsQueryVTxSupported(void)
258{
259 char szBuf[256];
260 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szBuf, sizeof(szBuf));
261
262 if (RT_SUCCESS(rc))
263 {
264 char *pszNext;
265 uint32_t uA, uB, uC;
266
267 rc = RTStrToUInt32Ex(szBuf, &pszNext, 10, &uA);
268 if ( RT_SUCCESS(rc)
269 && *pszNext == '.')
270 {
271 rc = RTStrToUInt32Ex(pszNext+1, &pszNext, 10, &uB);
272 if ( RT_SUCCESS(rc)
273 && *pszNext == '.')
274 {
275 rc = RTStrToUInt32Ex(pszNext+1, &pszNext, 10, &uC);
276 if (RT_SUCCESS(rc))
277 {
278 uint32_t uLinuxVersion = (uA << 16) + (uB << 8) + uC;
279 if (uLinuxVersion >= (2 << 16) + (6 << 8) + 13)
280 return VINF_SUCCESS;
281 }
282 }
283 }
284 }
285
286 return VERR_SUPDRV_KERNEL_TOO_OLD_FOR_VTX;
287}
288
289#endif /* !IN_SUP_HARDENED_R3 */
290
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