VirtualBox

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

Last change on this file since 36239 was 33595, checked in by vboxsync, 14 years ago

src/*: more spelling fixes (logging), thanks Timeless!

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