VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c@ 43435

Last change on this file since 43435 was 43435, checked in by vboxsync, 12 years ago

Support/FreeBSD: Add SUPDRV_WITH_RELEASE_LOGGER and change RTR0Term to RTR0TermForced (thanks to Ed Maste)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.2 KB
Line 
1/* $Id: SUPDrv-freebsd.c 43435 2012-09-26 09:31:17Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - FreeBSD specifics.
4 */
5
6/*
7 * Copyright (c) 2007 knut st. osmundsen <[email protected]>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#define LOG_GROUP LOG_GROUP_SUP_DRV
35/* Deal with conflicts first. */
36#include <sys/param.h>
37#undef PVM
38#include <sys/types.h>
39#include <sys/module.h>
40#include <sys/systm.h>
41#include <sys/errno.h>
42#include <sys/kernel.h>
43#include <sys/fcntl.h>
44#include <sys/conf.h>
45#include <sys/uio.h>
46
47#include "../SUPDrvInternal.h"
48#include <VBox/version.h>
49#include <iprt/initterm.h>
50#include <iprt/string.h>
51#include <iprt/spinlock.h>
52#include <iprt/process.h>
53#include <iprt/assert.h>
54#include <iprt/uuid.h>
55#include <VBox/log.h>
56#include <iprt/alloc.h>
57#include <iprt/err.h>
58#include <iprt/asm.h>
59
60#ifdef VBOX_WITH_HARDENING
61# define VBOXDRV_PERM 0600
62#else
63# define VBOXDRV_PERM 0666
64#endif
65
66/*******************************************************************************
67* Internal Functions *
68*******************************************************************************/
69static int VBoxDrvFreeBSDModuleEvent(struct module *pMod, int enmEventType, void *pvArg);
70static int VBoxDrvFreeBSDLoad(void);
71static int VBoxDrvFreeBSDUnload(void);
72
73static d_open_t VBoxDrvFreeBSDOpen;
74static void VBoxDrvFreeBSDDtr(void *pData);
75static d_ioctl_t VBoxDrvFreeBSDIOCtl;
76static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd);
77
78
79/*******************************************************************************
80* Global Variables *
81*******************************************************************************/
82/**
83 * Module info structure used by the kernel.
84 */
85static moduledata_t g_VBoxDrvFreeBSDModule =
86{
87 "vboxdrv",
88 VBoxDrvFreeBSDModuleEvent,
89 NULL
90};
91
92/** Declare the module as a pseudo device. */
93DECLARE_MODULE(vboxdrv, g_VBoxDrvFreeBSDModule, SI_SUB_PSEUDO, SI_ORDER_ANY);
94MODULE_VERSION(vboxdrv, 1);
95
96/**
97 * The /dev/vboxdrv character device entry points.
98 */
99static struct cdevsw g_VBoxDrvFreeBSDChrDevSW =
100{
101 .d_version = D_VERSION,
102 .d_open = VBoxDrvFreeBSDOpen,
103 .d_ioctl = VBoxDrvFreeBSDIOCtl,
104 .d_name = "vboxdrv"
105};
106
107/** The /dev/vboxdrv character device. */
108static struct cdev *g_pVBoxDrvFreeBSDChrDev;
109/** Reference counter. */
110static volatile uint32_t g_cUsers;
111
112/** The device extention. */
113static SUPDRVDEVEXT g_VBoxDrvFreeBSDDevExt;
114
115/**
116 * Module event handler.
117 *
118 * @param pMod The module structure.
119 * @param enmEventType The event type (modeventtype_t).
120 * @param pvArg Module argument. NULL.
121 *
122 * @return 0 on success, errno.h status code on failure.
123 */
124static int VBoxDrvFreeBSDModuleEvent(struct module *pMod, int enmEventType, void *pvArg)
125{
126 int rc;
127 switch (enmEventType)
128 {
129 case MOD_LOAD:
130 rc = VBoxDrvFreeBSDLoad();
131 break;
132
133 case MOD_UNLOAD:
134 mtx_unlock(&Giant);
135 rc = VBoxDrvFreeBSDUnload();
136 mtx_lock(&Giant);
137 break;
138
139 case MOD_SHUTDOWN:
140 case MOD_QUIESCE:
141 default:
142 return EOPNOTSUPP;
143 }
144
145 if (RT_SUCCESS(rc))
146 return 0;
147 return RTErrConvertToErrno(rc);
148}
149
150
151static int VBoxDrvFreeBSDLoad(void)
152{
153 g_cUsers = 0;
154
155 /*
156 * Initialize the runtime.
157 */
158 int rc = RTR0Init(0);
159 if (RT_SUCCESS(rc))
160 {
161 Log(("VBoxDrvFreeBSDLoad:\n"));
162
163 /*
164 * Initialize the device extension.
165 */
166 rc = supdrvInitDevExt(&g_VBoxDrvFreeBSDDevExt, sizeof(SUPDRVSESSION));
167 if (RT_SUCCESS(rc))
168 {
169 /*
170 * Configure character device. Add symbolic link for compatibility.
171 */
172 g_pVBoxDrvFreeBSDChrDev = make_dev(&g_VBoxDrvFreeBSDChrDevSW, 0, UID_ROOT, GID_WHEEL, VBOXDRV_PERM, "vboxdrv");
173 return VINF_SUCCESS;
174 }
175 else
176 printf("vboxdrv: supdrvInitDevExt failed, rc=%d\n", rc);
177 RTR0Term();
178 }
179 else
180 printf("vboxdrv: RTR0Init failed, rc=%d\n", rc);
181 return rc;
182}
183
184static int VBoxDrvFreeBSDUnload(void)
185{
186 Log(("VBoxDrvFreeBSDUnload:\n"));
187
188 if (g_cUsers > 0)
189 return VERR_RESOURCE_BUSY;
190
191 /*
192 * Reserve what we did in VBoxDrvFreeBSDInit.
193 */
194 destroy_dev(g_pVBoxDrvFreeBSDChrDev);
195
196 supdrvDeleteDevExt(&g_VBoxDrvFreeBSDDevExt);
197
198 RTR0TermForced();
199
200 memset(&g_VBoxDrvFreeBSDDevExt, 0, sizeof(g_VBoxDrvFreeBSDDevExt));
201 return VINF_SUCCESS;
202}
203
204
205/**
206 *
207 * @returns 0 on success, errno on failure.
208 * EBUSY if the device is used by someone else.
209 * @param pDev The device node.
210 * @param fOpen The open flags.
211 * @param pTd The thread.
212 * @param pFd The file descriptor. FreeBSD 7.0 and later.
213 * @param iFd The file descriptor index(?). Pre FreeBSD 7.0.
214 */
215static int VBoxDrvFreeBSDOpen(struct cdev *pDev, int fOpen, int iDevtype, struct thread *pTd)
216{
217 PSUPDRVSESSION pSession;
218 int rc;
219
220 /*
221 * Let's be a bit picky about the flags...
222 */
223 if (fOpen != (FREAD|FWRITE /*=O_RDWR*/))
224 {
225 Log(("VBoxDrvFreeBSDOpen: fOpen=%#x expected %#x\n", fOpen, O_RDWR));
226 return EINVAL;
227 }
228
229 /*
230 * Create a new session.
231 */
232 rc = supdrvCreateSession(&g_VBoxDrvFreeBSDDevExt, true /* fUser */, &pSession);
233 if (RT_SUCCESS(rc))
234 {
235 /** @todo get (r)uid and (r)gid.
236 pSession->Uid = stuff;
237 pSession->Gid = stuff; */
238 devfs_set_cdevpriv(pSession, VBoxDrvFreeBSDDtr);
239 Log(("VBoxDrvFreeBSDOpen: pSession=%p\n", pSession));
240 ASMAtomicIncU32(&g_cUsers);
241 return 0;
242 }
243
244 return RTErrConvertToErrno(rc);
245}
246
247
248/**
249 * Close a file device previously opened by VBoxDrvFreeBSDOpen
250 *
251 * @returns 0 on success.
252 * @param pDev The device.
253 * @param fFile The file descriptor flags.
254 * @param DevType The device type (CHR.
255 * @param pTd The calling thread.
256 */
257static void VBoxDrvFreeBSDDtr(void *pData)
258{
259 PSUPDRVSESSION pSession = pData;
260 Log(("VBoxDrvFreeBSDDtr: pSession=%p\n", pSession));
261
262 /*
263 * Close the session.
264 */
265 supdrvCloseSession(&g_VBoxDrvFreeBSDDevExt, pSession);
266 ASMAtomicDecU32(&g_cUsers);
267}
268
269
270/**
271 * I/O control request.
272 *
273 * @returns depends...
274 * @param pDev The device.
275 * @param ulCmd The command.
276 * @param pvData Pointer to the data.
277 * @param fFile The file descriptor flags.
278 * @param pTd The calling thread.
279 */
280static int VBoxDrvFreeBSDIOCtl(struct cdev *pDev, u_long ulCmd, caddr_t pvData, int fFile, struct thread *pTd)
281{
282 PSUPDRVSESSION pSession;
283 devfs_get_cdevpriv((void **)&pSession);
284
285 /*
286 * Deal with the fast ioctl path first.
287 */
288 if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
289 || ulCmd == SUP_IOCTL_FAST_DO_HM_RUN
290 || ulCmd == SUP_IOCTL_FAST_DO_NOP)
291 return supdrvIOCtlFast(ulCmd, *(uint32_t *)pvData, &g_VBoxDrvFreeBSDDevExt, pSession);
292
293 return VBoxDrvFreeBSDIOCtlSlow(pSession, ulCmd, pvData, pTd);
294}
295
296
297/**
298 * Deal with the 'slow' I/O control requests.
299 *
300 * @returns 0 on success, appropriate errno on failure.
301 * @param pSession The session.
302 * @param ulCmd The command.
303 * @param pvData The request data.
304 * @param pTd The calling thread.
305 */
306static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd)
307{
308 PSUPREQHDR pHdr;
309 uint32_t cbReq = IOCPARM_LEN(ulCmd);
310 void *pvUser = NULL;
311
312 /*
313 * Buffered request?
314 */
315 if ((IOC_DIRMASK & ulCmd) == IOC_INOUT)
316 {
317 pHdr = (PSUPREQHDR)pvData;
318 if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
319 {
320 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: cbReq=%#x < %#x; ulCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), ulCmd));
321 return EINVAL;
322 }
323 if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
324 {
325 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", pHdr->fFlags, ulCmd));
326 return EINVAL;
327 }
328 if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
329 || pHdr->cbIn < sizeof(*pHdr)
330 || pHdr->cbOut < sizeof(*pHdr)))
331 {
332 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x) != %#x; ulCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, ulCmd));
333 return EINVAL;
334 }
335 }
336 /*
337 * Big unbuffered request?
338 */
339 else if ((IOC_DIRMASK & ulCmd) == IOC_VOID && !cbReq)
340 {
341 /*
342 * Read the header, validate it and figure out how much that needs to be buffered.
343 */
344 SUPREQHDR Hdr;
345 pvUser = *(void **)pvData;
346 int rc = copyin(pvUser, &Hdr, sizeof(Hdr));
347 if (RT_UNLIKELY(rc))
348 {
349 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,Hdr,) -> %#x; ulCmd=%#lx\n", pvUser, rc, ulCmd));
350 return rc;
351 }
352 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
353 {
354 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", Hdr.fFlags, ulCmd));
355 return EINVAL;
356 }
357 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
358 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
359 || Hdr.cbOut < sizeof(Hdr)
360 || cbReq > _1M*16))
361 {
362 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x); ulCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, ulCmd));
363 return EINVAL;
364 }
365
366 /*
367 * Allocate buffer and copy in the data.
368 */
369 pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
370 if (RT_UNLIKELY(!pHdr))
371 {
372 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: failed to allocate buffer of %d bytes; ulCmd=%#lx\n", cbReq, ulCmd));
373 return ENOMEM;
374 }
375 rc = copyin(pvUser, pHdr, Hdr.cbIn);
376 if (RT_UNLIKELY(rc))
377 {
378 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,%p,%#x) -> %#x; ulCmd=%#lx\n",
379 pvUser, pHdr, Hdr.cbIn, rc, ulCmd));
380 RTMemTmpFree(pHdr);
381 return rc;
382 }
383 }
384 else
385 {
386 Log(("VBoxDrvFreeBSDIOCtlSlow: huh? cbReq=%#x ulCmd=%#lx\n", cbReq, ulCmd));
387 return EINVAL;
388 }
389
390 /*
391 * Process the IOCtl.
392 */
393 int rc = supdrvIOCtl(ulCmd, &g_VBoxDrvFreeBSDDevExt, pSession, pHdr);
394 if (RT_LIKELY(!rc))
395 {
396 /*
397 * If unbuffered, copy back the result before returning.
398 */
399 if (pvUser)
400 {
401 uint32_t cbOut = pHdr->cbOut;
402 if (cbOut > cbReq)
403 {
404 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, ulCmd));
405 cbOut = cbReq;
406 }
407 rc = copyout(pHdr, pvUser, cbOut);
408 if (RT_UNLIKELY(rc))
409 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyout(%p,%p,%#x) -> %d; uCmd=%#lx!\n", pHdr, pvUser, cbOut, rc, ulCmd));
410
411 Log(("VBoxDrvFreeBSDIOCtlSlow: returns %d / %d ulCmd=%lx\n", 0, pHdr->rc, ulCmd));
412
413 /* cleanup */
414 RTMemTmpFree(pHdr);
415 }
416 }
417 else
418 {
419 /*
420 * The request failed, just clean up.
421 */
422 if (pvUser)
423 RTMemTmpFree(pHdr);
424
425 Log(("VBoxDrvFreeBSDIOCtlSlow: ulCmd=%lx pData=%p failed, rc=%d\n", ulCmd, pvData, rc));
426 rc = EINVAL;
427 }
428
429 return rc;
430}
431
432
433/**
434 * The SUPDRV IDC entry point.
435 *
436 * @returns VBox status code, see supdrvIDC.
437 * @param iReq The request code.
438 * @param pReq The request.
439 */
440int VBOXCALL SUPDrvFreeBSDIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
441{
442 PSUPDRVSESSION pSession;
443
444 /*
445 * Some quick validations.
446 */
447 if (RT_UNLIKELY(!VALID_PTR(pReq)))
448 return VERR_INVALID_POINTER;
449
450 pSession = pReq->pSession;
451 if (pSession)
452 {
453 if (RT_UNLIKELY(!VALID_PTR(pReq->pSession)))
454 return VERR_INVALID_PARAMETER;
455 if (RT_UNLIKELY(pSession->pDevExt != &g_VBoxDrvFreeBSDDevExt))
456 return VERR_INVALID_PARAMETER;
457 }
458 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
459 return VERR_INVALID_PARAMETER;
460
461 /*
462 * Do the job.
463 */
464 return supdrvIDC(uReq, &g_VBoxDrvFreeBSDDevExt, pSession, pReq);
465}
466
467
468void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
469{
470 NOREF(pObj);
471 NOREF(pSession);
472}
473
474
475bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
476{
477 NOREF(pObj);
478 NOREF(pSession);
479 NOREF(pszObjName);
480 NOREF(prc);
481 return false;
482}
483
484
485bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
486{
487 return false;
488}
489
490
491int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
492{
493 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
494 return VERR_NOT_SUPPORTED;
495}
496
497
498void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
499{
500 NOREF(pDevExt); NOREF(pImage);
501}
502
503
504int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
505{
506 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
507 return VERR_NOT_SUPPORTED;
508}
509
510
511int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
512{
513 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
514 return VERR_NOT_SUPPORTED;
515}
516
517
518void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
519{
520 NOREF(pDevExt); NOREF(pImage);
521}
522
523
524SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
525{
526 va_list va;
527 char szMsg[256];
528 int cch;
529
530 va_start(va, pszFormat);
531 cch = RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, va);
532 va_end(va);
533
534 printf("%s", szMsg);
535
536 return cch;
537}
538
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