VirtualBox

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

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

Solaris/vboxdrv/vboxflt: Fixed incorrect return value on failure on _init.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 26.6 KB
Line 
1/* $Id: SUPDrv-solaris.c 16546 2009-02-06 13:07:22Z 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/* GCC C++ hack. */
184unsigned __gxx_personality_v0 = 0xcccccccc;
185
186/** Hash table */
187static PSUPDRVSESSION g_apSessionHashTab[19];
188/** Spinlock protecting g_apSessionHashTab. */
189static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
190/** Calculates bucket index into g_apSessionHashTab.*/
191#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
192
193/**
194 * Kernel entry points
195 */
196int _init(void)
197{
198 LogFlow((DEVICE_NAME ":_init\n"));
199
200 /*
201 * Prevent module autounloading.
202 */
203 modctl_t *pModCtl = mod_getctl(&g_VBoxDrvSolarisModLinkage);
204 if (pModCtl)
205 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
206 else
207 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
208
209 /*
210 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
211 */
212 int rc = RTR0Init(0);
213 if (RT_SUCCESS(rc))
214 {
215 /*
216 * Initialize the device extension
217 */
218 rc = supdrvInitDevExt(&g_DevExt);
219 if (RT_SUCCESS(rc))
220 {
221 /*
222 * Initialize the session hash table.
223 */
224 memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab));
225 rc = RTSpinlockCreate(&g_Spinlock);
226 if (RT_SUCCESS(rc))
227 {
228 int rc = ddi_soft_state_init(&g_pVBoxDrvSolarisState, sizeof(vbox_devstate_t), 8);
229 if (!rc)
230 {
231 rc = mod_install(&g_VBoxDrvSolarisModLinkage);
232 if (!rc)
233 return rc; /* success */
234
235 ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
236 LogRel((DEVICE_NAME ":mod_install failed! rc=%d\n", rc));
237 }
238 else
239 LogRel((DEVICE_NAME ":failed to initialize soft state.\n"));
240
241 RTSpinlockDestroy(g_Spinlock);
242 g_Spinlock = NIL_RTSPINLOCK;
243 }
244 else
245 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: RTSpinlockCreate failed\n"));
246 supdrvDeleteDevExt(&g_DevExt);
247 }
248 else
249 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: supdrvInitDevExt failed\n"));
250 RTR0Term();
251 }
252 else
253 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: failed to init R0Drv\n"));
254 memset(&g_DevExt, 0, sizeof(g_DevExt));
255
256 return RTErrConvertToErrno(rc);
257}
258
259
260int _fini(void)
261{
262 LogFlow((DEVICE_NAME ":_fini\n"));
263
264 /*
265 * Undo the work we did at start (in the reverse order).
266 */
267 int rc = mod_remove(&g_VBoxDrvSolarisModLinkage);
268 if (rc != 0)
269 return rc;
270
271 supdrvDeleteDevExt(&g_DevExt);
272
273 rc = RTSpinlockDestroy(g_Spinlock);
274 AssertRC(rc);
275 g_Spinlock = NIL_RTSPINLOCK;
276
277 RTR0Term();
278
279 memset(&g_DevExt, 0, sizeof(g_DevExt));
280
281 ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
282 return 0;
283}
284
285
286int _info(struct modinfo *pModInfo)
287{
288 LogFlow((DEVICE_NAME ":_info\n"));
289 int e = mod_info(&g_VBoxDrvSolarisModLinkage, pModInfo);
290 return e;
291}
292
293
294/**
295 * Attach entry point, to attach a device to the system or resume it.
296 *
297 * @param pDip The module structure instance.
298 * @param enmCmd Operation type (attach/resume).
299 *
300 * @return corresponding solaris error code.
301 */
302static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
303{
304 LogFlow((DEVICE_NAME ":VBoxDrvSolarisAttach\n"));
305
306 switch (enmCmd)
307 {
308 case DDI_ATTACH:
309 {
310 int rc;
311 int instance = ddi_get_instance(pDip);
312#ifdef USE_SESSION_HASH
313 vbox_devstate_t *pState;
314
315 if (ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, instance) != DDI_SUCCESS)
316 {
317 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: state alloc failed\n"));
318 return DDI_FAILURE;
319 }
320
321 pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
322#endif
323
324 /*
325 * Register ourselves as a character device, pseudo-driver
326 */
327#ifdef VBOX_WITH_HARDENING
328 rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO,
329 0, NULL, NULL, 0600);
330#else
331 rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO,
332 0, "none", "none", 0666);
333#endif
334 if (rc == DDI_SUCCESS)
335 {
336#ifdef USE_SESSION_HASH
337 pState->pDip = pDip;
338#endif
339 ddi_report_dev(pDip);
340 return DDI_SUCCESS;
341 }
342
343 return DDI_FAILURE;
344 }
345
346 case DDI_RESUME:
347 {
348 RTSemFastMutexRequest(g_DevExt.mtxGip);
349 if (g_DevExt.pGipTimer)
350 RTTimerStart(g_DevExt.pGipTimer, 0);
351
352 RTSemFastMutexRelease(g_DevExt.mtxGip);
353 return DDI_SUCCESS;
354 }
355
356 default:
357 return DDI_FAILURE;
358 }
359
360 return DDI_FAILURE;
361}
362
363
364/**
365 * Detach entry point, to detach a device to the system or suspend it.
366 *
367 * @param pDip The module structure instance.
368 * @param enmCmd Operation type (detach/suspend).
369 *
370 * @return corresponding solaris error code.
371 */
372static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
373{
374 int rc = VINF_SUCCESS;
375
376 LogFlow((DEVICE_NAME ":VBoxDrvSolarisDetach\n"));
377 switch (enmCmd)
378 {
379 case DDI_DETACH:
380 {
381 int instance = ddi_get_instance(pDip);
382#ifndef USE_SESSION_HASH
383 ddi_remove_minor_node(pDip, NULL);
384#else
385 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
386 ddi_remove_minor_node(pDip, NULL);
387 ddi_soft_state_free(g_pVBoxDrvSolarisState, instance);
388#endif
389 return DDI_SUCCESS;
390 }
391
392 case DDI_SUSPEND:
393 {
394 RTSemFastMutexRequest(g_DevExt.mtxGip);
395 if (g_DevExt.pGipTimer && g_DevExt.cGipUsers > 0)
396 RTTimerStop(g_DevExt.pGipTimer);
397
398 RTSemFastMutexRelease(g_DevExt.mtxGip);
399 return DDI_SUCCESS;
400 }
401
402 default:
403 return DDI_FAILURE;
404 }
405}
406
407
408
409/**
410 * User context entry points
411 */
412static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
413{
414 int rc;
415 PSUPDRVSESSION pSession;
416 LogFlow((DEVICE_NAME ":VBoxDrvSolarisOpen: pDev=%p:%#x\n", pDev, *pDev));
417
418#ifndef USE_SESSION_HASH
419 /*
420 * Locate a new device open instance.
421 *
422 * For each open call we'll allocate an item in the soft state of the device.
423 * The item index is stored in the dev_t. I hope this is ok...
424 */
425 vbox_devstate_t *pState = NULL;
426 unsigned iOpenInstance;
427 for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
428 {
429 if ( !ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance) /* faster */
430 && ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, iOpenInstance) == DDI_SUCCESS)
431 {
432 pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance);
433 break;
434 }
435 }
436 if (!pState)
437 {
438 LogRel((DEVICE_NAME ":VBoxDrvSolarisOpen: too many open instances.\n"));
439 return ENXIO;
440 }
441
442 /*
443 * Create a new session.
444 */
445 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
446 if (RT_SUCCESS(rc))
447 {
448 pSession->Uid = crgetruid(pCred);
449 pSession->Gid = crgetrgid(pCred);
450
451 pState->pSession = pSession;
452 *pDev = makedevice(getmajor(*pDev), iOpenInstance);
453 LogFlow((DEVICE_NAME ":VBoxDrvSolarisOpen: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
454 *pDev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
455 return 0;
456 }
457
458 /* failed - clean up */
459 ddi_soft_state_free(g_pVBoxDrvSolarisState, iOpenInstance);
460
461#else
462 /*
463 * Create a new session.
464 * Sessions in Solaris driver are mostly useless. It's however needed
465 * in VBoxDrvSolarisIOCtlSlow() while calling supdrvIOCtl()
466 */
467 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
468 if (RT_SUCCESS(rc))
469 {
470 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
471 unsigned iHash;
472
473 pSession->Uid = crgetruid(pCred);
474 pSession->Gid = crgetrgid(pCred);
475
476 /*
477 * Insert it into the hash table.
478 */
479 iHash = SESSION_HASH(pSession->Process);
480 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
481 pSession->pNextHash = g_apSessionHashTab[iHash];
482 g_apSessionHashTab[iHash] = pSession;
483 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
484 LogFlow((DEVICE_NAME ":VBoxDrvSolarisOpen success\n"));
485 }
486
487 int instance;
488 for (instance = 0; instance < DEVICE_MAXINSTANCES; instance++)
489 {
490 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
491 if (pState)
492 break;
493 }
494
495 if (instance >= DEVICE_MAXINSTANCES)
496 {
497 LogRel((DEVICE_NAME ":VBoxDrvSolarisOpen: All instances exhausted\n"));
498 return ENXIO;
499 }
500
501 *pDev = makedevice(getmajor(*pDev), instance);
502
503 return VBoxSupDrvErr2SolarisErr(rc);
504#endif
505}
506
507
508static int VBoxDrvSolarisClose(dev_t Dev, int flag, int otyp, cred_t *cred)
509{
510 LogFlow((DEVICE_NAME ":VBoxDrvSolarisClose: Dev=%#x\n", Dev));
511
512#ifndef USE_SESSION_HASH
513 /*
514 * Get the session and free the soft state item.
515 */
516 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
517 if (!pState)
518 {
519 LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: no state data for %#x (%d)\n", Dev, getminor(Dev)));
520 return EFAULT;
521 }
522
523 PSUPDRVSESSION pSession = pState->pSession;
524 pState->pSession = NULL;
525 ddi_soft_state_free(g_pVBoxDrvSolarisState, getminor(Dev));
526
527 if (!pSession)
528 {
529 LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
530 return EFAULT;
531 }
532 LogFlow((DEVICE_NAME ":VBoxDrvSolarisClose: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
533 Dev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
534
535#else
536 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
537 const RTPROCESS Process = RTProcSelf();
538 const unsigned iHash = SESSION_HASH(Process);
539 PSUPDRVSESSION pSession;
540
541 /*
542 * Remove from the hash table.
543 */
544 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
545 pSession = g_apSessionHashTab[iHash];
546 if (pSession)
547 {
548 if (pSession->Process == Process)
549 {
550 g_apSessionHashTab[iHash] = pSession->pNextHash;
551 pSession->pNextHash = NULL;
552 }
553 else
554 {
555 PSUPDRVSESSION pPrev = pSession;
556 pSession = pSession->pNextHash;
557 while (pSession)
558 {
559 if (pSession->Process == Process)
560 {
561 pPrev->pNextHash = pSession->pNextHash;
562 pSession->pNextHash = NULL;
563 break;
564 }
565
566 /* next */
567 pPrev = pSession;
568 pSession = pSession->pNextHash;
569 }
570 }
571 }
572 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
573 if (!pSession)
574 {
575 LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n",
576 (int)Process));
577 return EFAULT;
578 }
579#endif
580
581 /*
582 * Close the session.
583 */
584 supdrvCloseSession(&g_DevExt, pSession);
585 return 0;
586}
587
588
589static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
590{
591 LogFlow((DEVICE_NAME ":VBoxDrvSolarisRead"));
592 return 0;
593}
594
595
596static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
597{
598 LogFlow((DEVICE_NAME ":VBoxDrvSolarisWrite"));
599 return 0;
600}
601
602
603/**
604 * Driver ioctl, an alternate entry point for this character driver.
605 *
606 * @param Dev Device number
607 * @param Cmd Operation identifier
608 * @param pArg Arguments from user to driver
609 * @param Mode Information bitfield (read/write, address space etc.)
610 * @param pCred User credentials
611 * @param pVal Return value for calling process.
612 *
613 * @return corresponding solaris error code.
614 */
615static int VBoxDrvSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int Mode, cred_t *pCred, int *pVal)
616{
617#ifndef USE_SESSION_HASH
618 /*
619 * Get the session from the soft state item.
620 */
621 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
622 if (!pState)
623 {
624 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtl: no state data for %#x (%d)\n", Dev, getminor(Dev)));
625 return EINVAL;
626 }
627
628 PSUPDRVSESSION pSession = pState->pSession;
629 if (!pSession)
630 {
631 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtl: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
632 return DDI_SUCCESS;
633 }
634#else
635 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
636 const RTPROCESS Process = RTProcSelf();
637 const unsigned iHash = SESSION_HASH(Process);
638 PSUPDRVSESSION pSession;
639
640 /*
641 * Find the session.
642 */
643 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
644 pSession = g_apSessionHashTab[iHash];
645 if (pSession && pSession->Process != Process)
646 {
647 do pSession = pSession->pNextHash;
648 while (pSession && pSession->Process != Process);
649 }
650 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
651 if (!pSession)
652 {
653 LogRel((DEVICE_NAME ":VBoxSupDrvIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
654 (int)Process, Cmd));
655 return EINVAL;
656 }
657#endif
658
659 /*
660 * Deal with the two high-speed IOCtl that takes it's arguments from
661 * the session and iCmd, and only returns a VBox status code.
662 */
663 if ( Cmd == SUP_IOCTL_FAST_DO_RAW_RUN
664 || Cmd == SUP_IOCTL_FAST_DO_HWACC_RUN
665 || Cmd == SUP_IOCTL_FAST_DO_NOP)
666 {
667 *pVal = supdrvIOCtlFast(Cmd, pArgs, &g_DevExt, pSession);
668 return 0;
669 }
670
671 return VBoxDrvSolarisIOCtlSlow(pSession, Cmd, Mode, pArgs);
672}
673
674
675/** @def IOCPARM_LEN
676 * Gets the length from the ioctl number.
677 * This is normally defined by sys/ioccom.h on BSD systems...
678 */
679#ifndef IOCPARM_LEN
680# define IOCPARM_LEN(x) ( ((x) >> 16) & IOCPARM_MASK )
681#endif
682
683
684/**
685 * Worker for VBoxSupDrvIOCtl that takes the slow IOCtl functions.
686 *
687 * @returns Solaris errno.
688 *
689 * @param pSession The session.
690 * @param Cmd The IOCtl command.
691 * @param Mode Information bitfield (for specifying ownership of data)
692 * @param iArg User space address of the request buffer.
693 */
694static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int iCmd, int Mode, intptr_t iArg)
695{
696 int rc;
697 uint32_t cbBuf = 0;
698 union
699 {
700 SUPREQHDR Hdr;
701 uint8_t abBuf[64];
702 } StackBuf;
703 PSUPREQHDR pHdr;
704
705
706 /*
707 * Read the header.
708 */
709 if (RT_UNLIKELY(IOCPARM_LEN(iCmd) != sizeof(StackBuf.Hdr)))
710 {
711 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: iCmd=%#x len %d expected %d\n", iCmd, IOCPARM_LEN(iCmd), sizeof(StackBuf.Hdr)));
712 return EINVAL;
713 }
714 rc = ddi_copyin((void *)iArg, &StackBuf.Hdr, sizeof(StackBuf.Hdr), Mode);
715 if (RT_UNLIKELY(rc))
716 {
717 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: ddi_copyin(,%#lx,) failed; iCmd=%#x. rc=%d\n", iArg, iCmd, rc));
718 return EFAULT;
719 }
720 if (RT_UNLIKELY((StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
721 {
722 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: bad header magic %#x; iCmd=%#x\n", StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, iCmd));
723 return EINVAL;
724 }
725 cbBuf = RT_MAX(StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut);
726 if (RT_UNLIKELY( StackBuf.Hdr.cbIn < sizeof(StackBuf.Hdr)
727 || StackBuf.Hdr.cbOut < sizeof(StackBuf.Hdr)
728 || cbBuf > _1M*16))
729 {
730 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: max(%#x,%#x); iCmd=%#x\n", StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut, iCmd));
731 return EINVAL;
732 }
733
734 /*
735 * Buffer the request.
736 */
737 if (cbBuf <= sizeof(StackBuf))
738 pHdr = &StackBuf.Hdr;
739 else
740 {
741 pHdr = RTMemTmpAlloc(cbBuf);
742 if (RT_UNLIKELY(!pHdr))
743 {
744 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: failed to allocate buffer of %d bytes for iCmd=%#x.\n", cbBuf, iCmd));
745 return ENOMEM;
746 }
747 }
748 rc = ddi_copyin((void *)iArg, pHdr, cbBuf, Mode);
749 if (RT_UNLIKELY(rc))
750 {
751 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: copy_from_user(,%#lx, %#x) failed; iCmd=%#x. rc=%d\n", iArg, cbBuf, iCmd, rc));
752 if (pHdr != &StackBuf.Hdr)
753 RTMemFree(pHdr);
754 return EFAULT;
755 }
756
757 /*
758 * Process the IOCtl.
759 */
760 rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
761
762 /*
763 * Copy ioctl data and output buffer back to user space.
764 */
765 if (RT_LIKELY(!rc))
766 {
767 uint32_t cbOut = pHdr->cbOut;
768 if (RT_UNLIKELY(cbOut > cbBuf))
769 {
770 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: too much output! %#x > %#x; iCmd=%#x!\n", cbOut, cbBuf, iCmd));
771 cbOut = cbBuf;
772 }
773 rc = ddi_copyout(pHdr, (void *)iArg, cbOut, Mode);
774 if (RT_UNLIKELY(rc != 0))
775 {
776 /* this is really bad */
777 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: ddi_copyout(,%p,%d) failed. rc=%d\n", (void *)iArg, cbBuf, rc));
778 rc = EFAULT;
779 }
780 }
781 else
782 rc = EINVAL;
783
784 if (pHdr != &StackBuf.Hdr)
785 RTMemTmpFree(pHdr);
786 return rc;
787}
788
789
790/**
791 * The SUPDRV IDC entry point.
792 *
793 * @returns VBox status code, see supdrvIDC.
794 * @param iReq The request code.
795 * @param pReq The request.
796 */
797int VBOXCALL SUPDrvSolarisIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
798{
799 PSUPDRVSESSION pSession;
800
801 /*
802 * Some quick validations.
803 */
804 if (RT_UNLIKELY(!VALID_PTR(pReq)))
805 return VERR_INVALID_POINTER;
806
807 pSession = pReq->pSession;
808 if (pSession)
809 {
810 if (RT_UNLIKELY(!VALID_PTR(pSession)))
811 return VERR_INVALID_PARAMETER;
812 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
813 return VERR_INVALID_PARAMETER;
814 }
815 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
816 return VERR_INVALID_PARAMETER;
817
818 /*
819 * Do the job.
820 */
821 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
822}
823
824
825/**
826 * Converts an supdrv error code to a solaris error code.
827 *
828 * @returns corresponding solaris error code.
829 * @param rc supdrv error code (SUPDRV_ERR_* defines).
830 */
831static int VBoxSupDrvErr2SolarisErr(int rc)
832{
833 switch (rc)
834 {
835 case 0: return 0;
836 case SUPDRV_ERR_GENERAL_FAILURE: return EACCES;
837 case SUPDRV_ERR_INVALID_PARAM: return EINVAL;
838 case SUPDRV_ERR_INVALID_MAGIC: return EILSEQ;
839 case SUPDRV_ERR_INVALID_HANDLE: return ENXIO;
840 case SUPDRV_ERR_INVALID_POINTER: return EFAULT;
841 case SUPDRV_ERR_LOCK_FAILED: return ENOLCK;
842 case SUPDRV_ERR_ALREADY_LOADED: return EEXIST;
843 case SUPDRV_ERR_PERMISSION_DENIED: return EPERM;
844 case SUPDRV_ERR_VERSION_MISMATCH: return ENOSYS;
845 }
846
847 return EPERM;
848}
849
850
851/**
852 * Initializes any OS specific object creator fields.
853 */
854void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
855{
856 NOREF(pObj);
857 NOREF(pSession);
858}
859
860
861/**
862 * Checks if the session can access the object.
863 *
864 * @returns true if a decision has been made.
865 * @returns false if the default access policy should be applied.
866 *
867 * @param pObj The object in question.
868 * @param pSession The session wanting to access the object.
869 * @param pszObjName The object name, can be NULL.
870 * @param prc Where to store the result when returning true.
871 */
872bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
873{
874 NOREF(pObj);
875 NOREF(pSession);
876 NOREF(pszObjName);
877 NOREF(prc);
878 return false;
879}
880
881
882bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
883{
884 return false;
885}
886
887
888RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
889{
890 va_list args;
891 char szMsg[512];
892
893 va_start(args, pszFormat);
894 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, args);
895 va_end(args);
896
897 szMsg[sizeof(szMsg) - 1] = '\0';
898 cmn_err(CE_CONT, "%s", szMsg);
899 return 0;
900}
901
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