VirtualBox

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

Last change on this file since 38876 was 37280, checked in by vboxsync, 14 years ago

SUPDrv-solaris.c: ugly module loading hack for S10

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