VirtualBox

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

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

Solaris: Added Suspend/Resume for vboxdrv (Untested, needs build snv_77)

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