VirtualBox

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

Last change on this file since 57046 was 56293, checked in by vboxsync, 10 years ago

HostDrivers: Updated (C) year.

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