VirtualBox

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

Last change on this file since 25270 was 25262, checked in by vboxsync, 15 years ago

SUPDrv: Works on vista...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 28.0 KB
Line 
1/* $Id: SUPDrv-solaris.c 25262 2009-12-09 04:20:18Z 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 {
154 &g_VBoxDrvSolarisModule,
155 NULL /* terminate array of linkage structures */
156 }
157};
158
159#ifndef USE_SESSION_HASH
160/**
161 * State info for each open file handle.
162 */
163typedef struct
164{
165 /**< Pointer to the session data. */
166 PSUPDRVSESSION pSession;
167} vbox_devstate_t;
168#else
169/** State info. for each driver instance. */
170typedef struct
171{
172 dev_info_t *pDip; /* Device handle */
173} vbox_devstate_t;
174#endif
175
176/** Opaque pointer to list of state */
177static void *g_pVBoxDrvSolarisState;
178
179/** Device extention & session data association structure */
180static SUPDRVDEVEXT g_DevExt;
181
182/** Hash table */
183static PSUPDRVSESSION g_apSessionHashTab[19];
184/** Spinlock protecting g_apSessionHashTab. */
185static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
186/** Calculates bucket index into g_apSessionHashTab.*/
187#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
188
189/**
190 * Kernel entry points
191 */
192int _init(void)
193{
194 LogFlow((DEVICE_NAME ":_init\n"));
195
196 /*
197 * Prevent module autounloading.
198 */
199 modctl_t *pModCtl = mod_getctl(&g_VBoxDrvSolarisModLinkage);
200 if (pModCtl)
201 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
202 else
203 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
204
205 /*
206 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
207 */
208 int rc = RTR0Init(0);
209 if (RT_SUCCESS(rc))
210 {
211 /*
212 * Initialize the device extension
213 */
214 rc = supdrvInitDevExt(&g_DevExt);
215 if (RT_SUCCESS(rc))
216 {
217 /*
218 * Initialize the session hash table.
219 */
220 memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab));
221 rc = RTSpinlockCreate(&g_Spinlock);
222 if (RT_SUCCESS(rc))
223 {
224 rc = ddi_soft_state_init(&g_pVBoxDrvSolarisState, sizeof(vbox_devstate_t), 8);
225 if (!rc)
226 {
227 rc = mod_install(&g_VBoxDrvSolarisModLinkage);
228 if (!rc)
229 return rc; /* success */
230
231 ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
232 LogRel((DEVICE_NAME ":mod_install failed! rc=%d\n", rc));
233 }
234 else
235 LogRel((DEVICE_NAME ":failed to initialize soft state.\n"));
236
237 RTSpinlockDestroy(g_Spinlock);
238 g_Spinlock = NIL_RTSPINLOCK;
239 }
240 else
241 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: RTSpinlockCreate failed\n"));
242 supdrvDeleteDevExt(&g_DevExt);
243 }
244 else
245 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: supdrvInitDevExt failed\n"));
246 RTR0TermForced();
247 }
248 else
249 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: failed to init R0Drv\n"));
250 memset(&g_DevExt, 0, sizeof(g_DevExt));
251
252 return RTErrConvertToErrno(rc);
253}
254
255
256int _fini(void)
257{
258 LogFlow((DEVICE_NAME ":_fini\n"));
259
260 /*
261 * Undo the work we did at start (in the reverse order).
262 */
263 int rc = mod_remove(&g_VBoxDrvSolarisModLinkage);
264 if (rc != 0)
265 return rc;
266
267 supdrvDeleteDevExt(&g_DevExt);
268
269 rc = RTSpinlockDestroy(g_Spinlock);
270 AssertRC(rc);
271 g_Spinlock = NIL_RTSPINLOCK;
272
273 RTR0TermForced();
274
275 memset(&g_DevExt, 0, sizeof(g_DevExt));
276
277 ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
278 return 0;
279}
280
281
282int _info(struct modinfo *pModInfo)
283{
284 LogFlow((DEVICE_NAME ":_info\n"));
285 int e = mod_info(&g_VBoxDrvSolarisModLinkage, pModInfo);
286 return e;
287}
288
289
290/**
291 * Attach entry point, to attach a device to the system or resume it.
292 *
293 * @param pDip The module structure instance.
294 * @param enmCmd Operation type (attach/resume).
295 *
296 * @return corresponding solaris error code.
297 */
298static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
299{
300 LogFlow((DEVICE_NAME ":VBoxDrvSolarisAttach\n"));
301
302 switch (enmCmd)
303 {
304 case DDI_ATTACH:
305 {
306 int rc;
307 int instance = ddi_get_instance(pDip);
308#ifdef USE_SESSION_HASH
309 vbox_devstate_t *pState;
310
311 if (ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, instance) != DDI_SUCCESS)
312 {
313 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: state alloc failed\n"));
314 return DDI_FAILURE;
315 }
316
317 pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
318#endif
319
320 /*
321 * Register for suspend/resume notifications
322 */
323 rc = ddi_prop_create(DDI_DEV_T_NONE, pDip, DDI_PROP_CANSLEEP /* kmem alloc can sleep */,
324 "pm-hardware-state", "needs-suspend-resume", sizeof("needs-suspend-resume"));
325 if (rc != DDI_PROP_SUCCESS)
326 LogRel((DEVICE_NAME ":Suspend/Resume notification registeration failed.\n"));
327
328 /*
329 * Register ourselves as a character device, pseudo-driver
330 */
331#ifdef VBOX_WITH_HARDENING
332 rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO,
333 0, NULL, NULL, 0600);
334#else
335 rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO,
336 0, "none", "none", 0666);
337#endif
338 if (rc == DDI_SUCCESS)
339 {
340#ifdef USE_SESSION_HASH
341 pState->pDip = pDip;
342#endif
343 ddi_report_dev(pDip);
344 return DDI_SUCCESS;
345 }
346
347 return DDI_FAILURE;
348 }
349
350 case DDI_RESUME:
351 {
352#if 0
353 RTSemFastMutexRequest(g_DevExt.mtxGip);
354 if (g_DevExt.pGipTimer)
355 RTTimerStart(g_DevExt.pGipTimer, 0);
356
357 RTSemFastMutexRelease(g_DevExt.mtxGip);
358#endif
359 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
360 LogFlow((DEVICE_NAME ": Awakened from suspend.\n"));
361 return DDI_SUCCESS;
362 }
363
364 default:
365 return DDI_FAILURE;
366 }
367
368 return DDI_FAILURE;
369}
370
371
372/**
373 * Detach entry point, to detach a device to the system or suspend it.
374 *
375 * @param pDip The module structure instance.
376 * @param enmCmd Operation type (detach/suspend).
377 *
378 * @return corresponding solaris error code.
379 */
380static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
381{
382 LogFlow((DEVICE_NAME ":VBoxDrvSolarisDetach\n"));
383 switch (enmCmd)
384 {
385 case DDI_DETACH:
386 {
387#ifndef USE_SESSION_HASH
388 ddi_remove_minor_node(pDip, NULL);
389#else
390 int instance = ddi_get_instance(pDip);
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#endif
515
516 return VBoxSupDrvErr2SolarisErr(rc);
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#ifdef VBOX_WITH_NATIVE_R0_LOADER
900
901int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
902{
903 /** @todo This is something that shouldn't be impossible to implement
904 * here and would make a few people happy. */
905 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
906 return VERR_NOT_SUPPORTED;
907}
908
909
910int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
911{
912 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
913 return VERR_NOT_SUPPORTED;
914}
915
916
917int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits)
918{
919 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits);
920 return VERR_NOT_SUPPORTED;
921}
922
923
924void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
925{
926 NOREF(pDevExt); NOREF(pImage);
927}
928
929#endif /* VBOX_WITH_NATIVE_R0_LOADER */
930
931RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
932{
933 va_list args;
934 char szMsg[512];
935
936 va_start(args, pszFormat);
937 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, args);
938 va_end(args);
939
940 szMsg[sizeof(szMsg) - 1] = '\0';
941 cmn_err(CE_CONT, "%s", szMsg);
942 return 0;
943}
944
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