VirtualBox

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

Last change on this file since 49634 was 49634, checked in by vboxsync, 11 years ago

SUPDrv: Added an interface for probing MSRs.

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