VirtualBox

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

Last change on this file since 4824 was 4824, checked in by vboxsync, 18 years ago

stricter checks.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 20.2 KB
Line 
1/** @file
2 * VBox host drivers - Ring-0 support drivers - Solaris host:
3 * Solaris driver C code
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <sys/types.h>
23#include <sys/param.h>
24#include <sys/errno.h>
25#include <sys/uio.h>
26#include <sys/buf.h>
27#include <sys/modctl.h>
28#include <sys/open.h>
29#include <sys/conf.h>
30#include <sys/cmn_err.h>
31#include <sys/stat.h>
32#include <sys/ddi.h>
33#include <sys/sunddi.h>
34#include <sys/file.h>
35#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
36
37#include "SUPDRV.h"
38#include <iprt/spinlock.h>
39#include <iprt/process.h>
40#include <iprt/initterm.h>
41#include <iprt/alloc.h>
42
43
44/*******************************************************************************
45* Defined Constants And Macros *
46*******************************************************************************/
47/** The module name. */
48#define DEVICE_NAME "vboxdrv"
49/** The module description as seen in 'modinfo'. */
50#define DEVICE_DESC "VirtualBox Driver"
51/** Maximum number of driver instances. */
52#define DEVICE_MAXINSTANCES 16
53
54
55/*******************************************************************************
56* Internal Functions *
57*******************************************************************************/
58static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
59static int VBoxDrvSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
60static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
61static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
62static int VBoxDrvSolarisIOCtl (dev_t Dev, int Cmd, intptr_t pArgs, int mode, cred_t *pCred, int *pVal);
63
64static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t Cmd);
65static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t Cmd);
66
67static int VBoxSupDrvErr2SolarisErr(int rc);
68static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int Cmd, int Mode, intptr_t pArgs);
69
70
71/*******************************************************************************
72* Global Variables *
73*******************************************************************************/
74/**
75 * cb_ops: for drivers that support char/block entry points
76 */
77static struct cb_ops g_VBoxDrvSolarisCbOps =
78{
79 VBoxDrvSolarisOpen,
80 VBoxDrvSolarisClose,
81 nodev, /* b strategy */
82 nodev, /* b dump */
83 nodev, /* b print */
84 VBoxDrvSolarisRead,
85 VBoxDrvSolarisWrite,
86 VBoxDrvSolarisIOCtl,
87 nodev, /* c devmap */
88 nodev, /* c mmap */
89 nodev, /* c segmap */
90 nochpoll, /* c poll */
91 ddi_prop_op, /* property ops */
92 NULL, /* streamtab */
93 D_NEW | D_MP, /* compat. flag */
94 CB_REV /* revision */
95};
96
97/**
98 * dev_ops: for driver device operations
99 */
100static struct dev_ops g_VBoxDrvSolarisDevOps =
101{
102 DEVO_REV, /* driver build revision */
103 0, /* ref count */
104 nulldev, /* get info */
105 nulldev, /* identify */
106 nulldev, /* probe */
107 VBoxDrvSolarisAttach,
108 VBoxDrvSolarisDetach,
109 nodev, /* reset */
110 &g_VBoxDrvSolarisCbOps,
111 (struct bus_ops *)0,
112 nodev /* power */
113};
114
115/**
116 * modldrv: export driver specifics to the kernel
117 */
118static struct modldrv g_VBoxDrvSolarisModule =
119{
120 &mod_driverops, /* extern from kernel */
121 DEVICE_DESC,
122 &g_VBoxDrvSolarisDevOps
123};
124
125/**
126 * modlinkage: export install/remove/info to the kernel
127 */
128static struct modlinkage g_VBoxDrvSolarisModLinkage =
129{
130 MODREV_1, /* loadable module system revision */
131 &g_VBoxDrvSolarisModule,
132 NULL /* terminate array of linkage structures */
133};
134
135/** State info. for each driver instance. */
136typedef struct
137{
138 dev_info_t *pDip; /* Device handle */
139} vbox_devstate_t;
140
141/** Opaque pointer to state */
142static void *g_pVBoxDrvSolarisState;
143
144/** Device extention & session data association structure */
145static SUPDRVDEVEXT g_DevExt;
146
147/* GCC C++ hack. */
148unsigned __gxx_personality_v0 = 0xcccccccc;
149
150/** Hash table */
151static PSUPDRVSESSION g_apSessionHashTab[19];
152/** Spinlock protecting g_apSessionHashTab. */
153static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
154/** Calculates bucket index into g_apSessionHashTab.*/
155#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
156
157/**
158 * Kernel entry points
159 */
160int _init (void)
161{
162 cmn_err(CE_CONT, "VBoxDrvSolaris _init");
163
164 int e = ddi_soft_state_init(&g_pVBoxDrvSolarisState, sizeof (vbox_devstate_t), 1);
165 if (e != 0)
166 return e;
167
168 e = mod_install(&g_VBoxDrvSolarisModLinkage);
169 if (e != 0)
170 ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
171
172 return e;
173}
174
175int _fini (void)
176{
177 cmn_err(CE_CONT, "VBoxDrvSolaris _fini");
178
179 int e = mod_remove(&g_VBoxDrvSolarisModLinkage);
180 if (e != 0)
181 return e;
182
183 ddi_soft_state_fini(&g_pVBoxDrvSolarisState);
184 return e;
185}
186
187int _info (struct modinfo *pModInfo)
188{
189 cmn_err(CE_CONT, "VBoxDrvSolaris _info");
190 return mod_info (&g_VBoxDrvSolarisModLinkage, pModInfo);
191}
192
193/**
194 * User context entry points
195 */
196static int VBoxDrvSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
197{
198 cmn_err(CE_CONT, "VBoxDrvSolarisOpen");
199
200 int rc;
201 PSUPDRVSESSION pSession;
202
203 /*
204 * Create a new session.
205 * Sessions in Solaris driver are mostly useless. It's however needed
206 * in VBoxDrvSolarisIOCtlSlow() while calling supdrvIOCtl()
207 */
208 rc = supdrvCreateSession(&g_DevExt, &pSession);
209 if (RT_SUCCESS(rc))
210 {
211 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
212 unsigned iHash;
213
214 pSession->Uid = crgetuid(pCred);
215 pSession->Gid = crgetgid(pCred);
216 pSession->Process = RTProcSelf();
217 pSession->R0Process = RTR0ProcHandleSelf();
218
219 /*
220 * Insert it into the hash table.
221 */
222 iHash = SESSION_HASH(pSession->Process);
223 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
224 pSession->pNextHash = g_apSessionHashTab[iHash];
225 g_apSessionHashTab[iHash] = pSession;
226 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
227 cmn_err(CE_NOTE,"VBoxDrvSolarisOpen success");
228 }
229
230 int instance;
231 for (instance = 0; instance < DEVICE_MAXINSTANCES; instance++)
232 {
233 vbox_devstate_t *pState = ddi_get_soft_state (g_pVBoxDrvSolarisState, instance);
234 if (pState)
235 break;
236 }
237
238 if (instance >= DEVICE_MAXINSTANCES)
239 {
240 cmn_err(CE_NOTE, "VBoxDrvSolarisOpen: All instances exhausted\n");
241 return ENXIO;
242 }
243
244 *pDev = makedevice(getmajor(*pDev), instance);
245
246 return VBoxSupDrvErr2SolarisErr(rc);
247}
248
249static int VBoxDrvSolarisClose(dev_t pDev, int flag, int otyp, cred_t *cred)
250{
251 cmn_err(CE_CONT, "VBoxDrvSolarisClose");
252
253 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
254 const RTPROCESS Process = RTProcSelf();
255 const unsigned iHash = SESSION_HASH(Process);
256 PSUPDRVSESSION pSession;
257
258 /*
259 * Remove from the hash table.
260 */
261 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
262 pSession = g_apSessionHashTab[iHash];
263 if (pSession)
264 {
265 if (pSession->Process == Process)
266 {
267 g_apSessionHashTab[iHash] = pSession->pNextHash;
268 pSession->pNextHash = NULL;
269 }
270 else
271 {
272 PSUPDRVSESSION pPrev = pSession;
273 pSession = pSession->pNextHash;
274 while (pSession)
275 {
276 if (pSession->Process == Process)
277 {
278 pPrev->pNextHash = pSession->pNextHash;
279 pSession->pNextHash = NULL;
280 break;
281 }
282
283 /* next */
284 pPrev = pSession;
285 pSession = pSession->pNextHash;
286 }
287 }
288 }
289 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
290 if (!pSession)
291 {
292 OSDBGPRINT(("VBoxDrvSolarisClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n",
293 (int)Process));
294 return DDI_FAILURE;
295 }
296
297 /*
298 * Close the session.
299 */
300 supdrvCloseSession(&g_DevExt, pSession);
301 return DDI_SUCCESS;
302}
303
304static int VBoxDrvSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
305{
306 cmn_err(CE_CONT, "VBoxDrvSolarisRead");
307 return DDI_SUCCESS;
308}
309
310static int VBoxDrvSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
311{
312 cmn_err(CE_CONT, "VBoxDrvSolarisWrite");
313 return DDI_SUCCESS;
314}
315
316/**
317 * Attach entry point, to attach a device to the system or resume it.
318 *
319 * @param pDip The module structure instance.
320 * @param enmCmd Attach type (ddi_attach_cmd_t)
321 *
322 * @return corresponding solaris error code.
323 */
324static int VBoxDrvSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
325{
326 cmn_err(CE_CONT, "VBoxDrvSolarisAttach");
327 int rc = VINF_SUCCESS;
328 int instance = 0;
329 vbox_devstate_t *pState;
330
331 switch (enmCmd)
332 {
333 case DDI_ATTACH:
334 {
335 instance = ddi_get_instance (pDip);
336
337 if (ddi_soft_state_zalloc(g_pVBoxDrvSolarisState, instance) != DDI_SUCCESS)
338 {
339 cmn_err(CE_NOTE, "VBoxDrvSolarisAttach: state alloc failed");
340 return DDI_FAILURE;
341 }
342
343 pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
344
345 /*
346 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
347 */
348 rc = RTR0Init(0);
349 if (RT_SUCCESS(rc))
350 {
351 /*
352 * Initialize the device extension
353 */
354 rc = supdrvInitDevExt(&g_DevExt);
355 if (RT_SUCCESS(rc))
356 {
357 /*
358 * Initialize the session hash table.
359 */
360 memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab));
361 rc = RTSpinlockCreate(&g_Spinlock);
362 if (RT_SUCCESS(rc))
363 {
364 /*
365 * Register ourselves as a character device, pseudo-driver
366 */
367 if (ddi_create_minor_node(pDip, "0", S_IFCHR,
368 instance, DDI_PSEUDO, 0) == DDI_SUCCESS)
369 {
370 pState->pDip = pDip;
371 ddi_report_dev(pDip);
372 return DDI_SUCCESS;
373 }
374
375 /* Is this really necessary? */
376 ddi_remove_minor_node(pDip, NULL);
377 cmn_err(CE_NOTE,"VBoxDrvSolarisAttach: ddi_create_minor_node failed.");
378
379 RTSpinlockDestroy(g_Spinlock);
380 g_Spinlock = NIL_RTSPINLOCK;
381 }
382 else
383 cmn_err(CE_NOTE, "VBoxDrvSolarisAttach: RTSpinlockCreate failed");
384 supdrvDeleteDevExt(&g_DevExt);
385 }
386 else
387 cmn_err(CE_NOTE, "VBoxDrvSolarisAttach: supdrvInitDevExt failed");
388 RTR0Term ();
389 }
390 else
391 cmn_err(CE_NOTE, "VBoxDrvSolarisAttach: failed to init R0Drv");
392 memset(&g_DevExt, 0, sizeof(g_DevExt));
393 break;
394 }
395
396 default:
397 return DDI_FAILURE;
398 }
399
400 return DDI_FAILURE;
401}
402
403/**
404 * Detach entry point, to detach a device to the system or suspend it.
405 *
406 * @param pDip The module structure instance.
407 * @param enmCmd Attach type (ddi_attach_cmd_t)
408 *
409 * @return corresponding solaris error code.
410 */
411static int VBoxDrvSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
412{
413 int rc = VINF_SUCCESS;
414 int instance;
415 register vbox_devstate_t *pState;
416
417 cmn_err(CE_CONT, "VBoxDrvSolarisDetach");
418 switch (enmCmd)
419 {
420 case DDI_DETACH:
421 {
422 instance = ddi_get_instance(pDip);
423 pState = ddi_get_soft_state(g_pVBoxDrvSolarisState, instance);
424
425 ddi_remove_minor_node(pDip, NULL);
426 ddi_soft_state_free(g_pVBoxDrvSolarisState, instance);
427
428 supdrvDeleteDevExt(&g_DevExt);
429
430 rc = RTSpinlockDestroy(g_Spinlock);
431 AssertRC(rc);
432 g_Spinlock = NIL_RTSPINLOCK;
433
434 RTR0Term();
435
436 memset(&g_DevExt, 0, sizeof(g_DevExt));
437 cmn_err(CE_CONT, "VBoxDrvSolarisDetach: Clean Up Done.");
438 return DDI_SUCCESS;
439 }
440
441 default:
442 return DDI_FAILURE;
443 }
444}
445
446/**
447 * Driver ioctl, an alternate entry point for this character driver.
448 *
449 * @param Dev Device number
450 * @param Cmd Operation identifier
451 * @param pArg Arguments from user to driver
452 * @param Mode Information bitfield (read/write, address space etc.)
453 * @param pCred User credentials
454 * @param pVal Return value for calling process.
455 *
456 * @return corresponding solaris error code.
457 */
458static int VBoxDrvSolarisIOCtl (dev_t Dev, int Cmd, intptr_t pArgs, int Mode, cred_t* pCred, int* pVal)
459{
460 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
461 const RTPROCESS Process = RTProcSelf();
462 const unsigned iHash = SESSION_HASH(Process);
463 PSUPDRVSESSION pSession;
464
465 cmn_err(CE_CONT, "VBoxDrvSolarisIOCtl\n");
466 /*
467 * Find the session.
468 */
469 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
470 pSession = g_apSessionHashTab[iHash];
471 if (pSession && pSession->Process != Process)
472 {
473 do pSession = pSession->pNextHash;
474 while (pSession && pSession->Process != Process);
475 }
476 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
477 if (!pSession)
478 {
479 OSDBGPRINT(("VBoxSupDrvIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
480 (int)Process, Cmd));
481 return EINVAL;
482 }
483
484 /*
485 * Deal with the two high-speed IOCtl that takes it's arguments from
486 * the session and iCmd, and only returns a VBox status code.
487 */
488 if ( Cmd == SUP_IOCTL_FAST_DO_RAW_RUN
489 || Cmd == SUP_IOCTL_FAST_DO_HWACC_RUN
490 || Cmd == SUP_IOCTL_FAST_DO_NOP)
491 return supdrvIOCtlFast(Cmd, &g_DevExt, pSession);
492
493 return VBoxDrvSolarisIOCtlSlow(pSession, Cmd, Mode, pArgs);
494}
495
496
497/** @def IOCPARM_LEN
498 * Gets the length from the ioctl number.
499 * This is normally defined by sys/ioccom.h on BSD systems...
500 */
501#ifndef IOCPARM_LEN
502# define IOCPARM_LEN(x) ( ((x) >> 16) & IOCPARM_MASK )
503#endif
504
505
506/**
507 * Worker for VBoxSupDrvIOCtl that takes the slow IOCtl functions.
508 *
509 * @returns Solaris errno.
510 *
511 * @param pSession The session.
512 * @param Cmd The IOCtl command.
513 * @param Mode Information bitfield (for specifying ownership of data)
514 * @param iArg User space address of the request buffer.
515 */
516static int VBoxDrvSolarisIOCtlSlow(PSUPDRVSESSION pSession, int iCmd, int Mode, intptr_t iArg)
517{
518 int rc;
519 uint32_t cbBuf = 0;
520 SUPREQHDR Hdr;
521 PSUPREQHDR pHdr;
522
523
524 /*
525 * Read the header.
526 */
527 if (RT_UNLIKELY(IOC_PARMLEN(iCmd) != sizeof(Hdr)))
528 {
529 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: iCmd=%#x len %d expected %d\n", iCmd, IOC_PARMLEN(iCmd), sizeof(Hdr)));
530 return EINVAL;
531 }
532 rc = ddi_copyin(&Hdr, (void *)iArg, sizeof(Hdr), Mode);
533 if (RT_UNLIKELY(rc))
534 {
535 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: ddi_copyin(,%#lx,) failed; iCmd=%#x. rc=%d\n", iArg, iCmd, rc));
536 return EFAULT;
537 }
538 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
539 {
540 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: bad header magic %#x; iCmd=%#x\n", Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK, iCmd));
541 return EINVAL;
542 }
543 cbBuf = RT_MAX(Hdr.cbIn, Hdr.cbOut);
544 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
545 || Hdr.cbOut < sizeof(Hdr)
546 || cbReq > _1M*16))
547 {
548 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: max(%#x,%#x); iCmd=%#x\n", Hdr.cbIn, Hdr.cbOut, iCmd));
549 return EINVAL;
550 }
551
552 /*
553 * Buffer the request.
554 */
555 pHdr = RTMemTmpAlloc(cbBuf);
556 if (RT_UNLIKELY(!pHdr))
557 {
558 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: failed to allocate buffer of %d bytes for iCmd=%#x.\n", cbBuf, iCmd));
559 return ENOMEM;
560 }
561 rc = ddi_copyin(pHdr, (void *)iArg, cbBuf, Mode);
562 if (RT_UNLIKELY(rc))
563 {
564 dprintf(("VBoxDrvSolarisIOCtlSlow: copy_from_user(,%#lx, %#x) failed; iCmd=%#x. rc=%d\n", iArg, Hdr.cbIn, iCmd, rc));
565 RTMemFree(pHdr);
566 return EFAULT;
567 }
568
569 /*
570 * Process the IOCtl.
571 */
572 rc = supdrvIOCtl(Cmd, &g_DevExt, pSession, pHdr);
573
574 /*
575 * Copy ioctl data and output buffer back to user space.
576 */
577 if (RT_LIKELY(!rc))
578 {
579 uint32_t cbOut = pHdr->cbOut;
580 if (RT_UNLIKELY(cbOut > cbBuf))
581 {
582 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: too much output! %#x > %#x; iCmd=%#x!\n", cbOut, cbBuf, iCmd));
583 cbOut = cbBuf;
584 }
585 rc = ddi_copyout(pHdr, (void *)iArg, cbOut, Mode);
586 if (RT_UNLIKELY(rc != 0))
587 {
588 /* this is really bad */
589 OSDBGPRINT(("VBoxDrvSolarisIOCtlSlow: ddi_copyout(,%p,%d) failed. rc=%d\n", (void *)iArg, cbBuf, rc));
590 rc = EFAULT;
591 }
592 }
593 else
594 rc = EINVAL;
595
596 RTMemTmpFree(pHdr);
597 return rc;
598}
599
600
601/**
602 * Converts an supdrv error code to a solaris error code.
603 *
604 * @returns corresponding solaris error code.
605 * @param rc supdrv error code (SUPDRV_ERR_* defines).
606 */
607static int VBoxSupDrvErr2SolarisErr(int rc)
608{
609 switch (rc)
610 {
611 case 0: return 0;
612 case SUPDRV_ERR_GENERAL_FAILURE: return EACCES;
613 case SUPDRV_ERR_INVALID_PARAM: return EINVAL;
614 case SUPDRV_ERR_INVALID_MAGIC: return EILSEQ;
615 case SUPDRV_ERR_INVALID_HANDLE: return ENXIO;
616 case SUPDRV_ERR_INVALID_POINTER: return EFAULT;
617 case SUPDRV_ERR_LOCK_FAILED: return ENOLCK;
618 case SUPDRV_ERR_ALREADY_LOADED: return EEXIST;
619 case SUPDRV_ERR_PERMISSION_DENIED: return EPERM;
620 case SUPDRV_ERR_VERSION_MISMATCH: return ENOSYS;
621 }
622
623 return EPERM;
624}
625
626/**
627 * Initializes any OS specific object creator fields.
628 */
629void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
630{
631 NOREF(pObj);
632 NOREF(pSession);
633}
634
635
636/**
637 * Checks if the session can access the object.
638 *
639 * @returns true if a decision has been made.
640 * @returns false if the default access policy should be applied.
641 *
642 * @param pObj The object in question.
643 * @param pSession The session wanting to access the object.
644 * @param pszObjName The object name, can be NULL.
645 * @param prc Where to store the result when returning true.
646 */
647bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
648{
649 NOREF(pObj);
650 NOREF(pSession);
651 NOREF(pszObjName);
652 NOREF(prc);
653 return false;
654}
655
656
657RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
658{
659 va_list args;
660 char szMsg[512];
661
662 va_start(args, pszFormat);
663 vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
664 va_end(args);
665
666 szMsg[sizeof(szMsg) - 1] = '\0';
667 uprintf("%s", szMsg);
668 return 0;
669}
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