VirtualBox

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

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

SUPDrv: shared the symbol table dragging in symbols into the link on darwin and solaris.

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