VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/darwin/SUPDrv-darwin.cpp@ 15688

最後變更 在這個檔案從15688是 15350,由 vboxsync 提交於 16 年 前

Disabled host_vmxon as it is *broken* and will cause occation kernel panics. Extrememly annoying.

檔案大小: 34.4 KB
 
1/* $Id: $ */
2/** @file
3 *
4 * VBox host drivers - Ring-0 support drivers - Darwin host:
5 * Darwin driver C code
6 */
7
8/*
9 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.alldomusa.eu.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * The contents of this file may alternatively be used under the terms
20 * of the Common Development and Distribution License Version 1.0
21 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
22 * VirtualBox OSE distribution, in which case the provisions of the
23 * CDDL are applicable instead of those of the GPL.
24 *
25 * You may elect to license modified versions of this file under the
26 * terms and conditions of either the GPL or the CDDL or both.
27 *
28 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
29 * Clara, CA 95054 USA or visit http://www.sun.com if you need
30 * additional information or have any questions.
31 */
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
36#define LOG_GROUP LOG_GROUP_SUP_DRV
37/*
38 * Deal with conflicts first.
39 * PVM - BSD mess, that FreeBSD has correct a long time ago.
40 * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
41 */
42#include <iprt/types.h>
43#include <sys/param.h>
44#undef PVM
45
46#include <IOKit/IOLib.h> /* Assert as function */
47
48#include "../SUPDrvInternal.h"
49#include <VBox/version.h>
50#include <iprt/initterm.h>
51#include <iprt/assert.h>
52#include <iprt/spinlock.h>
53#include <iprt/semaphore.h>
54#include <iprt/process.h>
55#include <iprt/alloc.h>
56#include <iprt/power.h>
57#include <VBox/err.h>
58#include <VBox/log.h>
59
60#include <mach/kmod.h>
61#include <miscfs/devfs/devfs.h>
62#include <sys/conf.h>
63#include <sys/errno.h>
64#include <sys/ioccom.h>
65#include <sys/malloc.h>
66#include <sys/proc.h>
67#include <IOKit/IOService.h>
68#include <IOKit/IOUserclient.h>
69#include <IOKit/pwr_mgt/RootDomain.h>
70
71#ifdef VBOX_WITH_HOST_VMX
72__BEGIN_DECLS
73# include <i386/vmx.h>
74__END_DECLS
75#endif
76
77
78/*******************************************************************************
79* Defined Constants And Macros *
80*******************************************************************************/
81
82/** The module name. */
83#define DEVICE_NAME "vboxdrv"
84
85
86
87/*******************************************************************************
88* Internal Functions *
89*******************************************************************************/
90__BEGIN_DECLS
91static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData);
92static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData);
93
94static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
95static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
96static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
97static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess);
98
99static int VBoxDrvDarwinErr2DarwinErr(int rc);
100
101static IOReturn VBoxDrvDarwinSleepHandler(void *pvTarget, void *pvRefCon, UInt32 uMessageType, IOService *pProvider, void *pvMessageArgument, vm_size_t argSize);
102__END_DECLS
103
104
105/*******************************************************************************
106* Structures and Typedefs *
107*******************************************************************************/
108/**
109 * The service class.
110 * This is just a formality really.
111 */
112class org_virtualbox_SupDrv : public IOService
113{
114 OSDeclareDefaultStructors(org_virtualbox_SupDrv);
115
116public:
117 virtual bool init(OSDictionary *pDictionary = 0);
118 virtual void free(void);
119 virtual bool start(IOService *pProvider);
120 virtual void stop(IOService *pProvider);
121 virtual IOService *probe(IOService *pProvider, SInt32 *pi32Score);
122 virtual bool terminate(IOOptionBits fOptions);
123};
124
125OSDefineMetaClassAndStructors(org_virtualbox_SupDrv, IOService);
126
127
128/**
129 * An attempt at getting that clientDied() notification.
130 * I don't think it'll work as I cannot figure out where/what creates the correct
131 * port right.
132 */
133class org_virtualbox_SupDrvClient : public IOUserClient
134{
135 OSDeclareDefaultStructors(org_virtualbox_SupDrvClient);
136
137private:
138 PSUPDRVSESSION m_pSession; /**< The session. */
139 task_t m_Task; /**< The client task. */
140 org_virtualbox_SupDrv *m_pProvider; /**< The service provider. */
141
142public:
143 virtual bool initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type);
144 virtual bool start(IOService *pProvider);
145 static void sessionClose(RTPROCESS Process);
146 virtual IOReturn clientClose(void);
147 virtual IOReturn clientDied(void);
148 virtual bool terminate(IOOptionBits fOptions = 0);
149 virtual bool finalize(IOOptionBits fOptions);
150 virtual void stop(IOService *pProvider);
151};
152
153OSDefineMetaClassAndStructors(org_virtualbox_SupDrvClient, IOUserClient);
154
155
156
157/*******************************************************************************
158* Global Variables *
159*******************************************************************************/
160/**
161 * Declare the module stuff.
162 */
163__BEGIN_DECLS
164extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
165extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
166
167KMOD_EXPLICIT_DECL(VBoxDrv, VBOX_VERSION_STRING, _start, _stop)
168DECLHIDDEN(kmod_start_func_t *) _realmain = VBoxDrvDarwinStart;
169DECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxDrvDarwinStop;
170DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
171__END_DECLS
172
173
174/**
175 * Device extention & session data association structure.
176 */
177static SUPDRVDEVEXT g_DevExt;
178
179/**
180 * The character device switch table for the driver.
181 */
182static struct cdevsw g_DevCW =
183{
184 /** @todo g++ doesn't like this syntax - it worked with gcc before renaming to .cpp. */
185 /*.d_open = */VBoxDrvDarwinOpen,
186 /*.d_close = */VBoxDrvDarwinClose,
187 /*.d_read = */eno_rdwrt,
188 /*.d_write = */eno_rdwrt,
189 /*.d_ioctl = */VBoxDrvDarwinIOCtl,
190 /*.d_stop = */eno_stop,
191 /*.d_reset = */eno_reset,
192 /*.d_ttys = */NULL,
193 /*.d_select= */eno_select,
194 /*.d_mmap = */eno_mmap,
195 /*.d_strategy = */eno_strat,
196 /*.d_getc = */eno_getc,
197 /*.d_putc = */eno_putc,
198 /*.d_type = */0
199};
200
201/** Major device number. */
202static int g_iMajorDeviceNo = -1;
203/** Registered devfs device handle. */
204static void *g_hDevFsDevice = NULL;
205
206/** Spinlock protecting g_apSessionHashTab. */
207static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
208/** Hash table */
209static PSUPDRVSESSION g_apSessionHashTab[19];
210/** Calculates the index into g_apSessionHashTab.*/
211#define SESSION_HASH(pid) ((pid) % RT_ELEMENTS(g_apSessionHashTab))
212/** The number of open sessions. */
213static int32_t volatile g_cSessions = 0;
214/** The notifier handle for the sleep callback handler. */
215static IONotifier *g_pSleepNotifier = NULL;
216
217
218
219/**
220 * Start the kernel module.
221 */
222static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData)
223{
224 int rc;
225#ifdef DEBUG
226 printf("VBoxDrvDarwinStart\n");
227#endif
228
229 /*
230 * Initialize IPRT.
231 */
232 rc = RTR0Init(0);
233 if (RT_SUCCESS(rc))
234 {
235 /*
236 * Initialize the device extension.
237 */
238 rc = supdrvInitDevExt(&g_DevExt);
239 if (RT_SUCCESS(rc))
240 {
241 /*
242 * Initialize the session hash table.
243 */
244 memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab)); /* paranoia */
245 rc = RTSpinlockCreate(&g_Spinlock);
246 if (RT_SUCCESS(rc))
247 {
248 /*
249 * Registering ourselves as a character device.
250 */
251 g_iMajorDeviceNo = cdevsw_add(-1, &g_DevCW);
252 if (g_iMajorDeviceNo >= 0)
253 {
254#ifdef VBOX_WITH_HARDENING
255 g_hDevFsDevice = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
256 UID_ROOT, GID_WHEEL, 0600, DEVICE_NAME);
257#else
258 g_hDevFsDevice = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
259 UID_ROOT, GID_WHEEL, 0666, DEVICE_NAME);
260#endif
261 if (g_hDevFsDevice)
262 {
263 LogRel(("VBoxDrv: version " VBOX_VERSION_STRING " r%d; IOCtl version %#x; IDC version %#x; dev major=%d\n",
264 VBOX_SVN_REV, SUPDRV_IOC_VERSION, SUPDRV_IDC_VERSION, g_iMajorDeviceNo));
265
266 /* Register a sleep/wakeup notification callback */
267 g_pSleepNotifier = registerPrioritySleepWakeInterest(&VBoxDrvDarwinSleepHandler, &g_DevExt, NULL);
268 if (g_pSleepNotifier == NULL)
269 LogRel(("VBoxDrv: register for sleep/wakeup events failed\n"));
270
271 return KMOD_RETURN_SUCCESS;
272 }
273
274 LogRel(("VBoxDrv: devfs_make_node(makedev(%d,0),,,,%s) failed\n", g_iMajorDeviceNo, DEVICE_NAME));
275 cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
276 g_iMajorDeviceNo = -1;
277 }
278 else
279 LogRel(("VBoxDrv: cdevsw_add failed (%d)\n", g_iMajorDeviceNo));
280 RTSpinlockDestroy(g_Spinlock);
281 g_Spinlock = NIL_RTSPINLOCK;
282 }
283 else
284 LogRel(("VBoxDrv: RTSpinlockCreate failed (rc=%d)\n", rc));
285 supdrvDeleteDevExt(&g_DevExt);
286 }
287 else
288 printf("VBoxDrv: failed to initialize device extension (rc=%d)\n", rc);
289 RTR0Term();
290 }
291 else
292 printf("VBoxDrv: failed to initialize IPRT (rc=%d)\n", rc);
293
294 memset(&g_DevExt, 0, sizeof(g_DevExt));
295 return KMOD_RETURN_FAILURE;
296}
297
298
299/**
300 * Stop the kernel module.
301 */
302static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData)
303{
304 int rc;
305 LogFlow(("VBoxDrvDarwinStop\n"));
306
307 /** @todo I've got a nagging feeling that we'll have to keep track of users and refuse
308 * unloading if we're busy. Investigate and implement this! */
309
310 /*
311 * Undo the work done during start (in reverse order).
312 */
313 if (g_pSleepNotifier)
314 {
315 g_pSleepNotifier->remove();
316 g_pSleepNotifier = NULL;
317 }
318
319 devfs_remove(g_hDevFsDevice);
320 g_hDevFsDevice = NULL;
321
322 rc = cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
323 Assert(rc == g_iMajorDeviceNo);
324 g_iMajorDeviceNo = -1;
325
326 supdrvDeleteDevExt(&g_DevExt);
327
328 rc = RTSpinlockDestroy(g_Spinlock);
329 AssertRC(rc);
330 g_Spinlock = NIL_RTSPINLOCK;
331
332 RTR0Term();
333
334 memset(&g_DevExt, 0, sizeof(g_DevExt));
335#ifdef DEBUG
336 printf("VBoxDrvDarwinStop - done\n");
337#endif
338 return KMOD_RETURN_SUCCESS;
339}
340
341
342/**
343 * Device open. Called on open /dev/vboxdrv
344 *
345 * @param pInode Pointer to inode info structure.
346 * @param pFilp Associated file pointer.
347 */
348static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
349{
350#ifdef DEBUG_DARWIN_GIP
351 char szName[128];
352 szName[0] = '\0';
353 proc_name(proc_pid(pProcess), szName, sizeof(szName));
354 Log(("VBoxDrvDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
355#endif
356
357 /*
358 * Find the session created by org_virtualbox_SupDrvClient, fail
359 * if no such session, and mark it as opened. We set the uid & gid
360 * here too, since that is more straight forward at this point.
361 */
362 int rc = VINF_SUCCESS;
363 PSUPDRVSESSION pSession = NULL;
364 struct ucred *pCred = proc_ucred(pProcess);
365 if (pCred)
366 {
367 RTUID Uid = pCred->cr_ruid;
368 RTGID Gid = pCred->cr_rgid;
369 RTPROCESS Process = RTProcSelf();
370 unsigned iHash = SESSION_HASH(Process);
371 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
372 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
373
374 pSession = g_apSessionHashTab[iHash];
375 if (pSession && pSession->Process != Process)
376 {
377 do pSession = pSession->pNextHash;
378 while (pSession && pSession->Process != Process);
379 }
380 if (pSession)
381 {
382 if (!pSession->fOpened)
383 {
384 pSession->fOpened = true;
385 pSession->Uid = Uid;
386 pSession->Gid = Gid;
387 }
388 else
389 rc = VERR_ALREADY_LOADED;
390 }
391 else
392 rc = VERR_GENERAL_FAILURE;
393
394 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
395 }
396 else
397 rc = SUPDRV_ERR_INVALID_PARAM;
398
399#ifdef DEBUG_DARWIN_GIP
400 OSDBGPRINT(("VBoxDrvDarwinOpen: pid=%d '%s' pSession=%p rc=%d\n", proc_pid(pProcess), szName, pSession, rc));
401#else
402 Log(("VBoxDrvDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess)));
403#endif
404 return VBoxDrvDarwinErr2DarwinErr(rc);
405}
406
407
408/**
409 * Close device.
410 */
411static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
412{
413 Log(("VBoxDrvDarwinClose: pid=%d\n", (int)RTProcSelf()));
414 Assert(proc_pid(pProcess) == (int)RTProcSelf());
415
416 /*
417 * Hand the session closing to org_virtualbox_SupDrvClient.
418 */
419 org_virtualbox_SupDrvClient::sessionClose(RTProcSelf());
420 return 0;
421}
422
423
424/**
425 * Device I/O Control entry point.
426 *
427 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
428 * @param Dev The device number (major+minor).
429 * @param iCmd The IOCtl command.
430 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
431 * @param fFlags Flag saying we're a character device (like we didn't know already).
432 * @param pProcess The process issuing this request.
433 */
434static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
435{
436 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
437 const RTPROCESS Process = proc_pid(pProcess);
438 const unsigned iHash = SESSION_HASH(Process);
439 PSUPDRVSESSION pSession;
440
441 /*
442 * Find the session.
443 */
444 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
445 pSession = g_apSessionHashTab[iHash];
446 if (pSession && pSession->Process != Process)
447 {
448 do pSession = pSession->pNextHash;
449 while (pSession && pSession->Process != Process);
450 }
451 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
452 if (!pSession)
453 {
454 OSDBGPRINT(("VBoxDrvDarwinIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
455 (int)Process, iCmd));
456 return EINVAL;
457 }
458
459 /*
460 * Deal with the two high-speed IOCtl that takes it's arguments from
461 * the session and iCmd, and only returns a VBox status code.
462 */
463 if ( iCmd == SUP_IOCTL_FAST_DO_RAW_RUN
464 || iCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
465 || iCmd == SUP_IOCTL_FAST_DO_NOP)
466 return supdrvIOCtlFast(iCmd, *(uint32_t *)pData, &g_DevExt, pSession);
467 return VBoxDrvDarwinIOCtlSlow(pSession, iCmd, pData, pProcess);
468}
469
470
471/**
472 * Worker for VBoxDrvDarwinIOCtl that takes the slow IOCtl functions.
473 *
474 * @returns Darwin errno.
475 *
476 * @param pSession The session.
477 * @param iCmd The IOCtl command.
478 * @param pData Pointer to the kernel copy of the SUPDRVIOCTLDATA buffer.
479 * @param pProcess The calling process.
480 */
481static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
482{
483 LogFlow(("VBoxDrvDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));
484
485
486 /*
487 * Buffered or unbuffered?
488 */
489 PSUPREQHDR pHdr;
490 user_addr_t pUser = 0;
491 void *pvPageBuf = NULL;
492 uint32_t cbReq = IOCPARM_LEN(iCmd);
493 if ((IOC_DIRMASK & iCmd) == IOC_INOUT)
494 {
495 pHdr = (PSUPREQHDR)pData;
496 if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
497 {
498 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: cbReq=%#x < %#x; iCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), iCmd));
499 return EINVAL;
500 }
501 if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
502 {
503 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", pHdr->fFlags, iCmd));
504 return EINVAL;
505 }
506 if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
507 || pHdr->cbIn < sizeof(*pHdr)
508 || pHdr->cbOut < sizeof(*pHdr)))
509 {
510 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x) != %#x; iCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, iCmd));
511 return EINVAL;
512 }
513 }
514 else if ((IOC_DIRMASK & iCmd) == IOC_VOID && !cbReq)
515 {
516 /*
517 * Get the header and figure out how much we're gonna have to read.
518 */
519 SUPREQHDR Hdr;
520 pUser = (user_addr_t)*(void **)pData;
521 int rc = copyin(pUser, &Hdr, sizeof(Hdr));
522 if (RT_UNLIKELY(rc))
523 {
524 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
525 return rc;
526 }
527 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
528 {
529 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", Hdr.fFlags, iCmd));
530 return EINVAL;
531 }
532 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
533 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
534 || Hdr.cbOut < sizeof(Hdr)
535 || cbReq > _1M*16))
536 {
537 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x); iCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, iCmd));
538 return EINVAL;
539 }
540
541 /*
542 * Allocate buffer and copy in the data.
543 */
544 pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
545 if (!pHdr)
546 pvPageBuf = pHdr = (PSUPREQHDR)IOMallocAligned(RT_ALIGN_Z(cbReq, PAGE_SIZE), 8);
547 if (RT_UNLIKELY(!pHdr))
548 {
549 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
550 return ENOMEM;
551 }
552 rc = copyin(pUser, pHdr, Hdr.cbIn);
553 if (RT_UNLIKELY(rc))
554 {
555 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,%p,%#x) -> %#x; iCmd=%#lx\n",
556 (unsigned long long)pUser, pHdr, Hdr.cbIn, rc, iCmd));
557 if (pvPageBuf)
558 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
559 else
560 RTMemTmpFree(pHdr);
561 return rc;
562 }
563 }
564 else
565 {
566 Log(("VBoxDrvDarwinIOCtlSlow: huh? cbReq=%#x iCmd=%#lx\n", cbReq, iCmd));
567 return EINVAL;
568 }
569
570 /*
571 * Process the IOCtl.
572 */
573 int rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
574 if (RT_LIKELY(!rc))
575 {
576 /*
577 * If not buffered, copy back the buffer before returning.
578 */
579 if (pUser)
580 {
581 uint32_t cbOut = pHdr->cbOut;
582 if (cbOut > cbReq)
583 {
584 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, iCmd));
585 cbOut = cbReq;
586 }
587 rc = copyout(pHdr, pUser, cbOut);
588 if (RT_UNLIKELY(rc))
589 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyout(%p,%llx,%#x) -> %d; uCmd=%#lx!\n",
590 pHdr, (unsigned long long)pUser, cbOut, rc, iCmd));
591
592 /* cleanup */
593 if (pvPageBuf)
594 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
595 else
596 RTMemTmpFree(pHdr);
597 }
598 }
599 else
600 {
601 /*
602 * The request failed, just clean up.
603 */
604 if (pUser)
605 {
606 if (pvPageBuf)
607 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
608 else
609 RTMemTmpFree(pHdr);
610 }
611
612 Log(("VBoxDrvDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
613 rc = EINVAL;
614 }
615
616 Log2(("VBoxDrvDarwinIOCtlSlow: returns %d\n", rc));
617 return rc;
618}
619
620
621/**
622 * The SUPDRV IDC entry point.
623 *
624 * @returns VBox status code, see supdrvIDC.
625 * @param iReq The request code.
626 * @param pReq The request.
627 */
628int VBOXCALL SUPDrvDarwinIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
629{
630 PSUPDRVSESSION pSession;
631
632 /*
633 * Some quick validations.
634 */
635 if (RT_UNLIKELY(!VALID_PTR(pReq)))
636 return VERR_INVALID_POINTER;
637
638 pSession = pReq->pSession;
639 if (pSession)
640 {
641 if (RT_UNLIKELY(!VALID_PTR(pSession)))
642 return VERR_INVALID_PARAMETER;
643 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
644 return VERR_INVALID_PARAMETER;
645 }
646 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
647 return VERR_INVALID_PARAMETER;
648
649 /*
650 * Do the job.
651 */
652 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
653}
654
655
656/**
657 * Initializes any OS specific object creator fields.
658 */
659void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
660{
661 NOREF(pObj);
662 NOREF(pSession);
663}
664
665
666/**
667 * Checks if the session can access the object.
668 *
669 * @returns true if a decision has been made.
670 * @returns false if the default access policy should be applied.
671 *
672 * @param pObj The object in question.
673 * @param pSession The session wanting to access the object.
674 * @param pszObjName The object name, can be NULL.
675 * @param prc Where to store the result when returning true.
676 */
677bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
678{
679 NOREF(pObj);
680 NOREF(pSession);
681 NOREF(pszObjName);
682 NOREF(prc);
683 return false;
684}
685
686/**
687 * Callback for blah blah blah.
688 */
689IOReturn VBoxDrvDarwinSleepHandler(void * /* pvTarget */, void *pvRefCon, UInt32 uMessageType, IOService * /* pProvider */, void * /* pvMessageArgument */, vm_size_t /* argSize */)
690{
691 LogFlow(("VBoxDrv: Got sleep/wake notice. Message type was %X\n", (uint)uMessageType));
692
693 if (uMessageType == kIOMessageSystemWillSleep)
694 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
695 else if (uMessageType == kIOMessageSystemHasPoweredOn)
696 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
697
698 acknowledgeSleepWakeNotification(pvRefCon);
699
700 return 0;
701}
702
703
704/**
705 * Enables or disables VT-x using kernel functions.
706 *
707 * @returns VBox status code. VERR_NOT_SUPPORTED has a special meaning.
708 * @param fEnable Whether to enable or disable.
709 */
710int VBOXCALL supdrvOSEnableVTx(bool fEnable)
711{
712/* Zarking amateurish Apple engineering!
713 host_vmxon is actually buggy and may panic multicore machines. Reason, it
714 uses a simple lock which will disable preemption of the cpu/thread trying
715 to acquire it. Then it allocate wired memory in the kernel map for each
716 of the cpus in the system. If anyone else tries to mess around in the
717 kernel map on another CPU while this is going on, there is a fair chance
718 that it might cause the host_vmxon thread to block and hence panic since
719 preemption is disabled. Arrrg! */
720#if 0 /*def VBOX_WITH_HOST_VMX*/
721 int rc;
722 if (fEnable)
723 {
724 rc = host_vmxon(false /* exclusive */);
725 if (rc == 0 /* all ok */)
726 rc = VINF_SUCCESS;
727 else if (rc == 1 /* unsupported */)
728 rc = VERR_VMX_NO_VMX;
729 else if (rc == 2 /* exclusive user */)
730 rc = VERR_VMX_IN_VMX_ROOT_MODE;
731 else /* shouldn't happen, but just in case. */
732 {
733 LogRel(("host_vmxon returned %d\n", rc));
734 rc = VERR_UNRESOLVED_ERROR;
735 }
736 }
737 else
738 {
739 host_vmxoff();
740 rc = VINF_SUCCESS;
741 }
742 return rc;
743#else
744 return VERR_NOT_SUPPORTED;
745#endif
746}
747
748
749bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
750{
751 NOREF(pDevExt);
752 return false;
753}
754
755
756/**
757 * Converts a supdrv error code to a darwin error code.
758 *
759 * @returns corresponding darwin error code.
760 * @param rc supdrv error code (SUPDRV_ERR_* defines).
761 */
762static int VBoxDrvDarwinErr2DarwinErr(int rc)
763{
764 switch (rc)
765 {
766 case 0: return 0;
767 case SUPDRV_ERR_GENERAL_FAILURE: return EACCES;
768 case SUPDRV_ERR_INVALID_PARAM: return EINVAL;
769 case SUPDRV_ERR_INVALID_MAGIC: return EILSEQ;
770 case SUPDRV_ERR_INVALID_HANDLE: return ENXIO;
771 case SUPDRV_ERR_INVALID_POINTER: return EFAULT;
772 case SUPDRV_ERR_LOCK_FAILED: return ENOLCK;
773 case SUPDRV_ERR_ALREADY_LOADED: return EEXIST;
774 case SUPDRV_ERR_PERMISSION_DENIED: return EPERM;
775 case SUPDRV_ERR_VERSION_MISMATCH: return ENOSYS;
776 }
777
778 return EPERM;
779}
780
781
782/** @todo move this to assembly where a simple "jmp printf" will to the trick. */
783RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
784{
785 va_list args;
786 char szMsg[512];
787
788 va_start(args, pszFormat);
789 vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
790 va_end(args);
791
792 szMsg[sizeof(szMsg) - 1] = '\0';
793 printf("%s", szMsg);
794 return 0;
795}
796
797
798/*
799 *
800 * org_virtualbox_SupDrv
801 *
802 */
803
804
805/**
806 * Initialize the object.
807 */
808bool org_virtualbox_SupDrv::init(OSDictionary *pDictionary)
809{
810 LogFlow(("org_virtualbox_SupDrv::init([%p], %p)\n", this, pDictionary));
811 if (IOService::init(pDictionary))
812 {
813 /* init members. */
814 return true;
815 }
816 return false;
817}
818
819
820/**
821 * Free the object.
822 */
823void org_virtualbox_SupDrv::free(void)
824{
825 LogFlow(("IOService::free([%p])\n", this));
826 IOService::free();
827}
828
829
830/**
831 * Check if it's ok to start this service.
832 * It's always ok by us, so it's up to IOService to decide really.
833 */
834IOService *org_virtualbox_SupDrv::probe(IOService *pProvider, SInt32 *pi32Score)
835{
836 LogFlow(("org_virtualbox_SupDrv::probe([%p])\n", this));
837 return IOService::probe(pProvider, pi32Score);
838}
839
840
841/**
842 * Start this service.
843 */
844bool org_virtualbox_SupDrv::start(IOService *pProvider)
845{
846 LogFlow(("org_virtualbox_SupDrv::start([%p])\n", this));
847
848 if (IOService::start(pProvider))
849 {
850 /* register the service. */
851 registerService();
852 return true;
853 }
854 return false;
855}
856
857
858/**
859 * Stop this service.
860 */
861void org_virtualbox_SupDrv::stop(IOService *pProvider)
862{
863 LogFlow(("org_virtualbox_SupDrv::stop([%p], %p)\n", this, pProvider));
864 IOService::stop(pProvider);
865}
866
867
868/**
869 * Termination request.
870 *
871 * @return true if we're ok with shutting down now, false if we're not.
872 * @param fOptions Flags.
873 */
874bool org_virtualbox_SupDrv::terminate(IOOptionBits fOptions)
875{
876 bool fRc;
877 LogFlow(("org_virtualbox_SupDrv::terminate: reference_count=%d g_cSessions=%d (fOptions=%#x)\n",
878 KMOD_INFO_NAME.reference_count, ASMAtomicUoReadS32(&g_cSessions), fOptions));
879 if ( KMOD_INFO_NAME.reference_count != 0
880 || ASMAtomicUoReadS32(&g_cSessions))
881 fRc = false;
882 else
883 fRc = IOService::terminate(fOptions);
884 LogFlow(("org_virtualbox_SupDrv::terminate: returns %d\n", fRc));
885 return fRc;
886}
887
888
889/*
890 *
891 * org_virtualbox_SupDrvClient
892 *
893 */
894
895
896/**
897 * Initializer called when the client opens the service.
898 */
899bool org_virtualbox_SupDrvClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type)
900{
901 LogFlow(("org_virtualbox_SupDrvClient::initWithTask([%p], %#x, %p, %#x) (cur pid=%d proc=%p)\n",
902 this, OwningTask, pvSecurityId, u32Type, RTProcSelf(), RTR0ProcHandleSelf()));
903 AssertMsg((RTR0PROCESS)OwningTask == RTR0ProcHandleSelf(), ("%p %p\n", OwningTask, RTR0ProcHandleSelf()));
904
905 if (!OwningTask)
906 return false;
907 if (IOUserClient::initWithTask(OwningTask, pvSecurityId , u32Type))
908 {
909 m_Task = OwningTask;
910 m_pSession = NULL;
911 m_pProvider = NULL;
912 return true;
913 }
914 return false;
915}
916
917
918/**
919 * Start the client service.
920 */
921bool org_virtualbox_SupDrvClient::start(IOService *pProvider)
922{
923 LogFlow(("org_virtualbox_SupDrvClient::start([%p], %p) (cur pid=%d proc=%p)\n",
924 this, pProvider, RTProcSelf(), RTR0ProcHandleSelf() ));
925 AssertMsgReturn((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(),
926 ("%p %p\n", m_Task, RTR0ProcHandleSelf()),
927 false);
928
929 if (IOUserClient::start(pProvider))
930 {
931 m_pProvider = OSDynamicCast(org_virtualbox_SupDrv, pProvider);
932 if (m_pProvider)
933 {
934 Assert(!m_pSession);
935
936 /*
937 * Create a new session.
938 */
939 int rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &m_pSession);
940 if (RT_SUCCESS(rc))
941 {
942 m_pSession->fOpened = false;
943 /* The Uid and Gid fields are set on open. */
944
945 /*
946 * Insert it into the hash table, checking that there isn't
947 * already one for this process first.
948 */
949 unsigned iHash = SESSION_HASH(m_pSession->Process);
950 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
951 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
952
953 PSUPDRVSESSION pCur = g_apSessionHashTab[iHash];
954 if (pCur && pCur->Process != m_pSession->Process)
955 {
956 do pCur = pCur->pNextHash;
957 while (pCur && pCur->Process != m_pSession->Process);
958 }
959 if (!pCur)
960 {
961 m_pSession->pNextHash = g_apSessionHashTab[iHash];
962 g_apSessionHashTab[iHash] = m_pSession;
963 m_pSession->pvSupDrvClient = this;
964 ASMAtomicIncS32(&g_cSessions);
965 rc = VINF_SUCCESS;
966 }
967 else
968 rc = VERR_ALREADY_LOADED;
969
970 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
971 if (RT_SUCCESS(rc))
972 {
973 Log(("org_virtualbox_SupDrvClient::start: created session %p for pid %d\n", m_pSession, (int)RTProcSelf()));
974 return true;
975 }
976
977 LogFlow(("org_virtualbox_SupDrvClient::start: already got a session for this process (%p)\n", pCur));
978 supdrvCloseSession(&g_DevExt, m_pSession);
979 }
980
981 m_pSession = NULL;
982 LogFlow(("org_virtualbox_SupDrvClient::start: rc=%Rrc from supdrvCreateSession\n", rc));
983 }
984 else
985 LogFlow(("org_virtualbox_SupDrvClient::start: %p isn't org_virtualbox_SupDrv\n", pProvider));
986 }
987 return false;
988}
989
990
991/**
992 * Common worker for clientClose and VBoxDrvDarwinClose.
993 *
994 * It will
995 */
996/* static */ void org_virtualbox_SupDrvClient::sessionClose(RTPROCESS Process)
997{
998 /*
999 * Look for the session.
1000 */
1001 const unsigned iHash = SESSION_HASH(Process);
1002 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
1003 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
1004 PSUPDRVSESSION pSession = g_apSessionHashTab[iHash];
1005 if (pSession)
1006 {
1007 if (pSession->Process == Process)
1008 {
1009 g_apSessionHashTab[iHash] = pSession->pNextHash;
1010 pSession->pNextHash = NULL;
1011 ASMAtomicDecS32(&g_cSessions);
1012 }
1013 else
1014 {
1015 PSUPDRVSESSION pPrev = pSession;
1016 pSession = pSession->pNextHash;
1017 while (pSession)
1018 {
1019 if (pSession->Process == Process)
1020 {
1021 pPrev->pNextHash = pSession->pNextHash;
1022 pSession->pNextHash = NULL;
1023 ASMAtomicDecS32(&g_cSessions);
1024 break;
1025 }
1026
1027 /* next */
1028 pPrev = pSession;
1029 pSession = pSession->pNextHash;
1030 }
1031 }
1032 }
1033 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
1034 if (!pSession)
1035 {
1036 Log(("SupDrvClient::sessionClose: pSession == NULL, pid=%d; freed already?\n", (int)Process));
1037 return;
1038 }
1039
1040 /*
1041 * Remove it from the client object.
1042 */
1043 org_virtualbox_SupDrvClient *pThis = (org_virtualbox_SupDrvClient *)pSession->pvSupDrvClient;
1044 pSession->pvSupDrvClient = NULL;
1045 if (pThis)
1046 {
1047 Assert(pThis->m_pSession == pSession);
1048 pThis->m_pSession = NULL;
1049 }
1050
1051 /*
1052 * Close the session.
1053 */
1054 supdrvCloseSession(&g_DevExt, pSession);
1055}
1056
1057
1058/**
1059 * Client exits normally.
1060 */
1061IOReturn org_virtualbox_SupDrvClient::clientClose(void)
1062{
1063 LogFlow(("org_virtualbox_SupDrvClient::clientClose([%p]) (cur pid=%d proc=%p)\n", this, RTProcSelf(), RTR0ProcHandleSelf()));
1064 AssertMsg((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(), ("%p %p\n", m_Task, RTR0ProcHandleSelf()));
1065
1066 /*
1067 * Clean up the session if it's still around.
1068 *
1069 * We cannot rely 100% on close, and in the case of a dead client
1070 * we'll end up hanging inside vm_map_remove() if we postpone it.
1071 */
1072 if (m_pSession)
1073 {
1074 sessionClose(RTProcSelf());
1075 Assert(!m_pSession);
1076 }
1077
1078 m_pProvider = NULL;
1079 terminate();
1080
1081 return kIOReturnSuccess;
1082}
1083
1084
1085/**
1086 * The client exits abnormally / forgets to do cleanups. (logging)
1087 */
1088IOReturn org_virtualbox_SupDrvClient::clientDied(void)
1089{
1090 LogFlow(("org_virtualbox_SupDrvClient::clientDied([%p]) m_Task=%p R0Process=%p Process=%d\n",
1091 this, m_Task, RTR0ProcHandleSelf(), RTProcSelf()));
1092
1093 /* IOUserClient::clientDied() calls clientClose, so we'll just do the work there. */
1094 return IOUserClient::clientDied();
1095}
1096
1097
1098/**
1099 * Terminate the service (initiate the destruction). (logging)
1100 */
1101bool org_virtualbox_SupDrvClient::terminate(IOOptionBits fOptions)
1102{
1103 LogFlow(("org_virtualbox_SupDrvClient::terminate([%p], %#x)\n", this, fOptions));
1104 return IOUserClient::terminate(fOptions);
1105}
1106
1107
1108/**
1109 * The final stage of the client service destruction. (logging)
1110 */
1111bool org_virtualbox_SupDrvClient::finalize(IOOptionBits fOptions)
1112{
1113 LogFlow(("org_virtualbox_SupDrvClient::finalize([%p], %#x)\n", this, fOptions));
1114 return IOUserClient::finalize(fOptions);
1115}
1116
1117
1118/**
1119 * Stop the client service. (logging)
1120 */
1121void org_virtualbox_SupDrvClient::stop(IOService *pProvider)
1122{
1123 LogFlow(("org_virtualbox_SupDrvClient::stop([%p])\n", this));
1124 IOUserClient::stop(pProvider);
1125}
1126
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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