VirtualBox

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

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

Support,VBoxNet[Flt|Adp]/solaris: Fix S10 regression with trunk, ddi_quiesce_not_needed missing.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette