VirtualBox

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

Last change on this file since 41160 was 41067, checked in by vboxsync, 13 years ago

supdrvOSLdrNotifyOpened so we can record the load address in NVRAM if we choose to.

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