VirtualBox

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

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

SUP: pass idCpu up on all platforms (save OS/2), handle it in ring-0 on solaris, linux and freebsd.

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