VirtualBox

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

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

Initialize the RTMpNotification stuff.

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