VirtualBox

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

Last change on this file since 39304 was 39091, checked in by vboxsync, 13 years ago

More parameter warning fixes; made PciIch9 check the saved state version.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.5 KB
Line 
1/* $Id: SUPLib-linux.cpp 39091 2011-10-24 13:58:22Z 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 == (intptr_t)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 != (intptr_t)NIL_RTFILE)
148 {
149 if (close(pThis->hDevice))
150 AssertFailed();
151 pThis->hDevice = (intptr_t)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 != (intptr_t)NIL_RTFILE, ("SUPLIB not initiated successfully!\n"));
175 NOREF(cbReq);
176
177 /*
178 * Issue device iocontrol.
179 */
180 if (RT_LIKELY(ioctl(pThis->hDevice, uFunction, pvReq) >= 0))
181 return VINF_SUCCESS;
182
183 /* This is the reverse operation of the one found in SUPDrv-linux.c */
184 switch (errno)
185 {
186 case EACCES: return VERR_GENERAL_FAILURE;
187 case EINVAL: return VERR_INVALID_PARAMETER;
188 case EILSEQ: return VERR_INVALID_MAGIC;
189 case ENXIO: return VERR_INVALID_HANDLE;
190 case EFAULT: return VERR_INVALID_POINTER;
191 case ENOLCK: return VERR_LOCK_FAILED;
192 case EEXIST: return VERR_ALREADY_LOADED;
193 case EPERM: return VERR_PERMISSION_DENIED;
194 case ENOSYS: return VERR_VERSION_MISMATCH;
195 case 1000: return VERR_IDT_FAILED;
196 }
197
198 return RTErrConvertFromErrno(errno);
199}
200
201
202int suplibOsIOCtlFast(PSUPLIBDATA pThis, uintptr_t uFunction, uintptr_t idCpu)
203{
204 int rc = ioctl(pThis->hDevice, uFunction, idCpu);
205 if (rc == -1)
206 rc = -errno;
207 return rc;
208}
209
210
211int suplibOsPageAlloc(PSUPLIBDATA pThis, size_t cPages, void **ppvPages)
212{
213 size_t cbMmap = (pThis->fSysMadviseWorks ? cPages : cPages + 2) << PAGE_SHIFT;
214 char *pvPages = (char *)mmap(NULL, cbMmap, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
215 if (pvPages == MAP_FAILED)
216 return VERR_NO_MEMORY;
217
218 if (pThis->fSysMadviseWorks)
219 {
220 /*
221 * It is not fatal if we fail here but a forked child (e.g. the ALSA sound server)
222 * could crash. Linux < 2.6.16 does not implement madvise(MADV_DONTFORK) but the
223 * kernel seems to split bigger VMAs and that is all that we want -- later we set the
224 * VM_DONTCOPY attribute in supdrvOSLockMemOne().
225 */
226 if (madvise (pvPages, cbMmap, MADV_DONTFORK))
227 LogRel(("SUPLib: madvise %p-%p failed\n", pvPages, cbMmap));
228 *ppvPages = pvPages;
229 }
230 else
231 {
232 /*
233 * madvise(MADV_DONTFORK) is not available (most probably Linux 2.4). Enclose any
234 * mmapped region by two unmapped pages to guarantee that there is exactly one VM
235 * area struct of the very same size as the mmap area.
236 */
237 mprotect(pvPages, PAGE_SIZE, PROT_NONE);
238 mprotect(pvPages + cbMmap - PAGE_SIZE, PAGE_SIZE, PROT_NONE);
239 *ppvPages = pvPages + PAGE_SIZE;
240 }
241 memset(*ppvPages, 0, cPages << PAGE_SHIFT);
242 return VINF_SUCCESS;
243}
244
245
246int suplibOsPageFree(PSUPLIBDATA pThis, void *pvPages, size_t cPages)
247{
248 NOREF(pThis);
249 munmap(pvPages, cPages << PAGE_SHIFT);
250 return VINF_SUCCESS;
251}
252
253
254/** Check if the host kernel supports VT-x or not.
255 *
256 * Older Linux kernels clear the VMXE bit in the CR4 register (function
257 * tlb_flush_all()) leading to a host kernel panic.
258 */
259int suplibOsQueryVTxSupported(void)
260{
261 char szBuf[256];
262 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szBuf, sizeof(szBuf));
263
264 if (RT_SUCCESS(rc))
265 {
266 char *pszNext;
267 uint32_t uA, uB, uC;
268
269 rc = RTStrToUInt32Ex(szBuf, &pszNext, 10, &uA);
270 if ( RT_SUCCESS(rc)
271 && *pszNext == '.')
272 {
273 /*
274 * new version number scheme starting with Linux 3.0
275 */
276 if (uA >= 3)
277 return VINF_SUCCESS;
278 rc = RTStrToUInt32Ex(pszNext+1, &pszNext, 10, &uB);
279 if ( RT_SUCCESS(rc)
280 && *pszNext == '.')
281 {
282 rc = RTStrToUInt32Ex(pszNext+1, &pszNext, 10, &uC);
283 if (RT_SUCCESS(rc))
284 {
285 uint32_t uLinuxVersion = (uA << 16) + (uB << 8) + uC;
286 if (uLinuxVersion >= (2 << 16) + (6 << 8) + 13)
287 return VINF_SUCCESS;
288 }
289 }
290 }
291 }
292
293 return VERR_SUPDRV_KERNEL_TOO_OLD_FOR_VTX;
294}
295
296#endif /* !IN_SUP_HARDENED_R3 */
297
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