VirtualBox

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

Last change on this file since 8760 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

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