VirtualBox

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

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

Solaris: protect the GIP using the GIP mutex during suspend/resume.

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