VirtualBox

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

Last change on this file since 42842 was 41067, checked in by vboxsync, 13 years ago

supdrvOSLdrNotifyOpened so we can record the load address in NVRAM if we choose to.

  • 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 41067 2012-04-26 11:36:57Z 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 RTR0Term();
199
200 memset(&g_VBoxDrvFreeBSDDevExt, 0, sizeof(g_VBoxDrvFreeBSDDevExt));
201
202 Log(("VBoxDrvFreeBSDUnload: returns\n"));
203 return VINF_SUCCESS;
204}
205
206
207/**
208 *
209 * @returns 0 on success, errno on failure.
210 * EBUSY if the device is used by someone else.
211 * @param pDev The device node.
212 * @param fOpen The open flags.
213 * @param pTd The thread.
214 * @param pFd The file descriptor. FreeBSD 7.0 and later.
215 * @param iFd The file descriptor index(?). Pre FreeBSD 7.0.
216 */
217static int VBoxDrvFreeBSDOpen(struct cdev *pDev, int fOpen, int iDevtype, struct thread *pTd)
218{
219 PSUPDRVSESSION pSession;
220 int rc;
221
222 /*
223 * Let's be a bit picky about the flags...
224 */
225 if (fOpen != (FREAD|FWRITE /*=O_RDWR*/))
226 {
227 Log(("VBoxDrvFreeBSDOpen: fOpen=%#x expected %#x\n", fOpen, O_RDWR));
228 return EINVAL;
229 }
230
231 /*
232 * Create a new session.
233 */
234 rc = supdrvCreateSession(&g_VBoxDrvFreeBSDDevExt, true /* fUser */, &pSession);
235 if (RT_SUCCESS(rc))
236 {
237 /** @todo get (r)uid and (r)gid.
238 pSession->Uid = stuff;
239 pSession->Gid = stuff; */
240 devfs_set_cdevpriv(pSession, VBoxDrvFreeBSDDtr);
241 Log(("VBoxDrvFreeBSDOpen: pSession=%p\n", pSession));
242 ASMAtomicIncU32(&g_cUsers);
243 return 0;
244 }
245
246 return RTErrConvertToErrno(rc);
247}
248
249
250/**
251 * Close a file device previously opened by VBoxDrvFreeBSDOpen
252 *
253 * @returns 0 on success.
254 * @param pDev The device.
255 * @param fFile The file descriptor flags.
256 * @param DevType The device type (CHR.
257 * @param pTd The calling thread.
258 */
259static void VBoxDrvFreeBSDDtr(void *pData)
260{
261 PSUPDRVSESSION pSession = pData;
262 Log(("VBoxDrvFreeBSDDtr: pSession=%p\n", pSession));
263
264 /*
265 * Close the session.
266 */
267 supdrvCloseSession(&g_VBoxDrvFreeBSDDevExt, pSession);
268 ASMAtomicDecU32(&g_cUsers);
269}
270
271
272/**
273 * I/O control request.
274 *
275 * @returns depends...
276 * @param pDev The device.
277 * @param ulCmd The command.
278 * @param pvData Pointer to the data.
279 * @param fFile The file descriptor flags.
280 * @param pTd The calling thread.
281 */
282static int VBoxDrvFreeBSDIOCtl(struct cdev *pDev, u_long ulCmd, caddr_t pvData, int fFile, struct thread *pTd)
283{
284 PSUPDRVSESSION pSession;
285 devfs_get_cdevpriv((void **)&pSession);
286
287 /*
288 * Deal with the fast ioctl path first.
289 */
290 if ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
291 || ulCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
292 || ulCmd == SUP_IOCTL_FAST_DO_NOP)
293 return supdrvIOCtlFast(ulCmd, *(uint32_t *)pvData, &g_VBoxDrvFreeBSDDevExt, pSession);
294
295 return VBoxDrvFreeBSDIOCtlSlow(pSession, ulCmd, pvData, pTd);
296}
297
298
299/**
300 * Deal with the 'slow' I/O control requests.
301 *
302 * @returns 0 on success, appropriate errno on failure.
303 * @param pSession The session.
304 * @param ulCmd The command.
305 * @param pvData The request data.
306 * @param pTd The calling thread.
307 */
308static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd)
309{
310 PSUPREQHDR pHdr;
311 uint32_t cbReq = IOCPARM_LEN(ulCmd);
312 void *pvUser = NULL;
313
314 /*
315 * Buffered request?
316 */
317 if ((IOC_DIRMASK & ulCmd) == IOC_INOUT)
318 {
319 pHdr = (PSUPREQHDR)pvData;
320 if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
321 {
322 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: cbReq=%#x < %#x; ulCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), ulCmd));
323 return EINVAL;
324 }
325 if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
326 {
327 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", pHdr->fFlags, ulCmd));
328 return EINVAL;
329 }
330 if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
331 || pHdr->cbIn < sizeof(*pHdr)
332 || pHdr->cbOut < sizeof(*pHdr)))
333 {
334 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x) != %#x; ulCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, ulCmd));
335 return EINVAL;
336 }
337 }
338 /*
339 * Big unbuffered request?
340 */
341 else if ((IOC_DIRMASK & ulCmd) == IOC_VOID && !cbReq)
342 {
343 /*
344 * Read the header, validate it and figure out how much that needs to be buffered.
345 */
346 SUPREQHDR Hdr;
347 pvUser = *(void **)pvData;
348 int rc = copyin(pvUser, &Hdr, sizeof(Hdr));
349 if (RT_UNLIKELY(rc))
350 {
351 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,Hdr,) -> %#x; ulCmd=%#lx\n", pvUser, rc, ulCmd));
352 return rc;
353 }
354 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
355 {
356 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", Hdr.fFlags, ulCmd));
357 return EINVAL;
358 }
359 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
360 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
361 || Hdr.cbOut < sizeof(Hdr)
362 || cbReq > _1M*16))
363 {
364 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x); ulCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, ulCmd));
365 return EINVAL;
366 }
367
368 /*
369 * Allocate buffer and copy in the data.
370 */
371 pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
372 if (RT_UNLIKELY(!pHdr))
373 {
374 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: failed to allocate buffer of %d bytes; ulCmd=%#lx\n", cbReq, ulCmd));
375 return ENOMEM;
376 }
377 rc = copyin(pvUser, pHdr, Hdr.cbIn);
378 if (RT_UNLIKELY(rc))
379 {
380 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,%p,%#x) -> %#x; ulCmd=%#lx\n",
381 pvUser, pHdr, Hdr.cbIn, rc, ulCmd));
382 RTMemTmpFree(pHdr);
383 return rc;
384 }
385 }
386 else
387 {
388 Log(("VBoxDrvFreeBSDIOCtlSlow: huh? cbReq=%#x ulCmd=%#lx\n", cbReq, ulCmd));
389 return EINVAL;
390 }
391
392 /*
393 * Process the IOCtl.
394 */
395 int rc = supdrvIOCtl(ulCmd, &g_VBoxDrvFreeBSDDevExt, pSession, pHdr);
396 if (RT_LIKELY(!rc))
397 {
398 /*
399 * If unbuffered, copy back the result before returning.
400 */
401 if (pvUser)
402 {
403 uint32_t cbOut = pHdr->cbOut;
404 if (cbOut > cbReq)
405 {
406 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, ulCmd));
407 cbOut = cbReq;
408 }
409 rc = copyout(pHdr, pvUser, cbOut);
410 if (RT_UNLIKELY(rc))
411 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyout(%p,%p,%#x) -> %d; uCmd=%#lx!\n", pHdr, pvUser, cbOut, rc, ulCmd));
412
413 Log(("VBoxDrvFreeBSDIOCtlSlow: returns %d / %d ulCmd=%lx\n", 0, pHdr->rc, ulCmd));
414
415 /* cleanup */
416 RTMemTmpFree(pHdr);
417 }
418 }
419 else
420 {
421 /*
422 * The request failed, just clean up.
423 */
424 if (pvUser)
425 RTMemTmpFree(pHdr);
426
427 Log(("VBoxDrvFreeBSDIOCtlSlow: ulCmd=%lx pData=%p failed, rc=%d\n", ulCmd, pvData, rc));
428 rc = EINVAL;
429 }
430
431 return rc;
432}
433
434
435/**
436 * The SUPDRV IDC entry point.
437 *
438 * @returns VBox status code, see supdrvIDC.
439 * @param iReq The request code.
440 * @param pReq The request.
441 */
442int VBOXCALL SUPDrvFreeBSDIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
443{
444 PSUPDRVSESSION pSession;
445
446 /*
447 * Some quick validations.
448 */
449 if (RT_UNLIKELY(!VALID_PTR(pReq)))
450 return VERR_INVALID_POINTER;
451
452 pSession = pReq->pSession;
453 if (pSession)
454 {
455 if (RT_UNLIKELY(!VALID_PTR(pReq->pSession)))
456 return VERR_INVALID_PARAMETER;
457 if (RT_UNLIKELY(pSession->pDevExt != &g_VBoxDrvFreeBSDDevExt))
458 return VERR_INVALID_PARAMETER;
459 }
460 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
461 return VERR_INVALID_PARAMETER;
462
463 /*
464 * Do the job.
465 */
466 return supdrvIDC(uReq, &g_VBoxDrvFreeBSDDevExt, pSession, pReq);
467}
468
469
470void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
471{
472 NOREF(pObj);
473 NOREF(pSession);
474}
475
476
477bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
478{
479 NOREF(pObj);
480 NOREF(pSession);
481 NOREF(pszObjName);
482 NOREF(prc);
483 return false;
484}
485
486
487bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
488{
489 return false;
490}
491
492
493int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
494{
495 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
496 return VERR_NOT_SUPPORTED;
497}
498
499
500void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
501{
502 NOREF(pDevExt); NOREF(pImage);
503}
504
505
506int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
507{
508 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
509 return VERR_NOT_SUPPORTED;
510}
511
512
513int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
514{
515 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
516 return VERR_NOT_SUPPORTED;
517}
518
519
520void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
521{
522 NOREF(pDevExt); NOREF(pImage);
523}
524
525
526SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
527{
528 va_list va;
529 char szMsg[256];
530 int cch;
531
532 va_start(va, pszFormat);
533 cch = RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, va);
534 va_end(va);
535
536 printf("%s", szMsg);
537
538 return cch;
539}
540
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