VirtualBox

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

Last change on this file since 9657 was 9602, checked in by vboxsync, 17 years ago

Changed RTR0MpNotificationInit/Term to rtR0MpNotificationInit/Term and dropped the unused pvOS argument. They are now IPRT internal and called by RTR0Init/Term.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 24.7 KB
Line 
1/* $Id: SUPDrv-solaris.c 9602 2008-06-11 12:09:31Z 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 /*
266 * Initialize the device extension
267 */
268 rc = supdrvInitDevExt(&g_DevExt);
269 if (RT_SUCCESS(rc))
270 {
271 /*
272 * Initialize the session hash table.
273 */
274 memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab));
275 rc = RTSpinlockCreate(&g_Spinlock);
276 if (RT_SUCCESS(rc))
277 {
278 /*
279 * Register ourselves as a character device, pseudo-driver
280 */
281 if (ddi_create_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, 0) == DDI_SUCCESS)
282 {
283#ifdef USE_SESSION_HASH
284 pState->pDip = pDip;
285#endif
286 ddi_report_dev(pDip);
287 return DDI_SUCCESS;
288 }
289
290 /* Is this really necessary? */
291 ddi_remove_minor_node(pDip, NULL);
292 cmn_err(CE_NOTE,"VBoxDrvSolarisAttach: ddi_create_minor_node failed.");
293
294 RTSpinlockDestroy(g_Spinlock);
295 g_Spinlock = NIL_RTSPINLOCK;
296 }
297 else
298 cmn_err(CE_NOTE, "VBoxDrvSolarisAttach: RTSpinlockCreate failed");
299 supdrvDeleteDevExt(&g_DevExt);
300 }
301 else
302 cmn_err(CE_NOTE, "VBoxDrvSolarisAttach: supdrvInitDevExt failed");
303 RTR0Term();
304 }
305 else
306 cmn_err(CE_NOTE, "VBoxDrvSolarisAttach: failed to init R0Drv");
307 memset(&g_DevExt, 0, sizeof(g_DevExt));
308 break;
309 }
310
311 case DDI_RESUME:
312 {
313 RTSemFastMutexRequest(g_DevExt.mtxGip);
314 if (g_DevExt.pGipTimer)
315 RTTimerStart(g_DevExt.pGipTimer, 0);
316
317 RTSemFastMutexRelease(g_DevExt.mtxGip);
318 return DDI_SUCCESS;
319 }
320
321 default:
322 return DDI_FAILURE;
323 }
324
325 return DDI_FAILURE;
326}
327
328
329/**
330 * Detach entry point, to detach a device to the system or suspend it.
331 *
332 * @param pDip The module structure instance.
333 * @param enmCmd Attach type (ddi_attach_cmd_t)
334 *
335 * @return corresponding solaris error code.
336 */
337static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
338{
339 int rc = VINF_SUCCESS;
340
341
342 dprintf(("VBoxDrvSolarisDetach"));
343 switch (enmCmd)
344 {
345 case DDI_DETACH:
346 {
347 int instance = ddi_get_instance(pDip);
348#ifndef USE_SESSION_HASH
349 ddi_remove_minor_node(pDip, NULL);
350#else
351 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
352 ddi_remove_minor_node(pDip, NULL);
353 ddi_soft_state_free(g_pVBoxDrvSolarisState, instance);
354#endif
355
356 supdrvDeleteDevExt(&g_DevExt);
357
358 rc = RTSpinlockDestroy(g_Spinlock);
359 AssertRC(rc);
360 g_Spinlock = NIL_RTSPINLOCK;
361
362 RTR0Term();
363
364 memset(&g_DevExt, 0, sizeof(g_DevExt));
365 dprintf(("VBoxDrvSolarisDetach: Clean Up Done."));
366 return DDI_SUCCESS;
367 }
368
369 case DDI_SUSPEND:
370 {
371 RTSemFastMutexRequest(g_DevExt.mtxGip);
372 if (g_DevExt.pGipTimer && g_DevExt.cGipUsers > 0)
373 RTTimerStop(g_DevExt.pGipTimer);
374
375 RTSemFastMutexRelease(g_DevExt.mtxGip);
376 return DDI_SUCCESS;
377 }
378
379 default:
380 return DDI_FAILURE;
381 }
382}
383
384
385
386/**
387 * User context entry points
388 */
389static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
390{
391 int rc;
392 PSUPDRVSESSION pSession;
393 dprintf(("VBoxDrvSolarisOpen: pDev=%p:%#x\n", pDev, *pDev));
394
395#ifndef USE_SESSION_HASH
396 /*
397 * Locate a new device open instance.
398 *
399 * For each open call we'll allocate an item in the soft state of the device.
400 * The item index is stored in the dev_t. I hope this is ok...
401 */
402 vbox_devstate_t *pState = NULL;
403 unsigned iOpenInstance;
404 for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
405 {
406 if ( !ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance) /* faster */
407 && ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, iOpenInstance) == DDI_SUCCESS)
408 {
409 pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance);
410 break;
411 }
412 }
413 if (!pState)
414 {
415 cmn_err(CE_NOTE,"VBoxDrvSolarisOpen: too many open instances.");
416 return ENXIO;
417 }
418
419 /*
420 * Create a new session.
421 */
422 rc = supdrvCreateSession(&g_DevExt, &pSession);
423 if (RT_SUCCESS(rc))
424 {
425 pState->pSession = pSession;
426 *pDev = makedevice(getmajor(*pDev), iOpenInstance);
427 dprintf(("VBoxDrvSolarisOpen: returns pDev=%#x pSession=%p pState=%p\n", *pDev, pSession, pState));
428 OSDBGPRINT(("VBoxDrvSolarisOpen: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
429 *pDev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
430 return 0;
431 }
432
433 /* failed - clean up */
434 ddi_soft_state_free(g_pVBoxDrvSolarisState, iOpenInstance);
435
436#else
437 /*
438 * Create a new session.
439 * Sessions in Solaris driver are mostly useless. It's however needed
440 * in VBoxDrvSolarisIOCtlSlow() while calling supdrvIOCtl()
441 */
442 rc = supdrvCreateSession(&g_DevExt, &pSession);
443 if (RT_SUCCESS(rc))
444 {
445 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
446 unsigned iHash;
447
448 pSession->Uid = crgetuid(pCred);
449 pSession->Gid = crgetgid(pCred);
450 pSession->Process = RTProcSelf();
451 pSession->R0Process = RTR0ProcHandleSelf();
452
453 /*
454 * Insert it into the hash table.
455 */
456 iHash = SESSION_HASH(pSession->Process);
457 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
458 pSession->pNextHash = g_apSessionHashTab[iHash];
459 g_apSessionHashTab[iHash] = pSession;
460 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
461 OSDBGPRINT(("VBoxDrvSolarisOpen success"));
462 }
463
464 int instance;
465 for (instance = 0; instance < DEVICE_MAXINSTANCES; instance++)
466 {
467 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
468 if (pState)
469 break;
470 }
471
472 if (instance >= DEVICE_MAXINSTANCES)
473 {
474 cmn_err(CE_NOTE, "VBoxDrvSolarisOpen: All instances exhausted\n");
475 return ENXIO;
476 }
477
478 *pDev = makedevice(getmajor(*pDev), instance);
479
480 return VBoxSupDrvErr2SolarisErr(rc);
481#endif
482}
483
484
485static int VBoxDrvSolarisClose(dev_t Dev, int flag, int otyp, cred_t *cred)
486{
487 dprintf(("VBoxDrvSolarisClose: Dev=%#x\n", Dev));
488#ifndef USE_SESSION_HASH
489 /*
490 * Get the session and free the soft state item.
491 */
492 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
493 if (!pState)
494 {
495 OSDBGPRINT(("VBoxDrvSolarisClose: no state data for %#x (%d)\n", Dev, getminor(Dev)));
496 return EFAULT;
497 }
498
499 PSUPDRVSESSION pSession = pState->pSession;
500 pState->pSession = NULL;
501 ddi_soft_state_free(g_pVBoxDrvSolarisState, getminor(Dev));
502
503 if (!pSession)
504 {
505 OSDBGPRINT(("VBoxDrvSolarisClose: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
506 return EFAULT;
507 }
508 dprintf(("VBoxDrvSolarisClose: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n", Dev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
509
510#else
511 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
512 const RTPROCESS Process = RTProcSelf();
513 const unsigned iHash = SESSION_HASH(Process);
514 PSUPDRVSESSION pSession;
515
516 /*
517 * Remove from the hash table.
518 */
519 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
520 pSession = g_apSessionHashTab[iHash];
521 if (pSession)
522 {
523 if (pSession->Process == Process)
524 {
525 g_apSessionHashTab[iHash] = pSession->pNextHash;
526 pSession->pNextHash = NULL;
527 }
528 else
529 {
530 PSUPDRVSESSION pPrev = pSession;
531 pSession = pSession->pNextHash;
532 while (pSession)
533 {
534 if (pSession->Process == Process)
535 {
536 pPrev->pNextHash = pSession->pNextHash;
537 pSession->pNextHash = NULL;
538 break;
539 }
540
541 /* next */
542 pPrev = pSession;
543 pSession = pSession->pNextHash;
544 }
545 }
546 }
547 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
548 if (!pSession)
549 {
550 OSDBGPRINT(("VBoxDrvSolarisClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n",
551 (int)Process));
552 return EFAULT;
553 }
554#endif
555
556 /*
557 * Close the session.
558 */
559 supdrvCloseSession(&g_DevExt, pSession);
560 dprintf(("VBoxDrvSolarisClose: returns\n"));
561 return 0;
562}
563
564
565static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
566{
567 dprintf(("VBoxDrvSolarisRead"));
568 return 0;
569}
570
571
572static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
573{
574 dprintf(("VBoxDrvSolarisWrite"));
575 return 0;
576}
577
578
579/**
580 * Driver ioctl, an alternate entry point for this character driver.
581 *
582 * @param Dev Device number
583 * @param Cmd Operation identifier
584 * @param pArg Arguments from user to driver
585 * @param Mode Information bitfield (read/write, address space etc.)
586 * @param pCred User credentials
587 * @param pVal Return value for calling process.
588 *
589 * @return corresponding solaris error code.
590 */
591static int VBoxDrvSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int Mode, cred_t *pCred, int *pVal)
592{
593#ifndef USE_SESSION_HASH
594 /*
595 * Get the session from the soft state item.
596 */
597 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
598 if (!pState)
599 {
600 OSDBGPRINT(("VBoxDrvSolarisIOCtl: no state data for %#x (%d)\n", Dev, getminor(Dev)));
601 return EINVAL;
602 }
603
604 PSUPDRVSESSION pSession = pState->pSession;
605 if (!pSession)
606 {
607 OSDBGPRINT(("VBoxDrvSolarisIOCtl: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
608 return DDI_SUCCESS;
609 }
610#else
611 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
612 const RTPROCESS Process = RTProcSelf();
613 const unsigned iHash = SESSION_HASH(Process);
614 PSUPDRVSESSION pSession;
615
616 /*
617 * Find the session.
618 */
619 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
620 pSession = g_apSessionHashTab[iHash];
621 if (pSession && pSession->Process != Process)
622 {
623 do pSession = pSession->pNextHash;
624 while (pSession && pSession->Process != Process);
625 }
626 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
627 if (!pSession)
628 {
629 OSDBGPRINT(("VBoxSupDrvIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
630 (int)Process, Cmd));
631 return EINVAL;
632 }
633#endif
634
635 /*
636 * Deal with the two high-speed IOCtl that takes it's arguments from
637 * the session and iCmd, and only returns a VBox status code.
638 */
639 if ( Cmd == SUP_IOCTL_FAST_DO_RAW_RUN
640 || Cmd == SUP_IOCTL_FAST_DO_HWACC_RUN
641 || Cmd == SUP_IOCTL_FAST_DO_NOP)
642 {
643 *pVal = supdrvIOCtlFast(Cmd, &g_DevExt, pSession);
644 return 0;
645 }
646
647 return VBoxDrvSolarisIOCtlSlow(pSession, Cmd, Mode, pArgs);
648}
649
650
651/** @def IOCPARM_LEN
652 * Gets the length from the ioctl number.
653 * This is normally defined by sys/ioccom.h on BSD systems...
654 */
655#ifndef IOCPARM_LEN
656# define IOCPARM_LEN(x) ( ((x) >> 16) & IOCPARM_MASK )
657#endif
658
659
660/**
661 * Worker for VBoxSupDrvIOCtl that takes the slow IOCtl functions.
662 *
663 * @returns Solaris errno.
664 *
665 * @param pSession The session.
666 * @param Cmd The IOCtl command.
667 * @param Mode Information bitfield (for specifying ownership of data)
668 * @param iArg User space address of the request buffer.
669 */
670static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int iCmd, int Mode, intptr_t iArg)
671{
672 int rc;
673 uint32_t cbBuf = 0;
674 SUPREQHDR Hdr;
675 PSUPREQHDR pHdr;
676
677
678 /*
679 * Read the header.
680 */
681 if (RT_UNLIKELY(IOCPARM_LEN(iCmd) != sizeof(Hdr)))
682 {
683 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: iCmd=%#x len %d expected %d\n", iCmd, IOCPARM_LEN(iCmd), sizeof(Hdr)));
684 return EINVAL;
685 }
686 rc = ddi_copyin((void *)iArg, &Hdr, sizeof(Hdr), Mode);
687 if (RT_UNLIKELY(rc))
688 {
689 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: ddi_copyin(,%#lx,) failed; iCmd=%#x. rc=%d\n", iArg, iCmd, rc));
690 return EFAULT;
691 }
692 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
693 {
694 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: bad header magic %#x; iCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, iCmd));
695 return EINVAL;
696 }
697 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
698 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
699 || Hdr.cbOut < sizeof(Hdr)
700 || cbBuf > _1M*16))
701 {
702 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: max(%#x,%#x); iCmd=%#x\n", Hdr.cbIn, Hdr.cbOut, iCmd));
703 return EINVAL;
704 }
705
706 /*
707 * Buffer the request.
708 */
709 pHdr = RTMemTmpAlloc(cbBuf);
710 if (RT_UNLIKELY(!pHdr))
711 {
712 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: failed to allocate buffer of %d bytes for iCmd=%#x.\n", cbBuf, iCmd));
713 return ENOMEM;
714 }
715 rc = ddi_copyin((void *)iArg, pHdr, cbBuf, Mode);
716 if (RT_UNLIKELY(rc))
717 {
718 dprintf(("VBoxDrvSolarisIOCtlSlow: copy_from_user(,%#lx, %#x) failed; iCmd=%#x. rc=%d\n", iArg, Hdr.cbIn, iCmd, rc));
719 RTMemFree(pHdr);
720 return EFAULT;
721 }
722
723 /*
724 * Process the IOCtl.
725 */
726 rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
727
728 /*
729 * Copy ioctl data and output buffer back to user space.
730 */
731 if (RT_LIKELY(!rc))
732 {
733 uint32_t cbOut = pHdr->cbOut;
734 if (RT_UNLIKELY(cbOut > cbBuf))
735 {
736 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: too much output! %#x > %#x; iCmd=%#x!\n", cbOut, cbBuf, iCmd));
737 cbOut = cbBuf;
738 }
739 rc = ddi_copyout(pHdr, (void *)iArg, cbOut, Mode);
740 if (RT_UNLIKELY(rc != 0))
741 {
742 /* this is really bad */
743 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: ddi_copyout(,%p,%d) failed. rc=%d\n", (void *)iArg, cbBuf, rc));
744 rc = EFAULT;
745 }
746 }
747 else
748 rc = EINVAL;
749
750 RTMemTmpFree(pHdr);
751 return rc;
752}
753
754
755/**
756 * Converts an supdrv error code to a solaris error code.
757 *
758 * @returns corresponding solaris error code.
759 * @param rc supdrv error code (SUPDRV_ERR_* defines).
760 */
761static int VBoxSupDrvErr2SolarisErr(int rc)
762{
763 switch (rc)
764 {
765 case 0: return 0;
766 case SUPDRV_ERR_GENERAL_FAILURE: return EACCES;
767 case SUPDRV_ERR_INVALID_PARAM: return EINVAL;
768 case SUPDRV_ERR_INVALID_MAGIC: return EILSEQ;
769 case SUPDRV_ERR_INVALID_HANDLE: return ENXIO;
770 case SUPDRV_ERR_INVALID_POINTER: return EFAULT;
771 case SUPDRV_ERR_LOCK_FAILED: return ENOLCK;
772 case SUPDRV_ERR_ALREADY_LOADED: return EEXIST;
773 case SUPDRV_ERR_PERMISSION_DENIED: return EPERM;
774 case SUPDRV_ERR_VERSION_MISMATCH: return ENOSYS;
775 }
776
777 return EPERM;
778}
779
780
781/**
782 * Initializes any OS specific object creator fields.
783 */
784void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
785{
786 NOREF(pObj);
787 NOREF(pSession);
788}
789
790
791/**
792 * Checks if the session can access the object.
793 *
794 * @returns true if a decision has been made.
795 * @returns false if the default access policy should be applied.
796 *
797 * @param pObj The object in question.
798 * @param pSession The session wanting to access the object.
799 * @param pszObjName The object name, can be NULL.
800 * @param prc Where to store the result when returning true.
801 */
802bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
803{
804 NOREF(pObj);
805 NOREF(pSession);
806 NOREF(pszObjName);
807 NOREF(prc);
808 return false;
809}
810
811
812bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
813{
814 return false;
815}
816
817
818RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
819{
820 va_list args;
821 char szMsg[512];
822
823 va_start(args, pszFormat);
824 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, args);
825 va_end(args);
826
827 szMsg[sizeof(szMsg) - 1] = '\0';
828#if 0
829 uprintf("SUPR0Printf: %s", szMsg);
830#endif
831#if 1
832 cmn_err(CE_CONT, "VBoxDrv: %s", szMsg);
833#endif
834
835 return 0;
836}
837
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