VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/solaris/SUPDrv-solaris.c@ 16905

Last change on this file since 16905 was 16905, checked in by vboxsync, 16 years ago

Solaris/VBoxUSB: removed gxx_personality hack.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.5 KB
Line 
1/* $Id: SUPDrv-solaris.c 16905 2009-02-18 14:45:18Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Solaris specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#define LOG_GROUP LOG_GROUP_SUP_DRV
35#include <sys/types.h>
36#include <sys/param.h>
37#include <sys/errno.h>
38#include <sys/uio.h>
39#include <sys/buf.h>
40#include <sys/modctl.h>
41#include <sys/open.h>
42#include <sys/conf.h>
43#include <sys/cmn_err.h>
44#include <sys/stat.h>
45#include <sys/ddi.h>
46#include <sys/sunddi.h>
47#include <sys/file.h>
48#include <sys/priv_names.h>
49#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
50
51#include "../SUPDrvInternal.h"
52#include <VBox/log.h>
53#include <VBox/version.h>
54#include <iprt/semaphore.h>
55#include <iprt/spinlock.h>
56#include <iprt/mp.h>
57#include <iprt/process.h>
58#include <iprt/thread.h>
59#include <iprt/initterm.h>
60#include <iprt/alloc.h>
61#include <iprt/string.h>
62#include <iprt/err.h>
63
64
65/*******************************************************************************
66* Defined Constants And Macros *
67*******************************************************************************/
68/** @todo this quoting macros probably should be moved to a common place.
69 * The indirection is for expanding macros passed to the first macro. */
70#define VBOXSOLQUOTE2(x) #x
71#define VBOXSOLQUOTE(x) VBOXSOLQUOTE2(x)
72/** The module name. */
73#define DEVICE_NAME "vboxdrv"
74/** The module description as seen in 'modinfo'. */
75#define DEVICE_DESC "VirtualBox HostDrv"
76/** Maximum number of driver instances. */
77#define DEVICE_MAXINSTANCES 16
78
79
80/*******************************************************************************
81* Internal Functions *
82*******************************************************************************/
83static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
84static int VBoxDrvSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
85static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
86static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
87static int VBoxDrvSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int mode, cred_t *pCred, int *pVal);
88
89static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t Cmd);
90static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t Cmd);
91
92static int VBoxSupDrvErr2SolarisErr(int rc);
93static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int Cmd, int Mode, intptr_t pArgs);
94
95
96/*******************************************************************************
97* Global Variables *
98*******************************************************************************/
99/**
100 * cb_ops: for drivers that support char/block entry points
101 */
102static struct cb_ops g_VBoxDrvSolarisCbOps =
103{
104 VBoxDrvSolarisOpen,
105 VBoxDrvSolarisClose,
106 nodev, /* b strategy */
107 nodev, /* b dump */
108 nodev, /* b print */
109 VBoxDrvSolarisRead,
110 VBoxDrvSolarisWrite,
111 VBoxDrvSolarisIOCtl,
112 nodev, /* c devmap */
113 nodev, /* c mmap */
114 nodev, /* c segmap */
115 nochpoll, /* c poll */
116 ddi_prop_op, /* property ops */
117 NULL, /* streamtab */
118 D_NEW | D_MP, /* compat. flag */
119 CB_REV /* revision */
120};
121
122/**
123 * dev_ops: for driver device operations
124 */
125static struct dev_ops g_VBoxDrvSolarisDevOps =
126{
127 DEVO_REV, /* driver build revision */
128 0, /* ref count */
129 nulldev, /* get info */
130 nulldev, /* identify */
131 nulldev, /* probe */
132 VBoxDrvSolarisAttach,
133 VBoxDrvSolarisDetach,
134 nodev, /* reset */
135 &g_VBoxDrvSolarisCbOps,
136 (struct bus_ops *)0,
137 nodev /* power */
138};
139
140/**
141 * modldrv: export driver specifics to the kernel
142 */
143static struct modldrv g_VBoxDrvSolarisModule =
144{
145 &mod_driverops, /* extern from kernel */
146 DEVICE_DESC " " VBOX_VERSION_STRING "r" VBOXSOLQUOTE(VBOX_SVN_REV),
147 &g_VBoxDrvSolarisDevOps
148};
149
150/**
151 * modlinkage: export install/remove/info to the kernel
152 */
153static struct modlinkage g_VBoxDrvSolarisModLinkage =
154{
155 MODREV_1, /* loadable module system revision */
156 &g_VBoxDrvSolarisModule,
157 NULL /* terminate array of linkage structures */
158};
159
160#ifndef USE_SESSION_HASH
161/**
162 * State info for each open file handle.
163 */
164typedef struct
165{
166 /**< Pointer to the session data. */
167 PSUPDRVSESSION pSession;
168} vbox_devstate_t;
169#else
170/** State info. for each driver instance. */
171typedef struct
172{
173 dev_info_t *pDip; /* Device handle */
174} vbox_devstate_t;
175#endif
176
177/** Opaque pointer to list of state */
178static void *g_pVBoxDrvSolarisState;
179
180/** Device extention & session data association structure */
181static SUPDRVDEVEXT g_DevExt;
182
183/** Hash table */
184static PSUPDRVSESSION g_apSessionHashTab[19];
185/** Spinlock protecting g_apSessionHashTab. */
186static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
187/** Calculates bucket index into g_apSessionHashTab.*/
188#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
189
190/**
191 * Kernel entry points
192 */
193int _init(void)
194{
195 LogFlow((DEVICE_NAME ":_init\n"));
196
197 /*
198 * Prevent module autounloading.
199 */
200 modctl_t *pModCtl = mod_getctl(&g_VBoxDrvSolarisModLinkage);
201 if (pModCtl)
202 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
203 else
204 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
205
206 /*
207 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
208 */
209 int rc = RTR0Init(0);
210 if (RT_SUCCESS(rc))
211 {
212 /*
213 * Initialize the device extension
214 */
215 rc = supdrvInitDevExt(&g_DevExt);
216 if (RT_SUCCESS(rc))
217 {
218 /*
219 * Initialize the session hash table.
220 */
221 memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab));
222 rc = RTSpinlockCreate(&g_Spinlock);
223 if (RT_SUCCESS(rc))
224 {
225 int rc = ddi_soft_state_init(&g_pVBoxDrvSolarisState, sizeof(vbox_devstate_t), 8);
226 if (!rc)
227 {
228 rc = mod_install(&g_VBoxDrvSolarisModLinkage);
229 if (!rc)
230 return rc; /* success */
231
232 ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
233 LogRel((DEVICE_NAME ":mod_install failed! rc=%d\n", rc));
234 }
235 else
236 LogRel((DEVICE_NAME ":failed to initialize soft state.\n"));
237
238 RTSpinlockDestroy(g_Spinlock);
239 g_Spinlock = NIL_RTSPINLOCK;
240 }
241 else
242 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: RTSpinlockCreate failed\n"));
243 supdrvDeleteDevExt(&g_DevExt);
244 }
245 else
246 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: supdrvInitDevExt failed\n"));
247 RTR0Term();
248 }
249 else
250 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: failed to init R0Drv\n"));
251 memset(&g_DevExt, 0, sizeof(g_DevExt));
252
253 return RTErrConvertToErrno(rc);
254}
255
256
257int _fini(void)
258{
259 LogFlow((DEVICE_NAME ":_fini\n"));
260
261 /*
262 * Undo the work we did at start (in the reverse order).
263 */
264 int rc = mod_remove(&g_VBoxDrvSolarisModLinkage);
265 if (rc != 0)
266 return rc;
267
268 supdrvDeleteDevExt(&g_DevExt);
269
270 rc = RTSpinlockDestroy(g_Spinlock);
271 AssertRC(rc);
272 g_Spinlock = NIL_RTSPINLOCK;
273
274 RTR0Term();
275
276 memset(&g_DevExt, 0, sizeof(g_DevExt));
277
278 ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
279 return 0;
280}
281
282
283int _info(struct modinfo *pModInfo)
284{
285 LogFlow((DEVICE_NAME ":_info\n"));
286 int e = mod_info(&g_VBoxDrvSolarisModLinkage, pModInfo);
287 return e;
288}
289
290
291/**
292 * Attach entry point, to attach a device to the system or resume it.
293 *
294 * @param pDip The module structure instance.
295 * @param enmCmd Operation type (attach/resume).
296 *
297 * @return corresponding solaris error code.
298 */
299static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
300{
301 LogFlow((DEVICE_NAME ":VBoxDrvSolarisAttach\n"));
302
303 switch (enmCmd)
304 {
305 case DDI_ATTACH:
306 {
307 int rc;
308 int instance = ddi_get_instance(pDip);
309#ifdef USE_SESSION_HASH
310 vbox_devstate_t *pState;
311
312 if (ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, instance) != DDI_SUCCESS)
313 {
314 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: state alloc failed\n"));
315 return DDI_FAILURE;
316 }
317
318 pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
319#endif
320
321 /*
322 * Register ourselves as a character device, pseudo-driver
323 */
324#ifdef VBOX_WITH_HARDENING
325 rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO,
326 0, NULL, NULL, 0600);
327#else
328 rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO,
329 0, "none", "none", 0666);
330#endif
331 if (rc == DDI_SUCCESS)
332 {
333#ifdef USE_SESSION_HASH
334 pState->pDip = pDip;
335#endif
336 ddi_report_dev(pDip);
337 return DDI_SUCCESS;
338 }
339
340 return DDI_FAILURE;
341 }
342
343 case DDI_RESUME:
344 {
345 RTSemFastMutexRequest(g_DevExt.mtxGip);
346 if (g_DevExt.pGipTimer)
347 RTTimerStart(g_DevExt.pGipTimer, 0);
348
349 RTSemFastMutexRelease(g_DevExt.mtxGip);
350 return DDI_SUCCESS;
351 }
352
353 default:
354 return DDI_FAILURE;
355 }
356
357 return DDI_FAILURE;
358}
359
360
361/**
362 * Detach entry point, to detach a device to the system or suspend it.
363 *
364 * @param pDip The module structure instance.
365 * @param enmCmd Operation type (detach/suspend).
366 *
367 * @return corresponding solaris error code.
368 */
369static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
370{
371 int rc = VINF_SUCCESS;
372
373 LogFlow((DEVICE_NAME ":VBoxDrvSolarisDetach\n"));
374 switch (enmCmd)
375 {
376 case DDI_DETACH:
377 {
378 int instance = ddi_get_instance(pDip);
379#ifndef USE_SESSION_HASH
380 ddi_remove_minor_node(pDip, NULL);
381#else
382 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
383 ddi_remove_minor_node(pDip, NULL);
384 ddi_soft_state_free(g_pVBoxDrvSolarisState, instance);
385#endif
386 return DDI_SUCCESS;
387 }
388
389 case DDI_SUSPEND:
390 {
391 RTSemFastMutexRequest(g_DevExt.mtxGip);
392 if (g_DevExt.pGipTimer && g_DevExt.cGipUsers > 0)
393 RTTimerStop(g_DevExt.pGipTimer);
394
395 RTSemFastMutexRelease(g_DevExt.mtxGip);
396 return DDI_SUCCESS;
397 }
398
399 default:
400 return DDI_FAILURE;
401 }
402}
403
404
405
406/**
407 * User context entry points
408 */
409static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
410{
411 int rc;
412 PSUPDRVSESSION pSession;
413 LogFlow((DEVICE_NAME ":VBoxDrvSolarisOpen: pDev=%p:%#x\n", pDev, *pDev));
414
415#ifndef USE_SESSION_HASH
416 /*
417 * Locate a new device open instance.
418 *
419 * For each open call we'll allocate an item in the soft state of the device.
420 * The item index is stored in the dev_t. I hope this is ok...
421 */
422 vbox_devstate_t *pState = NULL;
423 unsigned iOpenInstance;
424 for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
425 {
426 if ( !ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance) /* faster */
427 && ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, iOpenInstance) == DDI_SUCCESS)
428 {
429 pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance);
430 break;
431 }
432 }
433 if (!pState)
434 {
435 LogRel((DEVICE_NAME ":VBoxDrvSolarisOpen: too many open instances.\n"));
436 return ENXIO;
437 }
438
439 /*
440 * Create a new session.
441 */
442 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
443 if (RT_SUCCESS(rc))
444 {
445 pSession->Uid = crgetruid(pCred);
446 pSession->Gid = crgetrgid(pCred);
447
448 pState->pSession = pSession;
449 *pDev = makedevice(getmajor(*pDev), iOpenInstance);
450 LogFlow((DEVICE_NAME ":VBoxDrvSolarisOpen: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
451 *pDev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
452 return 0;
453 }
454
455 /* failed - clean up */
456 ddi_soft_state_free(g_pVBoxDrvSolarisState, iOpenInstance);
457
458#else
459 /*
460 * Create a new session.
461 * Sessions in Solaris driver are mostly useless. It's however needed
462 * in VBoxDrvSolarisIOCtlSlow() while calling supdrvIOCtl()
463 */
464 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
465 if (RT_SUCCESS(rc))
466 {
467 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
468 unsigned iHash;
469
470 pSession->Uid = crgetruid(pCred);
471 pSession->Gid = crgetrgid(pCred);
472
473 /*
474 * Insert it into the hash table.
475 */
476 iHash = SESSION_HASH(pSession->Process);
477 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
478 pSession->pNextHash = g_apSessionHashTab[iHash];
479 g_apSessionHashTab[iHash] = pSession;
480 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
481 LogFlow((DEVICE_NAME ":VBoxDrvSolarisOpen success\n"));
482 }
483
484 int instance;
485 for (instance = 0; instance < DEVICE_MAXINSTANCES; instance++)
486 {
487 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
488 if (pState)
489 break;
490 }
491
492 if (instance >= DEVICE_MAXINSTANCES)
493 {
494 LogRel((DEVICE_NAME ":VBoxDrvSolarisOpen: All instances exhausted\n"));
495 return ENXIO;
496 }
497
498 *pDev = makedevice(getmajor(*pDev), instance);
499
500 return VBoxSupDrvErr2SolarisErr(rc);
501#endif
502}
503
504
505static int VBoxDrvSolarisClose(dev_t Dev, int flag, int otyp, cred_t *cred)
506{
507 LogFlow((DEVICE_NAME ":VBoxDrvSolarisClose: Dev=%#x\n", Dev));
508
509#ifndef USE_SESSION_HASH
510 /*
511 * Get the session and free the soft state item.
512 */
513 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
514 if (!pState)
515 {
516 LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: no state data for %#x (%d)\n", Dev, getminor(Dev)));
517 return EFAULT;
518 }
519
520 PSUPDRVSESSION pSession = pState->pSession;
521 pState->pSession = NULL;
522 ddi_soft_state_free(g_pVBoxDrvSolarisState, getminor(Dev));
523
524 if (!pSession)
525 {
526 LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
527 return EFAULT;
528 }
529 LogFlow((DEVICE_NAME ":VBoxDrvSolarisClose: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
530 Dev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
531
532#else
533 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
534 const RTPROCESS Process = RTProcSelf();
535 const unsigned iHash = SESSION_HASH(Process);
536 PSUPDRVSESSION pSession;
537
538 /*
539 * Remove from the hash table.
540 */
541 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
542 pSession = g_apSessionHashTab[iHash];
543 if (pSession)
544 {
545 if (pSession->Process == Process)
546 {
547 g_apSessionHashTab[iHash] = pSession->pNextHash;
548 pSession->pNextHash = NULL;
549 }
550 else
551 {
552 PSUPDRVSESSION pPrev = pSession;
553 pSession = pSession->pNextHash;
554 while (pSession)
555 {
556 if (pSession->Process == Process)
557 {
558 pPrev->pNextHash = pSession->pNextHash;
559 pSession->pNextHash = NULL;
560 break;
561 }
562
563 /* next */
564 pPrev = pSession;
565 pSession = pSession->pNextHash;
566 }
567 }
568 }
569 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
570 if (!pSession)
571 {
572 LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n",
573 (int)Process));
574 return EFAULT;
575 }
576#endif
577
578 /*
579 * Close the session.
580 */
581 supdrvCloseSession(&g_DevExt, pSession);
582 return 0;
583}
584
585
586static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
587{
588 LogFlow((DEVICE_NAME ":VBoxDrvSolarisRead"));
589 return 0;
590}
591
592
593static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
594{
595 LogFlow((DEVICE_NAME ":VBoxDrvSolarisWrite"));
596 return 0;
597}
598
599
600/**
601 * Driver ioctl, an alternate entry point for this character driver.
602 *
603 * @param Dev Device number
604 * @param Cmd Operation identifier
605 * @param pArg Arguments from user to driver
606 * @param Mode Information bitfield (read/write, address space etc.)
607 * @param pCred User credentials
608 * @param pVal Return value for calling process.
609 *
610 * @return corresponding solaris error code.
611 */
612static int VBoxDrvSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int Mode, cred_t *pCred, int *pVal)
613{
614#ifndef USE_SESSION_HASH
615 /*
616 * Get the session from the soft state item.
617 */
618 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
619 if (!pState)
620 {
621 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtl: no state data for %#x (%d)\n", Dev, getminor(Dev)));
622 return EINVAL;
623 }
624
625 PSUPDRVSESSION pSession = pState->pSession;
626 if (!pSession)
627 {
628 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtl: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
629 return DDI_SUCCESS;
630 }
631#else
632 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
633 const RTPROCESS Process = RTProcSelf();
634 const unsigned iHash = SESSION_HASH(Process);
635 PSUPDRVSESSION pSession;
636
637 /*
638 * Find the session.
639 */
640 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
641 pSession = g_apSessionHashTab[iHash];
642 if (pSession && pSession->Process != Process)
643 {
644 do pSession = pSession->pNextHash;
645 while (pSession && pSession->Process != Process);
646 }
647 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
648 if (!pSession)
649 {
650 LogRel((DEVICE_NAME ":VBoxSupDrvIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
651 (int)Process, Cmd));
652 return EINVAL;
653 }
654#endif
655
656 /*
657 * Deal with the two high-speed IOCtl that takes it's arguments from
658 * the session and iCmd, and only returns a VBox status code.
659 */
660 if ( Cmd == SUP_IOCTL_FAST_DO_RAW_RUN
661 || Cmd == SUP_IOCTL_FAST_DO_HWACC_RUN
662 || Cmd == SUP_IOCTL_FAST_DO_NOP)
663 {
664 *pVal = supdrvIOCtlFast(Cmd, pArgs, &g_DevExt, pSession);
665 return 0;
666 }
667
668 return VBoxDrvSolarisIOCtlSlow(pSession, Cmd, Mode, pArgs);
669}
670
671
672/** @def IOCPARM_LEN
673 * Gets the length from the ioctl number.
674 * This is normally defined by sys/ioccom.h on BSD systems...
675 */
676#ifndef IOCPARM_LEN
677# define IOCPARM_LEN(x) ( ((x) >> 16) & IOCPARM_MASK )
678#endif
679
680
681/**
682 * Worker for VBoxSupDrvIOCtl that takes the slow IOCtl functions.
683 *
684 * @returns Solaris errno.
685 *
686 * @param pSession The session.
687 * @param Cmd The IOCtl command.
688 * @param Mode Information bitfield (for specifying ownership of data)
689 * @param iArg User space address of the request buffer.
690 */
691static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int iCmd, int Mode, intptr_t iArg)
692{
693 int rc;
694 uint32_t cbBuf = 0;
695 union
696 {
697 SUPREQHDR Hdr;
698 uint8_t abBuf[64];
699 } StackBuf;
700 PSUPREQHDR pHdr;
701
702
703 /*
704 * Read the header.
705 */
706 if (RT_UNLIKELY(IOCPARM_LEN(iCmd) != sizeof(StackBuf.Hdr)))
707 {
708 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: iCmd=%#x len %d expected %d\n", iCmd, IOCPARM_LEN(iCmd), sizeof(StackBuf.Hdr)));
709 return EINVAL;
710 }
711 rc = ddi_copyin((void *)iArg, &StackBuf.Hdr, sizeof(StackBuf.Hdr), Mode);
712 if (RT_UNLIKELY(rc))
713 {
714 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: ddi_copyin(,%#lx,) failed; iCmd=%#x. rc=%d\n", iArg, iCmd, rc));
715 return EFAULT;
716 }
717 if (RT_UNLIKELY((StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
718 {
719 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: bad header magic %#x; iCmd=%#x\n", StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, iCmd));
720 return EINVAL;
721 }
722 cbBuf = RT_MAX(StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut);
723 if (RT_UNLIKELY( StackBuf.Hdr.cbIn < sizeof(StackBuf.Hdr)
724 || StackBuf.Hdr.cbOut < sizeof(StackBuf.Hdr)
725 || cbBuf > _1M*16))
726 {
727 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: max(%#x,%#x); iCmd=%#x\n", StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut, iCmd));
728 return EINVAL;
729 }
730
731 /*
732 * Buffer the request.
733 */
734 if (cbBuf <= sizeof(StackBuf))
735 pHdr = &StackBuf.Hdr;
736 else
737 {
738 pHdr = RTMemTmpAlloc(cbBuf);
739 if (RT_UNLIKELY(!pHdr))
740 {
741 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: failed to allocate buffer of %d bytes for iCmd=%#x.\n", cbBuf, iCmd));
742 return ENOMEM;
743 }
744 }
745 rc = ddi_copyin((void *)iArg, pHdr, cbBuf, Mode);
746 if (RT_UNLIKELY(rc))
747 {
748 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: copy_from_user(,%#lx, %#x) failed; iCmd=%#x. rc=%d\n", iArg, cbBuf, iCmd, rc));
749 if (pHdr != &StackBuf.Hdr)
750 RTMemFree(pHdr);
751 return EFAULT;
752 }
753
754 /*
755 * Process the IOCtl.
756 */
757 rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
758
759 /*
760 * Copy ioctl data and output buffer back to user space.
761 */
762 if (RT_LIKELY(!rc))
763 {
764 uint32_t cbOut = pHdr->cbOut;
765 if (RT_UNLIKELY(cbOut > cbBuf))
766 {
767 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: too much output! %#x > %#x; iCmd=%#x!\n", cbOut, cbBuf, iCmd));
768 cbOut = cbBuf;
769 }
770 rc = ddi_copyout(pHdr, (void *)iArg, cbOut, Mode);
771 if (RT_UNLIKELY(rc != 0))
772 {
773 /* this is really bad */
774 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: ddi_copyout(,%p,%d) failed. rc=%d\n", (void *)iArg, cbBuf, rc));
775 rc = EFAULT;
776 }
777 }
778 else
779 rc = EINVAL;
780
781 if (pHdr != &StackBuf.Hdr)
782 RTMemTmpFree(pHdr);
783 return rc;
784}
785
786
787/**
788 * The SUPDRV IDC entry point.
789 *
790 * @returns VBox status code, see supdrvIDC.
791 * @param iReq The request code.
792 * @param pReq The request.
793 */
794int VBOXCALL SUPDrvSolarisIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
795{
796 PSUPDRVSESSION pSession;
797
798 /*
799 * Some quick validations.
800 */
801 if (RT_UNLIKELY(!VALID_PTR(pReq)))
802 return VERR_INVALID_POINTER;
803
804 pSession = pReq->pSession;
805 if (pSession)
806 {
807 if (RT_UNLIKELY(!VALID_PTR(pSession)))
808 return VERR_INVALID_PARAMETER;
809 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
810 return VERR_INVALID_PARAMETER;
811 }
812 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
813 return VERR_INVALID_PARAMETER;
814
815 /*
816 * Do the job.
817 */
818 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
819}
820
821
822/**
823 * Converts an supdrv error code to a solaris error code.
824 *
825 * @returns corresponding solaris error code.
826 * @param rc supdrv error code (SUPDRV_ERR_* defines).
827 */
828static int VBoxSupDrvErr2SolarisErr(int rc)
829{
830 switch (rc)
831 {
832 case 0: return 0;
833 case SUPDRV_ERR_GENERAL_FAILURE: return EACCES;
834 case SUPDRV_ERR_INVALID_PARAM: return EINVAL;
835 case SUPDRV_ERR_INVALID_MAGIC: return EILSEQ;
836 case SUPDRV_ERR_INVALID_HANDLE: return ENXIO;
837 case SUPDRV_ERR_INVALID_POINTER: return EFAULT;
838 case SUPDRV_ERR_LOCK_FAILED: return ENOLCK;
839 case SUPDRV_ERR_ALREADY_LOADED: return EEXIST;
840 case SUPDRV_ERR_PERMISSION_DENIED: return EPERM;
841 case SUPDRV_ERR_VERSION_MISMATCH: return ENOSYS;
842 }
843
844 return EPERM;
845}
846
847
848/**
849 * Initializes any OS specific object creator fields.
850 */
851void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
852{
853 NOREF(pObj);
854 NOREF(pSession);
855}
856
857
858/**
859 * Checks if the session can access the object.
860 *
861 * @returns true if a decision has been made.
862 * @returns false if the default access policy should be applied.
863 *
864 * @param pObj The object in question.
865 * @param pSession The session wanting to access the object.
866 * @param pszObjName The object name, can be NULL.
867 * @param prc Where to store the result when returning true.
868 */
869bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
870{
871 NOREF(pObj);
872 NOREF(pSession);
873 NOREF(pszObjName);
874 NOREF(prc);
875 return false;
876}
877
878
879bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
880{
881 return false;
882}
883
884
885RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
886{
887 va_list args;
888 char szMsg[512];
889
890 va_start(args, pszFormat);
891 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, args);
892 va_end(args);
893
894 szMsg[sizeof(szMsg) - 1] = '\0';
895 cmn_err(CE_CONT, "%s", szMsg);
896 return 0;
897}
898
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