VirtualBox

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

Last change on this file since 10682 was 10662, checked in by vboxsync, 17 years ago

Increased the IOC version to 7.4 with the exporting of SUPR0ComponentQueryFactory and friends. Added release logging to darwin, windows and freebsd.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 25.6 KB
Line 
1/* $Id: SUPDrv-solaris.c 10662 2008-07-15 14:36:00Z 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#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
49
50#include "../SUPDrvInternal.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 list of 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 Operation type (attach/resume).
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 Operation type (detach/suspend).
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, true /* fUser */, &pSession);
423 if (RT_SUCCESS(rc))
424 {
425 pSession->Uid = crgetuid(pCred);
426 pSession->Gid = crgetgid(pCred);
427
428 pState->pSession = pSession;
429 *pDev = makedevice(getmajor(*pDev), iOpenInstance);
430 dprintf(("VBoxDrvSolarisOpen: returns pDev=%#x pSession=%p pState=%p\n", *pDev, pSession, pState));
431 OSDBGPRINT(("VBoxDrvSolarisOpen: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
432 *pDev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
433 return 0;
434 }
435
436 /* failed - clean up */
437 ddi_soft_state_free(g_pVBoxDrvSolarisState, iOpenInstance);
438
439#else
440 /*
441 * Create a new session.
442 * Sessions in Solaris driver are mostly useless. It's however needed
443 * in VBoxDrvSolarisIOCtlSlow() while calling supdrvIOCtl()
444 */
445 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
446 if (RT_SUCCESS(rc))
447 {
448 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
449 unsigned iHash;
450
451 pSession->Uid = crgetuid(pCred);
452 pSession->Gid = crgetgid(pCred);
453
454 /*
455 * Insert it into the hash table.
456 */
457 iHash = SESSION_HASH(pSession->Process);
458 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
459 pSession->pNextHash = g_apSessionHashTab[iHash];
460 g_apSessionHashTab[iHash] = pSession;
461 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
462 OSDBGPRINT(("VBoxDrvSolarisOpen success"));
463 }
464
465 int instance;
466 for (instance = 0; instance < DEVICE_MAXINSTANCES; instance++)
467 {
468 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
469 if (pState)
470 break;
471 }
472
473 if (instance >= DEVICE_MAXINSTANCES)
474 {
475 cmn_err(CE_NOTE, "VBoxDrvSolarisOpen: All instances exhausted\n");
476 return ENXIO;
477 }
478
479 *pDev = makedevice(getmajor(*pDev), instance);
480
481 return VBoxSupDrvErr2SolarisErr(rc);
482#endif
483}
484
485
486static int VBoxDrvSolarisClose(dev_t Dev, int flag, int otyp, cred_t *cred)
487{
488 dprintf(("VBoxDrvSolarisClose: Dev=%#x\n", Dev));
489#ifndef USE_SESSION_HASH
490 /*
491 * Get the session and free the soft state item.
492 */
493 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
494 if (!pState)
495 {
496 OSDBGPRINT(("VBoxDrvSolarisClose: no state data for %#x (%d)\n", Dev, getminor(Dev)));
497 return EFAULT;
498 }
499
500 PSUPDRVSESSION pSession = pState->pSession;
501 pState->pSession = NULL;
502 ddi_soft_state_free(g_pVBoxDrvSolarisState, getminor(Dev));
503
504 if (!pSession)
505 {
506 OSDBGPRINT(("VBoxDrvSolarisClose: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
507 return EFAULT;
508 }
509 dprintf(("VBoxDrvSolarisClose: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n", Dev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
510
511#else
512 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
513 const RTPROCESS Process = RTProcSelf();
514 const unsigned iHash = SESSION_HASH(Process);
515 PSUPDRVSESSION pSession;
516
517 /*
518 * Remove from the hash table.
519 */
520 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
521 pSession = g_apSessionHashTab[iHash];
522 if (pSession)
523 {
524 if (pSession->Process == Process)
525 {
526 g_apSessionHashTab[iHash] = pSession->pNextHash;
527 pSession->pNextHash = NULL;
528 }
529 else
530 {
531 PSUPDRVSESSION pPrev = pSession;
532 pSession = pSession->pNextHash;
533 while (pSession)
534 {
535 if (pSession->Process == Process)
536 {
537 pPrev->pNextHash = pSession->pNextHash;
538 pSession->pNextHash = NULL;
539 break;
540 }
541
542 /* next */
543 pPrev = pSession;
544 pSession = pSession->pNextHash;
545 }
546 }
547 }
548 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
549 if (!pSession)
550 {
551 OSDBGPRINT(("VBoxDrvSolarisClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n",
552 (int)Process));
553 return EFAULT;
554 }
555#endif
556
557 /*
558 * Close the session.
559 */
560 supdrvCloseSession(&g_DevExt, pSession);
561 dprintf(("VBoxDrvSolarisClose: returns\n"));
562 return 0;
563}
564
565
566static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
567{
568 dprintf(("VBoxDrvSolarisRead"));
569 return 0;
570}
571
572
573static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
574{
575 dprintf(("VBoxDrvSolarisWrite"));
576 return 0;
577}
578
579
580/**
581 * Driver ioctl, an alternate entry point for this character driver.
582 *
583 * @param Dev Device number
584 * @param Cmd Operation identifier
585 * @param pArg Arguments from user to driver
586 * @param Mode Information bitfield (read/write, address space etc.)
587 * @param pCred User credentials
588 * @param pVal Return value for calling process.
589 *
590 * @return corresponding solaris error code.
591 */
592static int VBoxDrvSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int Mode, cred_t *pCred, int *pVal)
593{
594#ifndef USE_SESSION_HASH
595 /*
596 * Get the session from the soft state item.
597 */
598 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
599 if (!pState)
600 {
601 OSDBGPRINT(("VBoxDrvSolarisIOCtl: no state data for %#x (%d)\n", Dev, getminor(Dev)));
602 return EINVAL;
603 }
604
605 PSUPDRVSESSION pSession = pState->pSession;
606 if (!pSession)
607 {
608 OSDBGPRINT(("VBoxDrvSolarisIOCtl: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
609 return DDI_SUCCESS;
610 }
611#else
612 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
613 const RTPROCESS Process = RTProcSelf();
614 const unsigned iHash = SESSION_HASH(Process);
615 PSUPDRVSESSION pSession;
616
617 /*
618 * Find the session.
619 */
620 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
621 pSession = g_apSessionHashTab[iHash];
622 if (pSession && pSession->Process != Process)
623 {
624 do pSession = pSession->pNextHash;
625 while (pSession && pSession->Process != Process);
626 }
627 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
628 if (!pSession)
629 {
630 OSDBGPRINT(("VBoxSupDrvIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
631 (int)Process, Cmd));
632 return EINVAL;
633 }
634#endif
635
636 /*
637 * Deal with the two high-speed IOCtl that takes it's arguments from
638 * the session and iCmd, and only returns a VBox status code.
639 */
640 if ( Cmd == SUP_IOCTL_FAST_DO_RAW_RUN
641 || Cmd == SUP_IOCTL_FAST_DO_HWACC_RUN
642 || Cmd == SUP_IOCTL_FAST_DO_NOP)
643 {
644 *pVal = supdrvIOCtlFast(Cmd, &g_DevExt, pSession);
645 return 0;
646 }
647
648 return VBoxDrvSolarisIOCtlSlow(pSession, Cmd, Mode, pArgs);
649}
650
651
652/** @def IOCPARM_LEN
653 * Gets the length from the ioctl number.
654 * This is normally defined by sys/ioccom.h on BSD systems...
655 */
656#ifndef IOCPARM_LEN
657# define IOCPARM_LEN(x) ( ((x) >> 16) & IOCPARM_MASK )
658#endif
659
660
661/**
662 * Worker for VBoxSupDrvIOCtl that takes the slow IOCtl functions.
663 *
664 * @returns Solaris errno.
665 *
666 * @param pSession The session.
667 * @param Cmd The IOCtl command.
668 * @param Mode Information bitfield (for specifying ownership of data)
669 * @param iArg User space address of the request buffer.
670 */
671static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int iCmd, int Mode, intptr_t iArg)
672{
673 int rc;
674 uint32_t cbBuf = 0;
675 SUPREQHDR Hdr;
676 PSUPREQHDR pHdr;
677
678
679 /*
680 * Read the header.
681 */
682 if (RT_UNLIKELY(IOCPARM_LEN(iCmd) != sizeof(Hdr)))
683 {
684 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: iCmd=%#x len %d expected %d\n", iCmd, IOCPARM_LEN(iCmd), sizeof(Hdr)));
685 return EINVAL;
686 }
687 rc = ddi_copyin((void *)iArg, &Hdr, sizeof(Hdr), Mode);
688 if (RT_UNLIKELY(rc))
689 {
690 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: ddi_copyin(,%#lx,) failed; iCmd=%#x. rc=%d\n", iArg, iCmd, rc));
691 return EFAULT;
692 }
693 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
694 {
695 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: bad header magic %#x; iCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, iCmd));
696 return EINVAL;
697 }
698 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
699 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
700 || Hdr.cbOut < sizeof(Hdr)
701 || cbBuf > _1M*16))
702 {
703 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: max(%#x,%#x); iCmd=%#x\n", Hdr.cbIn, Hdr.cbOut, iCmd));
704 return EINVAL;
705 }
706
707 /*
708 * Buffer the request.
709 */
710 pHdr = RTMemTmpAlloc(cbBuf);
711 if (RT_UNLIKELY(!pHdr))
712 {
713 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: failed to allocate buffer of %d bytes for iCmd=%#x.\n", cbBuf, iCmd));
714 return ENOMEM;
715 }
716 rc = ddi_copyin((void *)iArg, pHdr, cbBuf, Mode);
717 if (RT_UNLIKELY(rc))
718 {
719 dprintf(("VBoxDrvSolarisIOCtlSlow: copy_from_user(,%#lx, %#x) failed; iCmd=%#x. rc=%d\n", iArg, Hdr.cbIn, iCmd, rc));
720 RTMemFree(pHdr);
721 return EFAULT;
722 }
723
724 /*
725 * Process the IOCtl.
726 */
727 rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
728
729 /*
730 * Copy ioctl data and output buffer back to user space.
731 */
732 if (RT_LIKELY(!rc))
733 {
734 uint32_t cbOut = pHdr->cbOut;
735 if (RT_UNLIKELY(cbOut > cbBuf))
736 {
737 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: too much output! %#x > %#x; iCmd=%#x!\n", cbOut, cbBuf, iCmd));
738 cbOut = cbBuf;
739 }
740 rc = ddi_copyout(pHdr, (void *)iArg, cbOut, Mode);
741 if (RT_UNLIKELY(rc != 0))
742 {
743 /* this is really bad */
744 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: ddi_copyout(,%p,%d) failed. rc=%d\n", (void *)iArg, cbBuf, rc));
745 rc = EFAULT;
746 }
747 }
748 else
749 rc = EINVAL;
750
751 RTMemTmpFree(pHdr);
752 return rc;
753}
754
755
756/**
757 * The SUPDRV IDC entry point.
758 *
759 * @returns VBox status code, see supdrvIDC.
760 * @param iReq The request code.
761 * @param pReq The request.
762 */
763int VBOXCALL SUPDrvSolarisIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
764{
765 PSUPDRVSESSION pSession;
766
767 /*
768 * Some quick validations.
769 */
770 if (RT_UNLIKELY(!VALID_PTR(pReq)))
771 return VERR_INVALID_POINTER;
772
773 pSession = pReq->pSession;
774 if (pSession)
775 {
776 if (RT_UNLIKELY(!VALID_PTR(pSession)))
777 return VERR_INVALID_PARAMETER;
778 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
779 return VERR_INVALID_PARAMETER;
780 }
781 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
782 return VERR_INVALID_PARAMETER;
783
784 /*
785 * Do the job.
786 */
787 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
788}
789
790
791/**
792 * Converts an supdrv error code to a solaris error code.
793 *
794 * @returns corresponding solaris error code.
795 * @param rc supdrv error code (SUPDRV_ERR_* defines).
796 */
797static int VBoxSupDrvErr2SolarisErr(int rc)
798{
799 switch (rc)
800 {
801 case 0: return 0;
802 case SUPDRV_ERR_GENERAL_FAILURE: return EACCES;
803 case SUPDRV_ERR_INVALID_PARAM: return EINVAL;
804 case SUPDRV_ERR_INVALID_MAGIC: return EILSEQ;
805 case SUPDRV_ERR_INVALID_HANDLE: return ENXIO;
806 case SUPDRV_ERR_INVALID_POINTER: return EFAULT;
807 case SUPDRV_ERR_LOCK_FAILED: return ENOLCK;
808 case SUPDRV_ERR_ALREADY_LOADED: return EEXIST;
809 case SUPDRV_ERR_PERMISSION_DENIED: return EPERM;
810 case SUPDRV_ERR_VERSION_MISMATCH: return ENOSYS;
811 }
812
813 return EPERM;
814}
815
816
817/**
818 * Initializes any OS specific object creator fields.
819 */
820void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
821{
822 NOREF(pObj);
823 NOREF(pSession);
824}
825
826
827/**
828 * Checks if the session can access the object.
829 *
830 * @returns true if a decision has been made.
831 * @returns false if the default access policy should be applied.
832 *
833 * @param pObj The object in question.
834 * @param pSession The session wanting to access the object.
835 * @param pszObjName The object name, can be NULL.
836 * @param prc Where to store the result when returning true.
837 */
838bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
839{
840 NOREF(pObj);
841 NOREF(pSession);
842 NOREF(pszObjName);
843 NOREF(prc);
844 return false;
845}
846
847
848bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
849{
850 return false;
851}
852
853
854RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
855{
856 va_list args;
857 char szMsg[512];
858
859 va_start(args, pszFormat);
860 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, args);
861 va_end(args);
862
863 szMsg[sizeof(szMsg) - 1] = '\0';
864#if 0
865 uprintf("SUPR0Printf: %s", szMsg);
866#endif
867#if 1
868 cmn_err(CE_CONT, "VBoxDrv: %s", szMsg);
869#endif
870
871 return 0;
872}
873
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