VirtualBox

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

Last change on this file since 25002 was 24179, checked in by vboxsync, 15 years ago

iprt/initterm.h,SUPDrv-solaris.c: Added RTR0TermForced so the module containing IPRT can make sure it's really terminated and that modules not calling RTR0Term doesn't create trouble (other than debug assertions). Use this for SUPDrv on Solaris.

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