VirtualBox

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

Last change on this file since 6918 was 6918, checked in by vboxsync, 17 years ago

Solaris vboxdrv: Hide more verbose logging in release builds.

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