VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/freebsd/SUPDrv-freebsd.c@ 57358

最後變更 在這個檔案從57358是 57358,由 vboxsync 提交於 10 年 前

*: scm cleanup run.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 17.9 KB
 
1/* $Id: SUPDrv-freebsd.c 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - FreeBSD specifics.
4 */
5
6/*
7 * Copyright (c) 2007 knut st. osmundsen <[email protected]>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#define LOG_GROUP LOG_GROUP_SUP_DRV
36/* Deal with conflicts first. */
37#include <sys/param.h>
38#undef PVM
39#include <sys/types.h>
40#include <sys/module.h>
41#include <sys/systm.h>
42#include <sys/errno.h>
43#include <sys/kernel.h>
44#include <sys/fcntl.h>
45#include <sys/conf.h>
46#include <sys/uio.h>
47
48#include "../SUPDrvInternal.h"
49#include <VBox/version.h>
50#include <iprt/initterm.h>
51#include <iprt/string.h>
52#include <iprt/spinlock.h>
53#include <iprt/process.h>
54#include <iprt/assert.h>
55#include <iprt/uuid.h>
56#include <VBox/log.h>
57#include <iprt/alloc.h>
58#include <iprt/err.h>
59#include <iprt/asm.h>
60
61#ifdef VBOX_WITH_HARDENING
62# define VBOXDRV_PERM 0600
63#else
64# define VBOXDRV_PERM 0666
65#endif
66
67
68/*********************************************************************************************************************************
69* Internal Functions *
70*********************************************************************************************************************************/
71static int VBoxDrvFreeBSDModuleEvent(struct module *pMod, int enmEventType, void *pvArg);
72static int VBoxDrvFreeBSDLoad(void);
73static int VBoxDrvFreeBSDUnload(void);
74
75static d_open_t VBoxDrvFreeBSDOpenUsr;
76static d_open_t VBoxDrvFreeBSDOpenSys;
77static void VBoxDrvFreeBSDDtr(void *pData);
78static d_ioctl_t VBoxDrvFreeBSDIOCtl;
79static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd);
80
81
82/*********************************************************************************************************************************
83* Global Variables *
84*********************************************************************************************************************************/
85/**
86 * Module info structure used by the kernel.
87 */
88static moduledata_t g_VBoxDrvFreeBSDModule =
89{
90 "vboxdrv",
91 VBoxDrvFreeBSDModuleEvent,
92 NULL
93};
94
95/** Declare the module as a pseudo device. */
96DECLARE_MODULE(vboxdrv, g_VBoxDrvFreeBSDModule, SI_SUB_PSEUDO, SI_ORDER_ANY);
97MODULE_VERSION(vboxdrv, 1);
98
99/**
100 * The /dev/vboxdrv character device entry points.
101 */
102static struct cdevsw g_VBoxDrvFreeBSDChrDevSwSys =
103{
104 .d_version = D_VERSION,
105 .d_open = VBoxDrvFreeBSDOpenSys,
106 .d_ioctl = VBoxDrvFreeBSDIOCtl,
107 .d_name = "vboxdrv"
108};
109/** The /dev/vboxdrv character device. */
110static struct cdev *g_pVBoxDrvFreeBSDChrDevSys;
111
112/**
113 * The /dev/vboxdrvu character device entry points.
114 */
115static struct cdevsw g_VBoxDrvFreeBSDChrDevSwUsr =
116{
117 .d_version = D_VERSION,
118 .d_open = VBoxDrvFreeBSDOpenUsr,
119 .d_ioctl = VBoxDrvFreeBSDIOCtl,
120 .d_name = "vboxdrvu"
121};
122/** The /dev/vboxdrvu character device. */
123static struct cdev *g_pVBoxDrvFreeBSDChrDevUsr;
124
125/** Reference counter. */
126static volatile uint32_t g_cUsers;
127
128/** The device extention. */
129static SUPDRVDEVEXT g_VBoxDrvFreeBSDDevExt;
130
131/**
132 * Module event handler.
133 *
134 * @param pMod The module structure.
135 * @param enmEventType The event type (modeventtype_t).
136 * @param pvArg Module argument. NULL.
137 *
138 * @return 0 on success, errno.h status code on failure.
139 */
140static int VBoxDrvFreeBSDModuleEvent(struct module *pMod, int enmEventType, void *pvArg)
141{
142 int rc;
143 switch (enmEventType)
144 {
145 case MOD_LOAD:
146 rc = VBoxDrvFreeBSDLoad();
147 break;
148
149 case MOD_UNLOAD:
150 mtx_unlock(&Giant);
151 rc = VBoxDrvFreeBSDUnload();
152 mtx_lock(&Giant);
153 break;
154
155 case MOD_SHUTDOWN:
156 case MOD_QUIESCE:
157 default:
158 return EOPNOTSUPP;
159 }
160
161 if (RT_SUCCESS(rc))
162 return 0;
163 return RTErrConvertToErrno(rc);
164}
165
166
167static int VBoxDrvFreeBSDLoad(void)
168{
169 g_cUsers = 0;
170
171 /*
172 * Initialize the runtime.
173 */
174 int rc = RTR0Init(0);
175 if (RT_SUCCESS(rc))
176 {
177 Log(("VBoxDrvFreeBSDLoad:\n"));
178
179 /*
180 * Initialize the device extension.
181 */
182 rc = supdrvInitDevExt(&g_VBoxDrvFreeBSDDevExt, sizeof(SUPDRVSESSION));
183 if (RT_SUCCESS(rc))
184 {
185 /*
186 * Configure character devices. Add symbolic links for compatibility.
187 */
188 g_pVBoxDrvFreeBSDChrDevSys = make_dev(&g_VBoxDrvFreeBSDChrDevSwSys, 0, UID_ROOT, GID_WHEEL, VBOXDRV_PERM, "vboxdrv");
189 g_pVBoxDrvFreeBSDChrDevUsr = make_dev(&g_VBoxDrvFreeBSDChrDevSwUsr, 1, UID_ROOT, GID_WHEEL, 0666, "vboxdrvu");
190 return VINF_SUCCESS;
191 }
192
193 printf("vboxdrv: supdrvInitDevExt failed, rc=%d\n", rc);
194 RTR0Term();
195 }
196 else
197 printf("vboxdrv: RTR0Init failed, rc=%d\n", rc);
198 return rc;
199}
200
201static int VBoxDrvFreeBSDUnload(void)
202{
203 Log(("VBoxDrvFreeBSDUnload:\n"));
204
205 if (g_cUsers > 0)
206 return VERR_RESOURCE_BUSY;
207
208 /*
209 * Reserve what we did in VBoxDrvFreeBSDInit.
210 */
211 destroy_dev(g_pVBoxDrvFreeBSDChrDevUsr);
212 destroy_dev(g_pVBoxDrvFreeBSDChrDevSys);
213
214 supdrvDeleteDevExt(&g_VBoxDrvFreeBSDDevExt);
215
216 RTR0TermForced();
217
218 memset(&g_VBoxDrvFreeBSDDevExt, 0, sizeof(g_VBoxDrvFreeBSDDevExt));
219 return VINF_SUCCESS;
220}
221
222
223/**
224 *
225 * @returns 0 on success, errno on failure.
226 * EBUSY if the device is used by someone else.
227 * @param pDev The device node.
228 * @param fOpen The open flags.
229 * @param pTd The thread.
230 * @param iDevType ???
231 */
232static int vboxdrvFreeBSDOpenCommon(struct cdev *pDev, int fOpen, int iDevtype, struct thread *pTd, bool fUnrestricted)
233{
234 PSUPDRVSESSION pSession;
235 int rc;
236
237 /*
238 * Let's be a bit picky about the flags...
239 */
240 if (fOpen != (FREAD | FWRITE /*=O_RDWR*/))
241 {
242 Log(("VBoxDrvFreeBSDOpen: fOpen=%#x expected %#x\n", fOpen, O_RDWR));
243 return EINVAL;
244 }
245
246 /*
247 * Create a new session.
248 */
249 rc = supdrvCreateSession(&g_VBoxDrvFreeBSDDevExt, true /* fUser */, fUnrestricted, &pSession);
250 if (RT_SUCCESS(rc))
251 {
252 /** @todo get (r)uid and (r)gid.
253 pSession->Uid = stuff;
254 pSession->Gid = stuff; */
255 devfs_set_cdevpriv(pSession, VBoxDrvFreeBSDDtr);
256 Log(("VBoxDrvFreeBSDOpen: pSession=%p\n", pSession));
257 ASMAtomicIncU32(&g_cUsers);
258 return 0;
259 }
260
261 return RTErrConvertToErrno(rc);
262}
263
264
265/** For vboxdrv. */
266static int VBoxDrvFreeBSDOpenSys(struct cdev *pDev, int fOpen, int iDevtype, struct thread *pTd)
267{
268 return vboxdrvFreeBSDOpenCommon(pDev, fOpen, iDevtype, pTd, true);
269}
270
271
272/** For vboxdrvu. */
273static int VBoxDrvFreeBSDOpenUsr(struct cdev *pDev, int fOpen, int iDevtype, struct thread *pTd)
274{
275 return vboxdrvFreeBSDOpenCommon(pDev, fOpen, iDevtype, pTd, false);
276}
277
278
279/**
280 * Close a file device previously opened by VBoxDrvFreeBSDOpen
281 *
282 * @returns 0 on success.
283 * @param pDev The device.
284 * @param fFile The file descriptor flags.
285 * @param DevType The device type (CHR.
286 * @param pTd The calling thread.
287 */
288static void VBoxDrvFreeBSDDtr(void *pData)
289{
290 PSUPDRVSESSION pSession = pData;
291 Log(("VBoxDrvFreeBSDDtr: pSession=%p\n", pSession));
292
293 /*
294 * Close the session.
295 */
296 supdrvSessionRelease(pSession);
297 ASMAtomicDecU32(&g_cUsers);
298}
299
300
301/**
302 * I/O control request.
303 *
304 * @returns depends...
305 * @param pDev The device.
306 * @param ulCmd The command.
307 * @param pvData Pointer to the data.
308 * @param fFile The file descriptor flags.
309 * @param pTd The calling thread.
310 */
311static int VBoxDrvFreeBSDIOCtl(struct cdev *pDev, u_long ulCmd, caddr_t pvData, int fFile, struct thread *pTd)
312{
313 PSUPDRVSESSION pSession;
314 devfs_get_cdevpriv((void **)&pSession);
315
316 /*
317 * Deal with the fast ioctl path first.
318 */
319 if ( ( ulCmd == SUP_IOCTL_FAST_DO_RAW_RUN
320 || ulCmd == SUP_IOCTL_FAST_DO_HM_RUN
321 || ulCmd == SUP_IOCTL_FAST_DO_NOP)
322 && pSession->fUnrestricted == true)
323 return supdrvIOCtlFast(ulCmd, *(uint32_t *)pvData, &g_VBoxDrvFreeBSDDevExt, pSession);
324
325 return VBoxDrvFreeBSDIOCtlSlow(pSession, ulCmd, pvData, pTd);
326}
327
328
329/**
330 * Deal with the 'slow' I/O control requests.
331 *
332 * @returns 0 on success, appropriate errno on failure.
333 * @param pSession The session.
334 * @param ulCmd The command.
335 * @param pvData The request data.
336 * @param pTd The calling thread.
337 */
338static int VBoxDrvFreeBSDIOCtlSlow(PSUPDRVSESSION pSession, u_long ulCmd, caddr_t pvData, struct thread *pTd)
339{
340 PSUPREQHDR pHdr;
341 uint32_t cbReq = IOCPARM_LEN(ulCmd);
342 void *pvUser = NULL;
343
344 /*
345 * Buffered request?
346 */
347 if ((IOC_DIRMASK & ulCmd) == IOC_INOUT)
348 {
349 pHdr = (PSUPREQHDR)pvData;
350 if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
351 {
352 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: cbReq=%#x < %#x; ulCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), ulCmd));
353 return EINVAL;
354 }
355 if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
356 {
357 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", pHdr->fFlags, ulCmd));
358 return EINVAL;
359 }
360 if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
361 || pHdr->cbIn < sizeof(*pHdr)
362 || pHdr->cbOut < sizeof(*pHdr)))
363 {
364 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x) != %#x; ulCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, ulCmd));
365 return EINVAL;
366 }
367 }
368 /*
369 * Big unbuffered request?
370 */
371 else if ((IOC_DIRMASK & ulCmd) == IOC_VOID && !cbReq)
372 {
373 /*
374 * Read the header, validate it and figure out how much that needs to be buffered.
375 */
376 SUPREQHDR Hdr;
377 pvUser = *(void **)pvData;
378 int rc = copyin(pvUser, &Hdr, sizeof(Hdr));
379 if (RT_UNLIKELY(rc))
380 {
381 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,Hdr,) -> %#x; ulCmd=%#lx\n", pvUser, rc, ulCmd));
382 return rc;
383 }
384 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
385 {
386 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: bad magic fFlags=%#x; ulCmd=%#lx\n", Hdr.fFlags, ulCmd));
387 return EINVAL;
388 }
389 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
390 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
391 || Hdr.cbOut < sizeof(Hdr)
392 || cbReq > _1M*16))
393 {
394 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: max(%#x,%#x); ulCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, ulCmd));
395 return EINVAL;
396 }
397
398 /*
399 * Allocate buffer and copy in the data.
400 */
401 pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
402 if (RT_UNLIKELY(!pHdr))
403 {
404 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: failed to allocate buffer of %d bytes; ulCmd=%#lx\n", cbReq, ulCmd));
405 return ENOMEM;
406 }
407 rc = copyin(pvUser, pHdr, Hdr.cbIn);
408 if (RT_UNLIKELY(rc))
409 {
410 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyin(%p,%p,%#x) -> %#x; ulCmd=%#lx\n",
411 pvUser, pHdr, Hdr.cbIn, rc, ulCmd));
412 RTMemTmpFree(pHdr);
413 return rc;
414 }
415 if (Hdr.cbIn < cbReq)
416 RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbReq - Hdr.cbIn);
417 }
418 else
419 {
420 Log(("VBoxDrvFreeBSDIOCtlSlow: huh? cbReq=%#x ulCmd=%#lx\n", cbReq, ulCmd));
421 return EINVAL;
422 }
423
424 /*
425 * Process the IOCtl.
426 */
427 int rc = supdrvIOCtl(ulCmd, &g_VBoxDrvFreeBSDDevExt, pSession, pHdr, cbReq);
428 if (RT_LIKELY(!rc))
429 {
430 /*
431 * If unbuffered, copy back the result before returning.
432 */
433 if (pvUser)
434 {
435 uint32_t cbOut = pHdr->cbOut;
436 if (cbOut > cbReq)
437 {
438 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, ulCmd));
439 cbOut = cbReq;
440 }
441 rc = copyout(pHdr, pvUser, cbOut);
442 if (RT_UNLIKELY(rc))
443 OSDBGPRINT(("VBoxDrvFreeBSDIOCtlSlow: copyout(%p,%p,%#x) -> %d; uCmd=%#lx!\n", pHdr, pvUser, cbOut, rc, ulCmd));
444
445 Log(("VBoxDrvFreeBSDIOCtlSlow: returns %d / %d ulCmd=%lx\n", 0, pHdr->rc, ulCmd));
446
447 /* cleanup */
448 RTMemTmpFree(pHdr);
449 }
450 }
451 else
452 {
453 /*
454 * The request failed, just clean up.
455 */
456 if (pvUser)
457 RTMemTmpFree(pHdr);
458
459 Log(("VBoxDrvFreeBSDIOCtlSlow: ulCmd=%lx pData=%p failed, rc=%d\n", ulCmd, pvData, rc));
460 rc = EINVAL;
461 }
462
463 return rc;
464}
465
466
467/**
468 * The SUPDRV IDC entry point.
469 *
470 * @returns VBox status code, see supdrvIDC.
471 * @param iReq The request code.
472 * @param pReq The request.
473 */
474int VBOXCALL SUPDrvFreeBSDIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
475{
476 PSUPDRVSESSION pSession;
477
478 /*
479 * Some quick validations.
480 */
481 if (RT_UNLIKELY(!VALID_PTR(pReq)))
482 return VERR_INVALID_POINTER;
483
484 pSession = pReq->pSession;
485 if (pSession)
486 {
487 if (RT_UNLIKELY(!VALID_PTR(pReq->pSession)))
488 return VERR_INVALID_PARAMETER;
489 if (RT_UNLIKELY(pSession->pDevExt != &g_VBoxDrvFreeBSDDevExt))
490 return VERR_INVALID_PARAMETER;
491 }
492 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
493 return VERR_INVALID_PARAMETER;
494
495 /*
496 * Do the job.
497 */
498 return supdrvIDC(uReq, &g_VBoxDrvFreeBSDDevExt, pSession, pReq);
499}
500
501
502void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
503{
504 NOREF(pDevExt);
505 NOREF(pSession);
506}
507
508
509void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
510{
511 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
512}
513
514
515void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
516{
517 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
518}
519
520
521void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
522{
523 NOREF(pObj);
524 NOREF(pSession);
525}
526
527
528bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
529{
530 NOREF(pObj);
531 NOREF(pSession);
532 NOREF(pszObjName);
533 NOREF(prc);
534 return false;
535}
536
537
538bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
539{
540 return false;
541}
542
543
544bool VBOXCALL supdrvOSAreCpusOfflinedOnSuspend(void)
545{
546 /** @todo verify this. */
547 return false;
548}
549
550
551bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
552{
553 return false;
554}
555
556
557int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
558{
559 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
560 return VERR_NOT_SUPPORTED;
561}
562
563
564void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
565{
566 NOREF(pDevExt); NOREF(pImage);
567}
568
569
570int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv, const uint8_t *pbImageBits)
571{
572 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits);
573 return VERR_NOT_SUPPORTED;
574}
575
576
577int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
578{
579 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
580 return VERR_NOT_SUPPORTED;
581}
582
583
584void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
585{
586 NOREF(pDevExt); NOREF(pImage);
587}
588
589
590#ifdef SUPDRV_WITH_MSR_PROBER
591
592int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
593{
594 NOREF(uMsr); NOREF(idCpu); NOREF(puValue);
595 return VERR_NOT_SUPPORTED;
596}
597
598
599int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
600{
601 NOREF(uMsr); NOREF(idCpu); NOREF(uValue);
602 return VERR_NOT_SUPPORTED;
603}
604
605
606int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
607{
608 NOREF(idCpu); NOREF(pReq);
609 return VERR_NOT_SUPPORTED;
610}
611
612#endif /* SUPDRV_WITH_MSR_PROBER */
613
614
615SUPR0DECL(int) SUPR0Printf(const char *pszFormat, ...)
616{
617 va_list va;
618 char szMsg[256];
619 int cch;
620
621 va_start(va, pszFormat);
622 cch = RTStrPrintfV(szMsg, sizeof(szMsg), pszFormat, va);
623 va_end(va);
624
625 printf("%s", szMsg);
626
627 return cch;
628}
629
630
631SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
632{
633 return 0;
634}
635
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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