VirtualBox

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

Last change on this file since 19889 was 19271, checked in by vboxsync, 16 years ago

Solaris/vboxdrv: suspend/resume ring0 notifications.

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