VirtualBox

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

Last change on this file since 67981 was 62490, checked in by vboxsync, 8 years ago

(C) 2016

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

© 2023 Oracle
ContactPrivacy policyTerms of Use