VirtualBox

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

Last change on this file since 40388 was 38895, checked in by vboxsync, 13 years ago

HostDrivers/solaris: LogFlow->Log for debug purposes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 35.4 KB
Line 
1/* $Id: SUPDrv-solaris.c 38895 2011-09-28 12:04:39Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Solaris specifics.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
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* Header Files *
29*******************************************************************************/
30#define LOG_GROUP LOG_GROUP_SUP_DRV
31#ifdef DEBUG_ramshankar
32# define LOG_ENABLED
33# define LOG_INSTANCE RTLogRelDefaultInstance()
34#endif
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/kobj.h>
42#include <sys/kobj_impl.h>
43#include <sys/open.h>
44#include <sys/conf.h>
45#include <sys/cmn_err.h>
46#include <sys/stat.h>
47#include <sys/ddi.h>
48#include <sys/sunddi.h>
49#include <sys/file.h>
50#include <sys/priv_names.h>
51#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
52
53#include "../SUPDrvInternal.h"
54#include <VBox/log.h>
55#include <VBox/version.h>
56#include <iprt/semaphore.h>
57#include <iprt/spinlock.h>
58#include <iprt/mp.h>
59#include <iprt/path.h>
60#include <iprt/power.h>
61#include <iprt/process.h>
62#include <iprt/thread.h>
63#include <iprt/initterm.h>
64#include <iprt/alloc.h>
65#include <iprt/string.h>
66#include <iprt/err.h>
67
68
69/*******************************************************************************
70* Defined Constants And Macros *
71*******************************************************************************/
72/** The module name. */
73#define DEVICE_NAME "vboxdrv"
74/** The module description as seen in 'modinfo'. */
75#define DEVICE_DESC "VirtualBox HostDrv"
76/** Maximum number of driver instances. */
77#define DEVICE_MAXINSTANCES 16
78
79
80/*******************************************************************************
81* Internal Functions *
82*******************************************************************************/
83static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
84static int VBoxDrvSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
85static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
86static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
87static int VBoxDrvSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int mode, cred_t *pCred, int *pVal);
88
89static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t Cmd);
90static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t Cmd);
91
92static int VBoxSupDrvErr2SolarisErr(int rc);
93static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int Cmd, int Mode, intptr_t pArgs);
94
95
96/*******************************************************************************
97* Global Variables *
98*******************************************************************************/
99/**
100 * cb_ops: for drivers that support char/block entry points
101 */
102static struct cb_ops g_VBoxDrvSolarisCbOps =
103{
104 VBoxDrvSolarisOpen,
105 VBoxDrvSolarisClose,
106 nodev, /* b strategy */
107 nodev, /* b dump */
108 nodev, /* b print */
109 VBoxDrvSolarisRead,
110 VBoxDrvSolarisWrite,
111 VBoxDrvSolarisIOCtl,
112 nodev, /* c devmap */
113 nodev, /* c mmap */
114 nodev, /* c segmap */
115 nochpoll, /* c poll */
116 ddi_prop_op, /* property ops */
117 NULL, /* streamtab */
118 D_NEW | D_MP, /* compat. flag */
119 CB_REV /* revision */
120};
121
122/**
123 * dev_ops: for driver device operations
124 */
125static struct dev_ops g_VBoxDrvSolarisDevOps =
126{
127 DEVO_REV, /* driver build revision */
128 0, /* ref count */
129 nulldev, /* get info */
130 nulldev, /* identify */
131 nulldev, /* probe */
132 VBoxDrvSolarisAttach,
133 VBoxDrvSolarisDetach,
134 nodev, /* reset */
135 &g_VBoxDrvSolarisCbOps,
136 (struct bus_ops *)0,
137 nodev /* power */
138};
139
140/**
141 * modldrv: export driver specifics to the kernel
142 */
143static struct modldrv g_VBoxDrvSolarisModule =
144{
145 &mod_driverops, /* extern from kernel */
146 DEVICE_DESC " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV),
147 &g_VBoxDrvSolarisDevOps
148};
149
150/**
151 * modlinkage: export install/remove/info to the kernel
152 */
153static struct modlinkage g_VBoxDrvSolarisModLinkage =
154{
155 MODREV_1, /* loadable module system revision */
156 {
157 &g_VBoxDrvSolarisModule,
158 NULL /* terminate array of linkage structures */
159 }
160};
161
162#ifndef USE_SESSION_HASH
163/**
164 * State info for each open file handle.
165 */
166typedef struct
167{
168 /**< Pointer to the session data. */
169 PSUPDRVSESSION pSession;
170} vbox_devstate_t;
171#else
172/** State info. for each driver instance. */
173typedef struct
174{
175 dev_info_t *pDip; /* Device handle */
176} vbox_devstate_t;
177#endif
178
179/** Opaque pointer to list of state */
180static void *g_pVBoxDrvSolarisState;
181
182/** Device extention & session data association structure */
183static SUPDRVDEVEXT g_DevExt;
184
185/** Hash table */
186static PSUPDRVSESSION g_apSessionHashTab[19];
187/** Spinlock protecting g_apSessionHashTab. */
188static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
189/** Calculates bucket index into g_apSessionHashTab.*/
190#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
191
192/**
193 * Kernel entry points
194 */
195int _init(void)
196{
197 LogFlowFunc((DEVICE_NAME ":_init\n"));
198
199 /*
200 * Prevent module autounloading.
201 */
202 modctl_t *pModCtl = mod_getctl(&g_VBoxDrvSolarisModLinkage);
203 if (pModCtl)
204 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
205 else
206 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
207
208 /*
209 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
210 */
211 int rc = RTR0Init(0);
212 if (RT_SUCCESS(rc))
213 {
214 /*
215 * Initialize the device extension
216 */
217 rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION));
218 if (RT_SUCCESS(rc))
219 {
220 /*
221 * Initialize the session hash table.
222 */
223 memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab));
224 rc = RTSpinlockCreate(&g_Spinlock);
225 if (RT_SUCCESS(rc))
226 {
227 rc = ddi_soft_state_init(&g_pVBoxDrvSolarisState, sizeof(vbox_devstate_t), 8);
228 if (!rc)
229 {
230 rc = mod_install(&g_VBoxDrvSolarisModLinkage);
231 if (!rc)
232 return rc; /* success */
233
234 ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
235 LogRel((DEVICE_NAME ":mod_install failed! rc=%d\n", rc));
236 }
237 else
238 LogRel((DEVICE_NAME ":failed to initialize soft state.\n"));
239
240 RTSpinlockDestroy(g_Spinlock);
241 g_Spinlock = NIL_RTSPINLOCK;
242 }
243 else
244 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: RTSpinlockCreate failed\n"));
245 supdrvDeleteDevExt(&g_DevExt);
246 }
247 else
248 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: supdrvInitDevExt failed\n"));
249 RTR0TermForced();
250 }
251 else
252 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: failed to init R0Drv\n"));
253 memset(&g_DevExt, 0, sizeof(g_DevExt));
254
255 return RTErrConvertToErrno(rc);
256}
257
258
259int _fini(void)
260{
261 LogFlowFunc((DEVICE_NAME ":_fini\n"));
262
263 /*
264 * Undo the work we did at start (in the reverse order).
265 */
266 int rc = mod_remove(&g_VBoxDrvSolarisModLinkage);
267 if (rc != 0)
268 return rc;
269
270 supdrvDeleteDevExt(&g_DevExt);
271
272 rc = RTSpinlockDestroy(g_Spinlock);
273 AssertRC(rc);
274 g_Spinlock = NIL_RTSPINLOCK;
275
276 RTR0TermForced();
277
278 memset(&g_DevExt, 0, sizeof(g_DevExt));
279
280 ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
281 return 0;
282}
283
284
285int _info(struct modinfo *pModInfo)
286{
287 LogFlowFunc((DEVICE_NAME ":_info\n"));
288 int e = mod_info(&g_VBoxDrvSolarisModLinkage, pModInfo);
289 return e;
290}
291
292
293/**
294 * Attach entry point, to attach a device to the system or resume it.
295 *
296 * @param pDip The module structure instance.
297 * @param enmCmd Operation type (attach/resume).
298 *
299 * @return corresponding solaris error code.
300 */
301static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
302{
303 LogFlowFunc((DEVICE_NAME ":VBoxDrvSolarisAttach\n"));
304
305 switch (enmCmd)
306 {
307 case DDI_ATTACH:
308 {
309 int rc;
310 int instance = ddi_get_instance(pDip);
311#ifdef USE_SESSION_HASH
312 vbox_devstate_t *pState;
313
314 if (ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, instance) != DDI_SUCCESS)
315 {
316 LogRel((DEVICE_NAME ":VBoxDrvSolarisAttach: state alloc failed\n"));
317 return DDI_FAILURE;
318 }
319
320 pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
321#endif
322
323 /*
324 * Register for suspend/resume notifications
325 */
326 rc = ddi_prop_create(DDI_DEV_T_NONE, pDip, DDI_PROP_CANSLEEP /* kmem alloc can sleep */,
327 "pm-hardware-state", "needs-suspend-resume", sizeof("needs-suspend-resume"));
328 if (rc != DDI_PROP_SUCCESS)
329 LogRel((DEVICE_NAME ":Suspend/Resume notification registration failed.\n"));
330
331 /*
332 * Register ourselves as a character device, pseudo-driver
333 */
334#ifdef VBOX_WITH_HARDENING
335 rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO,
336 0, NULL, NULL, 0600);
337#else
338 rc = ddi_create_priv_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO,
339 0, "none", "none", 0666);
340#endif
341 if (rc == DDI_SUCCESS)
342 {
343#ifdef USE_SESSION_HASH
344 pState->pDip = pDip;
345#endif
346 ddi_report_dev(pDip);
347 return DDI_SUCCESS;
348 }
349
350 return DDI_FAILURE;
351 }
352
353 case DDI_RESUME:
354 {
355#if 0
356 RTSemFastMutexRequest(g_DevExt.mtxGip);
357 if (g_DevExt.pGipTimer)
358 RTTimerStart(g_DevExt.pGipTimer, 0);
359
360 RTSemFastMutexRelease(g_DevExt.mtxGip);
361#endif
362 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
363 LogFlow((DEVICE_NAME ": Awakened from suspend.\n"));
364 return DDI_SUCCESS;
365 }
366
367 default:
368 return DDI_FAILURE;
369 }
370
371 return DDI_FAILURE;
372}
373
374
375/**
376 * Detach entry point, to detach a device to the system or suspend it.
377 *
378 * @param pDip The module structure instance.
379 * @param enmCmd Operation type (detach/suspend).
380 *
381 * @return corresponding solaris error code.
382 */
383static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
384{
385 LogFlowFunc((DEVICE_NAME ":VBoxDrvSolarisDetach\n"));
386 switch (enmCmd)
387 {
388 case DDI_DETACH:
389 {
390#ifndef USE_SESSION_HASH
391 ddi_remove_minor_node(pDip, NULL);
392#else
393 int instance = ddi_get_instance(pDip);
394 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
395 ddi_remove_minor_node(pDip, NULL);
396 ddi_soft_state_free(g_pVBoxDrvSolarisState, instance);
397#endif
398 ddi_prop_remove_all(pDip);
399 return DDI_SUCCESS;
400 }
401
402 case DDI_SUSPEND:
403 {
404#if 0
405 RTSemFastMutexRequest(g_DevExt.mtxGip);
406 if (g_DevExt.pGipTimer && g_DevExt.cGipUsers > 0)
407 RTTimerStop(g_DevExt.pGipTimer);
408
409 RTSemFastMutexRelease(g_DevExt.mtxGip);
410#endif
411 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
412 LogFlow((DEVICE_NAME ": Falling to suspend mode.\n"));
413 return DDI_SUCCESS;
414
415 }
416
417 default:
418 return DDI_FAILURE;
419 }
420}
421
422
423
424/**
425 * User context entry points
426 */
427static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
428{
429 int rc;
430 PSUPDRVSESSION pSession;
431 LogFlowFunc((DEVICE_NAME ":VBoxDrvSolarisOpen: pDev=%p:%#x\n", pDev, *pDev));
432
433#ifndef USE_SESSION_HASH
434 /*
435 * Locate a new device open instance.
436 *
437 * For each open call we'll allocate an item in the soft state of the device.
438 * The item index is stored in the dev_t. I hope this is ok...
439 */
440 vbox_devstate_t *pState = NULL;
441 unsigned iOpenInstance;
442 for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
443 {
444 if ( !ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance) /* faster */
445 && ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, iOpenInstance) == DDI_SUCCESS)
446 {
447 pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, iOpenInstance);
448 break;
449 }
450 }
451 if (!pState)
452 {
453 LogRel((DEVICE_NAME ":VBoxDrvSolarisOpen: too many open instances.\n"));
454 return ENXIO;
455 }
456
457 /*
458 * Create a new session.
459 */
460 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
461 if (RT_SUCCESS(rc))
462 {
463 pSession->Uid = crgetruid(pCred);
464 pSession->Gid = crgetrgid(pCred);
465
466 pState->pSession = pSession;
467 *pDev = makedevice(getmajor(*pDev), iOpenInstance);
468 LogFlow((DEVICE_NAME ":VBoxDrvSolarisOpen: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
469 *pDev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
470 return 0;
471 }
472
473 /* failed - clean up */
474 ddi_soft_state_free(g_pVBoxDrvSolarisState, iOpenInstance);
475
476#else
477 /*
478 * Create a new session.
479 * Sessions in Solaris driver are mostly useless. It's however needed
480 * in VBoxDrvSolarisIOCtlSlow() while calling supdrvIOCtl()
481 */
482 rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &pSession);
483 if (RT_SUCCESS(rc))
484 {
485 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
486 unsigned iHash;
487
488 pSession->Uid = crgetruid(pCred);
489 pSession->Gid = crgetrgid(pCred);
490
491 /*
492 * Insert it into the hash table.
493 */
494 iHash = SESSION_HASH(pSession->Process);
495 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
496 pSession->pNextHash = g_apSessionHashTab[iHash];
497 g_apSessionHashTab[iHash] = pSession;
498 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
499 LogFlow((DEVICE_NAME ":VBoxDrvSolarisOpen success\n"));
500 }
501
502 int instance;
503 for (instance = 0; instance < DEVICE_MAXINSTANCES; instance++)
504 {
505 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
506 if (pState)
507 break;
508 }
509
510 if (instance >= DEVICE_MAXINSTANCES)
511 {
512 LogRel((DEVICE_NAME ":VBoxDrvSolarisOpen: All instances exhausted\n"));
513 return ENXIO;
514 }
515
516 *pDev = makedevice(getmajor(*pDev), instance);
517#endif
518
519 return VBoxSupDrvErr2SolarisErr(rc);
520}
521
522
523static int VBoxDrvSolarisClose(dev_t Dev, int flag, int otyp, cred_t *cred)
524{
525 LogFlowFunc((DEVICE_NAME ":VBoxDrvSolarisClose: Dev=%#x\n", Dev));
526
527#ifndef USE_SESSION_HASH
528 /*
529 * Get the session and free the soft state item.
530 */
531 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
532 if (!pState)
533 {
534 LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: no state data for %#x (%d)\n", Dev, getminor(Dev)));
535 return EFAULT;
536 }
537
538 PSUPDRVSESSION pSession = pState->pSession;
539 pState->pSession = NULL;
540 ddi_soft_state_free(g_pVBoxDrvSolarisState, getminor(Dev));
541
542 if (!pSession)
543 {
544 LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
545 return EFAULT;
546 }
547 LogFlow((DEVICE_NAME ":VBoxDrvSolarisClose: Dev=%#x pSession=%p pid=%d r0proc=%p thread=%p\n",
548 Dev, pSession, RTProcSelf(), RTR0ProcHandleSelf(), RTThreadNativeSelf() ));
549
550#else
551 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
552 const RTPROCESS Process = RTProcSelf();
553 const unsigned iHash = SESSION_HASH(Process);
554 PSUPDRVSESSION pSession;
555
556 /*
557 * Remove from the hash table.
558 */
559 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
560 pSession = g_apSessionHashTab[iHash];
561 if (pSession)
562 {
563 if (pSession->Process == Process)
564 {
565 g_apSessionHashTab[iHash] = pSession->pNextHash;
566 pSession->pNextHash = NULL;
567 }
568 else
569 {
570 PSUPDRVSESSION pPrev = pSession;
571 pSession = pSession->pNextHash;
572 while (pSession)
573 {
574 if (pSession->Process == Process)
575 {
576 pPrev->pNextHash = pSession->pNextHash;
577 pSession->pNextHash = NULL;
578 break;
579 }
580
581 /* next */
582 pPrev = pSession;
583 pSession = pSession->pNextHash;
584 }
585 }
586 }
587 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
588 if (!pSession)
589 {
590 LogRel((DEVICE_NAME ":VBoxDrvSolarisClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n",
591 (int)Process));
592 return EFAULT;
593 }
594#endif
595
596 /*
597 * Close the session.
598 */
599 supdrvCloseSession(&g_DevExt, pSession);
600 return 0;
601}
602
603
604static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
605{
606 LogFlowFunc((DEVICE_NAME ":VBoxDrvSolarisRead"));
607 return 0;
608}
609
610
611static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
612{
613 LogFlowFunc((DEVICE_NAME ":VBoxDrvSolarisWrite"));
614 return 0;
615}
616
617
618/**
619 * Driver ioctl, an alternate entry point for this character driver.
620 *
621 * @param Dev Device number
622 * @param Cmd Operation identifier
623 * @param pArg Arguments from user to driver
624 * @param Mode Information bitfield (read/write, address space etc.)
625 * @param pCred User credentials
626 * @param pVal Return value for calling process.
627 *
628 * @return corresponding solaris error code.
629 */
630static int VBoxDrvSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArgs, int Mode, cred_t *pCred, int *pVal)
631{
632#ifndef USE_SESSION_HASH
633 /*
634 * Get the session from the soft state item.
635 */
636 vbox_devstate_t *pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, getminor(Dev));
637 if (!pState)
638 {
639 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtl: no state data for %#x (%d)\n", Dev, getminor(Dev)));
640 return EINVAL;
641 }
642
643 PSUPDRVSESSION pSession = pState->pSession;
644 if (!pSession)
645 {
646 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtl: no session in state data for %#x (%d)\n", Dev, getminor(Dev)));
647 return DDI_SUCCESS;
648 }
649#else
650 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
651 const RTPROCESS Process = RTProcSelf();
652 const unsigned iHash = SESSION_HASH(Process);
653 PSUPDRVSESSION pSession;
654
655 /*
656 * Find the session.
657 */
658 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
659 pSession = g_apSessionHashTab[iHash];
660 if (pSession && pSession->Process != Process)
661 {
662 do pSession = pSession->pNextHash;
663 while (pSession && pSession->Process != Process);
664 }
665 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
666 if (!pSession)
667 {
668 LogRel((DEVICE_NAME ":VBoxSupDrvIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
669 (int)Process, Cmd));
670 return EINVAL;
671 }
672#endif
673
674 /*
675 * Deal with the two high-speed IOCtl that takes it's arguments from
676 * the session and iCmd, and only returns a VBox status code.
677 */
678 if ( Cmd == SUP_IOCTL_FAST_DO_RAW_RUN
679 || Cmd == SUP_IOCTL_FAST_DO_HWACC_RUN
680 || Cmd == SUP_IOCTL_FAST_DO_NOP)
681 {
682 *pVal = supdrvIOCtlFast(Cmd, pArgs, &g_DevExt, pSession);
683 return 0;
684 }
685
686 return VBoxDrvSolarisIOCtlSlow(pSession, Cmd, Mode, pArgs);
687}
688
689
690/** @def IOCPARM_LEN
691 * Gets the length from the ioctl number.
692 * This is normally defined by sys/ioccom.h on BSD systems...
693 */
694#ifndef IOCPARM_LEN
695# define IOCPARM_LEN(x) ( ((x) >> 16) & IOCPARM_MASK )
696#endif
697
698
699/**
700 * Worker for VBoxSupDrvIOCtl that takes the slow IOCtl functions.
701 *
702 * @returns Solaris errno.
703 *
704 * @param pSession The session.
705 * @param Cmd The IOCtl command.
706 * @param Mode Information bitfield (for specifying ownership of data)
707 * @param iArg User space address of the request buffer.
708 */
709static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int iCmd, int Mode, intptr_t iArg)
710{
711 int rc;
712 uint32_t cbBuf = 0;
713 union
714 {
715 SUPREQHDR Hdr;
716 uint8_t abBuf[64];
717 } StackBuf;
718 PSUPREQHDR pHdr;
719
720
721 /*
722 * Read the header.
723 */
724 if (RT_UNLIKELY(IOCPARM_LEN(iCmd) != sizeof(StackBuf.Hdr)))
725 {
726 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: iCmd=%#x len %d expected %d\n", iCmd, IOCPARM_LEN(iCmd), sizeof(StackBuf.Hdr)));
727 return EINVAL;
728 }
729 rc = ddi_copyin((void *)iArg, &StackBuf.Hdr, sizeof(StackBuf.Hdr), Mode);
730 if (RT_UNLIKELY(rc))
731 {
732 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: ddi_copyin(,%#lx,) failed; iCmd=%#x. rc=%d\n", iArg, iCmd, rc));
733 return EFAULT;
734 }
735 if (RT_UNLIKELY((StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
736 {
737 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: bad header magic %#x; iCmd=%#x\n", StackBuf.Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, iCmd));
738 return EINVAL;
739 }
740 cbBuf = RT_MAX(StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut);
741 if (RT_UNLIKELY( StackBuf.Hdr.cbIn < sizeof(StackBuf.Hdr)
742 || StackBuf.Hdr.cbOut < sizeof(StackBuf.Hdr)
743 || cbBuf > _1M*16))
744 {
745 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: max(%#x,%#x); iCmd=%#x\n", StackBuf.Hdr.cbIn, StackBuf.Hdr.cbOut, iCmd));
746 return EINVAL;
747 }
748
749 /*
750 * Buffer the request.
751 */
752 if (cbBuf <= sizeof(StackBuf))
753 pHdr = &StackBuf.Hdr;
754 else
755 {
756 pHdr = RTMemTmpAlloc(cbBuf);
757 if (RT_UNLIKELY(!pHdr))
758 {
759 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: failed to allocate buffer of %d bytes for iCmd=%#x.\n", cbBuf, iCmd));
760 return ENOMEM;
761 }
762 }
763 rc = ddi_copyin((void *)iArg, pHdr, cbBuf, Mode);
764 if (RT_UNLIKELY(rc))
765 {
766 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: copy_from_user(,%#lx, %#x) failed; iCmd=%#x. rc=%d\n", iArg, cbBuf, iCmd, rc));
767 if (pHdr != &StackBuf.Hdr)
768 RTMemFree(pHdr);
769 return EFAULT;
770 }
771
772 /*
773 * Process the IOCtl.
774 */
775 rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
776
777 /*
778 * Copy ioctl data and output buffer back to user space.
779 */
780 if (RT_LIKELY(!rc))
781 {
782 uint32_t cbOut = pHdr->cbOut;
783 if (RT_UNLIKELY(cbOut > cbBuf))
784 {
785 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: too much output! %#x > %#x; iCmd=%#x!\n", cbOut, cbBuf, iCmd));
786 cbOut = cbBuf;
787 }
788 rc = ddi_copyout(pHdr, (void *)iArg, cbOut, Mode);
789 if (RT_UNLIKELY(rc != 0))
790 {
791 /* this is really bad */
792 LogRel((DEVICE_NAME ":VBoxDrvSolarisIOCtlSlow: ddi_copyout(,%p,%d) failed. rc=%d\n", (void *)iArg, cbBuf, rc));
793 rc = EFAULT;
794 }
795 }
796 else
797 rc = EINVAL;
798
799 if (pHdr != &StackBuf.Hdr)
800 RTMemTmpFree(pHdr);
801 return rc;
802}
803
804
805/**
806 * The SUPDRV IDC entry point.
807 *
808 * @returns VBox status code, see supdrvIDC.
809 * @param iReq The request code.
810 * @param pReq The request.
811 */
812int VBOXCALL SUPDrvSolarisIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
813{
814 PSUPDRVSESSION pSession;
815
816 /*
817 * Some quick validations.
818 */
819 if (RT_UNLIKELY(!VALID_PTR(pReq)))
820 return VERR_INVALID_POINTER;
821
822 pSession = pReq->pSession;
823 if (pSession)
824 {
825 if (RT_UNLIKELY(!VALID_PTR(pSession)))
826 return VERR_INVALID_PARAMETER;
827 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
828 return VERR_INVALID_PARAMETER;
829 }
830 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
831 return VERR_INVALID_PARAMETER;
832
833 /*
834 * Do the job.
835 */
836 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
837}
838
839
840/**
841 * Converts an supdrv error code to a solaris error code.
842 *
843 * @returns corresponding solaris error code.
844 * @param rc IPRT status code.
845 */
846static int VBoxSupDrvErr2SolarisErr(int rc)
847{
848 switch (rc)
849 {
850 case VINF_SUCCESS: return 0;
851 case VERR_GENERAL_FAILURE: return EACCES;
852 case VERR_INVALID_PARAMETER: return EINVAL;
853 case VERR_INVALID_MAGIC: return EILSEQ;
854 case VERR_INVALID_HANDLE: return ENXIO;
855 case VERR_INVALID_POINTER: return EFAULT;
856 case VERR_LOCK_FAILED: return ENOLCK;
857 case VERR_ALREADY_LOADED: return EEXIST;
858 case VERR_PERMISSION_DENIED: return EPERM;
859 case VERR_VERSION_MISMATCH: return ENOSYS;
860 }
861
862 return EPERM;
863}
864
865
866/**
867 * Initializes any OS specific object creator fields.
868 */
869void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
870{
871 NOREF(pObj);
872 NOREF(pSession);
873}
874
875
876/**
877 * Checks if the session can access the object.
878 *
879 * @returns true if a decision has been made.
880 * @returns false if the default access policy should be applied.
881 *
882 * @param pObj The object in question.
883 * @param pSession The session wanting to access the object.
884 * @param pszObjName The object name, can be NULL.
885 * @param prc Where to store the result when returning true.
886 */
887bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
888{
889 NOREF(pObj);
890 NOREF(pSession);
891 NOREF(pszObjName);
892 NOREF(prc);
893 return false;
894}
895
896
897bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
898{
899 return false;
900}
901
902#if defined(VBOX_WITH_NATIVE_SOLARIS_LOADING) \
903 && !defined(VBOX_WITHOUT_NATIVE_R0_LOADER)
904
905int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
906{
907 pImage->idSolMod = -1;
908 pImage->pSolModCtl = NULL;
909
910# if 1 /* This approach requires _init/_fini/_info stubs. */
911 /*
912 * Construct a filename that escapes the module search path and let us
913 * specify a root path.
914 */
915 /** @todo change this to use modctl and use_path=0. */
916 const char *pszName = RTPathFilename(pszFilename);
917 AssertReturn(pszName, VERR_INVALID_PARAMETER);
918 char *pszSubDir = RTStrAPrintf2("../../../../../../../../../../..%.*s", pszName - pszFilename - 1, pszFilename);
919 if (!pszSubDir)
920 return VERR_NO_STR_MEMORY;
921 int idMod = modload(pszSubDir, pszName);
922 if (idMod == -1)
923 {
924 /* This is an horrible hack for avoiding the mod-present check in
925 modrload on S10. Fortunately, nobody else seems to be using that
926 variable... */
927 extern int swaploaded;
928 int saved_swaploaded = swaploaded;
929 swaploaded = 0;
930 idMod = modload(pszSubDir, pszName);
931 swaploaded = saved_swaploaded;
932 }
933 RTStrFree(pszSubDir);
934 if (idMod == -1)
935 {
936 LogRel(("modload(,%s): failed, could be anything...\n", pszFilename));
937 return VERR_LDR_GENERAL_FAILURE;
938 }
939
940 modctl_t *pModCtl = mod_hold_by_id(idMod);
941 if (!pModCtl)
942 {
943 LogRel(("mod_hold_by_id(,%s): failed, weird.\n", pszFilename));
944 /* No point in calling modunload. */
945 return VERR_LDR_GENERAL_FAILURE;
946 }
947 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD | MOD_NOUNLOAD; /* paranoia */
948
949# else
950
951 const int idMod = -1;
952 modctl_t *pModCtl = mod_hold_by_name(pszFilename);
953 if (!pModCtl)
954 {
955 LogRel(("mod_hold_by_name failed for '%s'\n", pszFilename));
956 return VERR_LDR_GENERAL_FAILURE;
957 }
958
959 int rc = kobj_load_module(pModCtl, 0 /*use_path*/);
960 if (rc != 0)
961 {
962 LogRel(("kobj_load_module failed with rc=%d for '%s'\n", rc, pszFilename));
963 mod_release_mod(pModCtl);
964 return RTErrConvertFromErrno(rc);
965 }
966# endif
967
968 /*
969 * Get the module info.
970 *
971 * Note! The text section is actually not at mi_base, but and the next
972 * alignment boundrary and there seems to be no easy way of
973 * getting at this address. This sabotages supdrvOSLdrLoad.
974 * Bastards!
975 */
976 struct modinfo ModInfo;
977 kobj_getmodinfo(pModCtl->mod_mp, &ModInfo);
978 pImage->pvImage = ModInfo.mi_base;
979 pImage->idSolMod = idMod;
980 pImage->pSolModCtl = pModCtl;
981
982 mod_release_mod(pImage->pSolModCtl);
983 LogRel(("supdrvOSLdrOpen: succeeded for '%s' (mi_base=%p mi_size=%#x), id=%d ctl=%p\n",
984 pszFilename, ModInfo.mi_base, ModInfo.mi_size, idMod, pModCtl));
985 return VINF_SUCCESS;
986}
987
988
989int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
990{
991 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
992 if (kobj_addrcheck(pImage->pSolModCtl->mod_mp, pv))
993 return VERR_INVALID_PARAMETER;
994 return VINF_SUCCESS;
995}
996
997
998/**
999 * Resolves a module entry point address.
1000 *
1001 * @returns VBox status code.
1002 * @param pImage The image.
1003 * @param pszSymbol The symbol name.
1004 * @param ppvValue Where to store the value. On input this holds
1005 * the symbol value SUPLib calculated.
1006 */
1007static int supdrvSolLdrResolvEp(PSUPDRVLDRIMAGE pImage, const char *pszSymbol, void **ppvValue)
1008{
1009 /* Don't try resolve symbols which, according to SUPLib, aren't there. */
1010 if (!*ppvValue)
1011 return VINF_SUCCESS;
1012
1013 uintptr_t uValue = modlookup_by_modctl(pImage->pSolModCtl, pszSymbol);
1014 if (!uValue)
1015 {
1016 LogRel(("supdrvOSLdrLoad on %s failed to resolve %s\n", pImage->szName, pszSymbol));
1017 return VERR_SYMBOL_NOT_FOUND;
1018 }
1019 *ppvValue = (void *)uValue;
1020 return VINF_SUCCESS;
1021}
1022
1023
1024int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
1025{
1026#if 0 /* This doesn't work because of text alignment. */
1027 /*
1028 * Comparing is very very difficult since text and data may be allocated
1029 * separately.
1030 */
1031 size_t cbCompare = RT_MIN(pImage->cbImageBits, 64);
1032 if (memcmp(pImage->pvImage, pbImageBits, cbCompare))
1033 {
1034 LogRel(("Image mismatch: %s (%p)\n", pImage->szName, pImage->pvImage));
1035 LogRel(("Native: %.*Rhxs\n", cbCompare, pImage->pvImage));
1036 LogRel(("SUPLib: %.*Rhxs\n", cbCompare, pbImageBits));
1037 return VERR_LDR_MISMATCH_NATIVE;
1038 }
1039#endif
1040
1041 /*
1042 * Get the exported symbol addresses.
1043 */
1044 int rc;
1045 modctl_t *pModCtl = mod_hold_by_id(pImage->idSolMod);
1046 if (pModCtl && pModCtl == pImage->pSolModCtl)
1047 {
1048 uint32_t iSym = pImage->cSymbols;
1049 while (iSym-- > 0)
1050 {
1051 const char *pszSymbol = &pImage->pachStrTab[pImage->paSymbols[iSym].offName];
1052 uintptr_t uValue = modlookup_by_modctl(pImage->pSolModCtl, pszSymbol);
1053 if (!uValue)
1054 {
1055 LogRel(("supdrvOSLdrLoad on %s failed to resolve the exported symbol: '%s'\n", pImage->szName, pszSymbol));
1056 break;
1057 }
1058 uintptr_t offSymbol = uValue - (uintptr_t)pImage->pvImage;
1059 pImage->paSymbols[iSym].offSymbol = offSymbol;
1060 if (pImage->paSymbols[iSym].offSymbol != (int32_t)offSymbol)
1061 {
1062 LogRel(("supdrvOSLdrLoad on %s symbol out of range: %p (%s) \n", pImage->szName, offSymbol, pszSymbol));
1063 break;
1064 }
1065 }
1066
1067 rc = iSym == UINT32_MAX ? VINF_SUCCESS : VERR_LDR_GENERAL_FAILURE;
1068
1069 /*
1070 * Get the standard module entry points.
1071 */
1072 if (RT_SUCCESS(rc))
1073 {
1074 rc = supdrvSolLdrResolvEp(pImage, "ModuleInit", (void **)&pImage->pfnModuleInit);
1075 if (RT_SUCCESS(rc))
1076 rc = supdrvSolLdrResolvEp(pImage, "ModuleTerm", (void **)&pImage->pfnModuleTerm);
1077
1078 switch (pReq->u.In.eEPType)
1079 {
1080 case SUPLDRLOADEP_VMMR0:
1081 {
1082 if (RT_SUCCESS(rc))
1083 rc = supdrvSolLdrResolvEp(pImage, "VMMR0EntryInt", (void **)&pReq->u.In.EP.VMMR0.pvVMMR0EntryInt);
1084 if (RT_SUCCESS(rc))
1085 rc = supdrvSolLdrResolvEp(pImage, "VMMR0EntryFast", (void **)&pReq->u.In.EP.VMMR0.pvVMMR0EntryFast);
1086 if (RT_SUCCESS(rc))
1087 rc = supdrvSolLdrResolvEp(pImage, "VMMR0EntryEx", (void **)&pReq->u.In.EP.VMMR0.pvVMMR0EntryEx);
1088 break;
1089 }
1090
1091 case SUPLDRLOADEP_SERVICE:
1092 {
1093 /** @todo we need the name of the entry point. */
1094 return VERR_NOT_SUPPORTED;
1095 }
1096 }
1097 }
1098
1099 mod_release_mod(pImage->pSolModCtl);
1100 }
1101 else
1102 {
1103 LogRel(("mod_hold_by_id failed in supdrvOSLdrLoad on %s: %p\n", pImage->szName, pModCtl));
1104 rc = VERR_LDR_MISMATCH_NATIVE;
1105 }
1106 return rc;
1107}
1108
1109
1110void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1111{
1112# if 1
1113 pImage->pSolModCtl->mod_loadflags &= ~MOD_NOUNLOAD;
1114 int rc = modunload(pImage->idSolMod);
1115 if (rc)
1116 LogRel(("modunload(%u (%s)) failed: %d\n", pImage->idSolMod, pImage->szName, rc));
1117# else
1118 kobj_unload_module(pImage->pSolModCtl);
1119# endif
1120 pImage->pSolModCtl = NULL;
1121 pImage->idSolMod = NULL;
1122}
1123
1124#else /* !VBOX_WITH_NATIVE_SOLARIS_LOADING */
1125
1126int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1127{
1128 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
1129 return VERR_NOT_SUPPORTED;
1130}
1131
1132
1133int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
1134{
1135 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
1136 return VERR_NOT_SUPPORTED;
1137}
1138
1139
1140int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
1141{
1142 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
1143 return VERR_NOT_SUPPORTED;
1144}
1145
1146
1147void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1148{
1149 NOREF(pDevExt); NOREF(pImage);
1150}
1151
1152#endif /* !VBOX_WITH_NATIVE_SOLARIS_LOADING */
1153
1154
1155RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
1156{
1157 va_list args;
1158 char szMsg[512];
1159
1160 va_start(args, pszFormat);
1161 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, args);
1162 va_end(args);
1163
1164 szMsg[sizeof(szMsg) - 1] = '\0';
1165 cmn_err(CE_CONT, "%s", szMsg);
1166 return 0;
1167}
1168
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