VirtualBox

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

Last change on this file since 11822 was 11725, checked in by vboxsync, 17 years ago

#3076: Merged in the branch with the alternate driver authentication method. (34468:HEAD)

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