VirtualBox

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

Last change on this file since 78286 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 76.8 KB
Line 
1/* $Id: SUPDrv-darwin.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VirtualBox Support Driver - Darwin Specific Code.
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#define LOG_GROUP LOG_GROUP_SUP_DRV
32#include "../../../Runtime/r0drv/darwin/the-darwin-kernel.h"
33
34#include "../SUPDrvInternal.h"
35#include <VBox/version.h>
36#include <iprt/assert.h>
37#include <iprt/asm.h>
38#include <iprt/asm-amd64-x86.h>
39#include <iprt/ctype.h>
40#include <iprt/dbg.h>
41#include <iprt/initterm.h>
42#include <iprt/file.h>
43#include <iprt/ldr.h>
44#include <iprt/mem.h>
45#include <iprt/power.h>
46#include <iprt/process.h>
47#include <iprt/spinlock.h>
48#include <iprt/semaphore.h>
49#include <iprt/x86.h>
50#include <iprt/crypto/applecodesign.h>
51#include <iprt/crypto/store.h>
52#include <iprt/crypto/pkcs7.h>
53#include <iprt/crypto/x509.h>
54#include <VBox/err.h>
55#include <VBox/log.h>
56
57#include <mach/kmod.h>
58#include <miscfs/devfs/devfs.h>
59#include <sys/conf.h>
60#include <sys/errno.h>
61#include <sys/ioccom.h>
62#include <sys/malloc.h>
63#include <sys/proc.h>
64#include <sys/kauth.h>
65#include <IOKit/IOService.h>
66#include <IOKit/IOUserClient.h>
67#include <IOKit/pwr_mgt/RootDomain.h>
68#include <IOKit/IODeviceTreeSupport.h>
69#include <IOKit/usb/IOUSBHIDDriver.h>
70#include <IOKit/bluetooth/IOBluetoothHIDDriver.h>
71#include <IOKit/bluetooth/IOBluetoothHIDDriverTypes.h>
72
73#ifdef VBOX_WITH_HOST_VMX
74# include <libkern/version.h>
75RT_C_DECLS_BEGIN
76# include <i386/vmx.h>
77RT_C_DECLS_END
78#endif
79
80
81/*********************************************************************************************************************************
82* Defined Constants And Macros *
83*********************************************************************************************************************************/
84
85/** The system device node name. */
86#define DEVICE_NAME_SYS "vboxdrv"
87/** The user device node name. */
88#define DEVICE_NAME_USR "vboxdrvu"
89
90
91/** @name For debugging/whatever, now permanent.
92 * @{ */
93#define VBOX_PROC_SELFNAME_LEN 31
94#define VBOX_RETRIEVE_CUR_PROC_NAME(a_Name) char a_Name[VBOX_PROC_SELFNAME_LEN + 1]; \
95 proc_selfname(a_Name, VBOX_PROC_SELFNAME_LEN)
96/** @} */
97
98
99/*********************************************************************************************************************************
100* Internal Functions *
101*********************************************************************************************************************************/
102RT_C_DECLS_BEGIN
103static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData);
104static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData);
105#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
106static int supdrvDarwinInitCertStores(PSUPDRVDEVEXT pDevExt);
107static void supdrvDarwinDestroyCertStores(PSUPDRVDEVEXT pDevExt);
108#endif
109
110static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
111static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
112static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
113static int VBoxDrvDarwinIOCtlSMAP(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
114static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess);
115
116static int VBoxDrvDarwinErr2DarwinErr(int rc);
117
118static IOReturn VBoxDrvDarwinSleepHandler(void *pvTarget, void *pvRefCon, UInt32 uMessageType, IOService *pProvider, void *pvMessageArgument, vm_size_t argSize);
119RT_C_DECLS_END
120
121static int vboxdrvDarwinResolveSymbols(void);
122static bool vboxdrvDarwinCpuHasSMAP(void);
123
124
125/*********************************************************************************************************************************
126* Structures and Typedefs *
127*********************************************************************************************************************************/
128/**
129 * The service class.
130 * This is just a formality really.
131 */
132class org_virtualbox_SupDrv : public IOService
133{
134 OSDeclareDefaultStructors(org_virtualbox_SupDrv);
135
136public:
137 virtual bool init(OSDictionary *pDictionary = 0);
138 virtual void free(void);
139 virtual bool start(IOService *pProvider);
140 virtual void stop(IOService *pProvider);
141 virtual IOService *probe(IOService *pProvider, SInt32 *pi32Score);
142 virtual bool terminate(IOOptionBits fOptions);
143
144 RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT();
145
146private:
147 /** Guard against the parent class growing and us using outdated headers. */
148 uint8_t m_abSafetyPadding[256];
149};
150
151OSDefineMetaClassAndStructors(org_virtualbox_SupDrv, IOService);
152
153
154/**
155 * An attempt at getting that clientDied() notification.
156 * I don't think it'll work as I cannot figure out where/what creates the correct
157 * port right.
158 */
159class org_virtualbox_SupDrvClient : public IOUserClient
160{
161 OSDeclareDefaultStructors(org_virtualbox_SupDrvClient);
162
163private:
164 /** Guard against the parent class growing and us using outdated headers. */
165 uint8_t m_abSafetyPadding[256];
166
167 PSUPDRVSESSION m_pSession; /**< The session. */
168 task_t m_Task; /**< The client task. */
169 org_virtualbox_SupDrv *m_pProvider; /**< The service provider. */
170
171public:
172 virtual bool initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type);
173 virtual bool start(IOService *pProvider);
174 static void sessionClose(RTPROCESS Process);
175 virtual IOReturn clientClose(void);
176 virtual IOReturn clientDied(void);
177 virtual bool terminate(IOOptionBits fOptions = 0);
178 virtual bool finalize(IOOptionBits fOptions);
179 virtual void stop(IOService *pProvider);
180
181 RTR0MEMEF_NEW_AND_DELETE_OPERATORS_IOKIT();
182};
183
184OSDefineMetaClassAndStructors(org_virtualbox_SupDrvClient, IOUserClient);
185
186
187
188/*********************************************************************************************************************************
189* Global Variables *
190*********************************************************************************************************************************/
191/**
192 * Declare the module stuff.
193 */
194RT_C_DECLS_BEGIN
195extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
196extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
197
198KMOD_EXPLICIT_DECL(VBoxDrv, VBOX_VERSION_STRING, _start, _stop)
199DECLHIDDEN(kmod_start_func_t *) _realmain = VBoxDrvDarwinStart;
200DECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxDrvDarwinStop;
201DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
202RT_C_DECLS_END
203
204
205/**
206 * Device extention & session data association structure.
207 */
208static SUPDRVDEVEXT g_DevExt;
209
210/**
211 * The character device switch table for the driver.
212 */
213static struct cdevsw g_DevCW =
214{
215 /** @todo g++ doesn't like this syntax - it worked with gcc before renaming to .cpp. */
216 /*.d_open = */VBoxDrvDarwinOpen,
217 /*.d_close = */VBoxDrvDarwinClose,
218 /*.d_read = */eno_rdwrt,
219 /*.d_write = */eno_rdwrt,
220 /*.d_ioctl = */VBoxDrvDarwinIOCtl,
221 /*.d_stop = */eno_stop,
222 /*.d_reset = */eno_reset,
223 /*.d_ttys = */NULL,
224 /*.d_select= */eno_select,
225 /*.d_mmap = */eno_mmap,
226 /*.d_strategy = */eno_strat,
227 /*.d_getc = */(void *)(uintptr_t)&enodev, //eno_getc,
228 /*.d_putc = */(void *)(uintptr_t)&enodev, //eno_putc,
229 /*.d_type = */0
230};
231
232/** Major device number. */
233static int g_iMajorDeviceNo = -1;
234/** Registered devfs device handle for the system device. */
235static void *g_hDevFsDeviceSys = NULL;
236/** Registered devfs device handle for the user device. */
237static void *g_hDevFsDeviceUsr = NULL;
238
239/** Spinlock protecting g_apSessionHashTab. */
240static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
241/** Hash table */
242static PSUPDRVSESSION g_apSessionHashTab[19];
243/** Calculates the index into g_apSessionHashTab.*/
244#define SESSION_HASH(pid) ((pid) % RT_ELEMENTS(g_apSessionHashTab))
245/** The number of open sessions. */
246static int32_t volatile g_cSessions = 0;
247/** The notifier handle for the sleep callback handler. */
248static IONotifier *g_pSleepNotifier = NULL;
249
250/** Pointer to vmx_suspend(). */
251static PFNRT g_pfnVmxSuspend = NULL;
252/** Pointer to vmx_resume(). */
253static PFNRT g_pfnVmxResume = NULL;
254/** Pointer to vmx_use_count. */
255static int volatile *g_pVmxUseCount = NULL;
256
257#ifdef SUPDRV_WITH_MSR_PROBER
258/** Pointer to rdmsr_carefully if found. Returns 0 on success. */
259static int (*g_pfnRdMsrCarefully)(uint32_t uMsr, uint32_t *puLow, uint32_t *puHigh) = NULL;
260/** Pointer to rdmsr64_carefully if found. Returns 0 on success. */
261static int (*g_pfnRdMsr64Carefully)(uint32_t uMsr, uint64_t *uValue) = NULL;
262/** Pointer to wrmsr[64]_carefully if found. Returns 0 on success. */
263static int (*g_pfnWrMsr64Carefully)(uint32_t uMsr, uint64_t uValue) = NULL;
264#endif
265
266
267/**
268 * Start the kernel module.
269 */
270static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData)
271{
272 RT_NOREF(pKModInfo, pvData);
273#ifdef DEBUG
274 printf("VBoxDrvDarwinStart\n");
275#endif
276
277 /*
278 * Initialize IPRT.
279 */
280 int rc = RTR0Init(0);
281 if (RT_SUCCESS(rc))
282 {
283 /*
284 * Initialize the device extension.
285 */
286 rc = supdrvInitDevExt(&g_DevExt, sizeof(SUPDRVSESSION));
287 if (RT_SUCCESS(rc))
288 {
289#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
290 supdrvDarwinInitCertStores(&g_DevExt);
291#endif
292
293 /*
294 * Initialize the session hash table.
295 */
296 memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab)); /* paranoia */
297 rc = RTSpinlockCreate(&g_Spinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxDrvDarwin");
298 if (RT_SUCCESS(rc))
299 {
300 if (vboxdrvDarwinCpuHasSMAP())
301 {
302 LogRel(("disabling SMAP for VBoxDrvDarwinIOCtl\n"));
303 g_DevCW.d_ioctl = VBoxDrvDarwinIOCtlSMAP;
304 }
305
306 /*
307 * Resolve some extra kernel symbols.
308 */
309 rc = vboxdrvDarwinResolveSymbols();
310 if (RT_SUCCESS(rc))
311 {
312
313 /*
314 * Registering ourselves as a character device.
315 */
316 g_iMajorDeviceNo = cdevsw_add(-1, &g_DevCW);
317 if (g_iMajorDeviceNo >= 0)
318 {
319#ifdef VBOX_WITH_HARDENING
320 g_hDevFsDeviceSys = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
321 UID_ROOT, GID_WHEEL, 0600, DEVICE_NAME_SYS);
322#else
323 g_hDevFsDeviceSys = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
324 UID_ROOT, GID_WHEEL, 0666, DEVICE_NAME_SYS);
325#endif
326 if (g_hDevFsDeviceSys)
327 {
328 g_hDevFsDeviceUsr = devfs_make_node(makedev(g_iMajorDeviceNo, 1), DEVFS_CHAR,
329 UID_ROOT, GID_WHEEL, 0666, DEVICE_NAME_USR);
330 if (g_hDevFsDeviceUsr)
331 {
332 LogRel(("VBoxDrv: version " VBOX_VERSION_STRING " r%d; IOCtl version %#x; IDC version %#x; dev major=%d\n",
333 VBOX_SVN_REV, SUPDRV_IOC_VERSION, SUPDRV_IDC_VERSION, g_iMajorDeviceNo));
334
335 /* Register a sleep/wakeup notification callback */
336 g_pSleepNotifier = registerPrioritySleepWakeInterest(&VBoxDrvDarwinSleepHandler, &g_DevExt, NULL);
337 if (g_pSleepNotifier == NULL)
338 LogRel(("VBoxDrv: register for sleep/wakeup events failed\n"));
339
340 return KMOD_RETURN_SUCCESS;
341 }
342
343 LogRel(("VBoxDrv: devfs_make_node(makedev(%d,1),,,,%s) failed\n", g_iMajorDeviceNo, DEVICE_NAME_USR));
344 devfs_remove(g_hDevFsDeviceSys);
345 g_hDevFsDeviceSys = NULL;
346 }
347 else
348 LogRel(("VBoxDrv: devfs_make_node(makedev(%d,0),,,,%s) failed\n", g_iMajorDeviceNo, DEVICE_NAME_SYS));
349
350 cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
351 g_iMajorDeviceNo = -1;
352 }
353 else
354 LogRel(("VBoxDrv: cdevsw_add failed (%d)\n", g_iMajorDeviceNo));
355 }
356#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
357 supdrvDarwinDestroyCertStores(&g_DevExt);
358#endif
359 RTSpinlockDestroy(g_Spinlock);
360 g_Spinlock = NIL_RTSPINLOCK;
361 }
362 else
363 LogRel(("VBoxDrv: RTSpinlockCreate failed (rc=%d)\n", rc));
364 supdrvDeleteDevExt(&g_DevExt);
365 }
366 else
367 printf("VBoxDrv: failed to initialize device extension (rc=%d)\n", rc);
368 RTR0TermForced();
369 }
370 else
371 printf("VBoxDrv: failed to initialize IPRT (rc=%d)\n", rc);
372
373 memset(&g_DevExt, 0, sizeof(g_DevExt));
374 return KMOD_RETURN_FAILURE;
375}
376
377
378/**
379 * Resolves kernel symbols we need and some we just would like to have.
380 */
381static int vboxdrvDarwinResolveSymbols(void)
382{
383 RTDBGKRNLINFO hKrnlInfo;
384 int rc = RTR0DbgKrnlInfoOpen(&hKrnlInfo, 0);
385 if (RT_SUCCESS(rc))
386 {
387 /*
388 * The VMX stuff - required with raw-mode (in theory for 64-bit on
389 * 32-bit too, but we never did that on darwin).
390 */
391 int rc1 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "vmx_resume", (void **)&g_pfnVmxResume);
392 int rc2 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "vmx_suspend", (void **)&g_pfnVmxSuspend);
393 int rc3 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "vmx_use_count", (void **)&g_pVmxUseCount);
394 if (RT_SUCCESS(rc1) && RT_SUCCESS(rc2) && RT_SUCCESS(rc3))
395 {
396 LogRel(("VBoxDrv: vmx_resume=%p vmx_suspend=%p vmx_use_count=%p (%d) cr4=%#x\n",
397 g_pfnVmxResume, g_pfnVmxSuspend, g_pVmxUseCount, *g_pVmxUseCount, ASMGetCR4() ));
398 }
399 else
400 {
401 LogRel(("VBoxDrv: failed to resolve vmx stuff: vmx_resume=%Rrc vmx_suspend=%Rrc vmx_use_count=%Rrc", rc1, rc2, rc3));
402 g_pfnVmxResume = NULL;
403 g_pfnVmxSuspend = NULL;
404 g_pVmxUseCount = NULL;
405#ifdef VBOX_WITH_RAW_MODE
406 rc = VERR_SYMBOL_NOT_FOUND;
407#endif
408 }
409
410 if (RT_SUCCESS(rc))
411 {
412#ifdef SUPDRV_WITH_MSR_PROBER
413 /*
414 * MSR prober stuff - optional!
415 */
416 rc2 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "rdmsr_carefully", (void **)&g_pfnRdMsrCarefully);
417 if (RT_FAILURE(rc2))
418 g_pfnRdMsrCarefully = NULL;
419 rc2 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "rdmsr64_carefully", (void **)&g_pfnRdMsr64Carefully);
420 if (RT_FAILURE(rc2))
421 g_pfnRdMsr64Carefully = NULL;
422# ifdef RT_ARCH_AMD64 /* Missing 64 in name, so if implemented on 32-bit it could have different signature. */
423 rc2 = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, "wrmsr_carefully", (void **)&g_pfnWrMsr64Carefully);
424 if (RT_FAILURE(rc2))
425# endif
426 g_pfnWrMsr64Carefully = NULL;
427
428 LogRel(("VBoxDrv: g_pfnRdMsrCarefully=%p g_pfnRdMsr64Carefully=%p g_pfnWrMsr64Carefully=%p\n",
429 g_pfnRdMsrCarefully, g_pfnRdMsr64Carefully, g_pfnWrMsr64Carefully));
430
431#endif /* SUPDRV_WITH_MSR_PROBER */
432 }
433
434 RTR0DbgKrnlInfoRelease(hKrnlInfo);
435 }
436 else
437 LogRel(("VBoxDrv: Failed to open kernel symbols, rc=%Rrc\n", rc));
438 return rc;
439}
440
441
442#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
443
444/**
445 * Initalizes the certificate stores (code signing) in the device extension.
446 */
447static int supdrvDarwinInitCertStores(PSUPDRVDEVEXT pDevExt)
448{
449 pDevExt->hAdditionalStore = NIL_RTCRSTORE;
450
451 pDevExt->hRootStore = NIL_RTCRSTORE;
452 int rc = RTCrStoreCreateInMem(&pDevExt->hRootStore, g_cSUPTrustedTAs + 1);
453 if (RT_SUCCESS(rc))
454 {
455 for (uint32_t i = 0; i < g_cSUPTrustedTAs; i++)
456 {
457 int rc2 = RTCrStoreCertAddEncoded(pDevExt->hRootStore, RTCRCERTCTX_F_ENC_TAF_DER,
458 g_aSUPTrustedTAs[i].pch, g_aSUPTrustedTAs[i].cb, NULL);
459 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
460 {
461 printf("VBoxDrv: Error loading g_aSUPTrustedTAs[%u]: %d\n", i, rc);
462 rc = rc2;
463 }
464 }
465
466 /* We implicitly trust the build certificate. */
467 int rc2 = RTCrStoreCertAddEncoded(pDevExt->hRootStore, RTCRCERTCTX_F_ENC_X509_DER,
468 g_abSUPBuildCert, g_cbSUPBuildCert, NULL);
469 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
470 {
471 printf("VBoxDrv: Error loading g_cbSUPBuildCert: %d\n", rc);
472 rc = rc2;
473 }
474 }
475 return rc;
476}
477
478
479/**
480 * Releases the certificate stores in the device extension.
481 */
482static void supdrvDarwinDestroyCertStores(PSUPDRVDEVEXT pDevExt)
483{
484 if (pDevExt->hRootStore != NIL_RTCRSTORE)
485 {
486 uint32_t cRefs = RTCrStoreRelease(pDevExt->hRootStore);
487 Assert(cRefs == 0); RT_NOREF(cRefs);
488 pDevExt->hRootStore = NIL_RTCRSTORE;
489 }
490 if (pDevExt->hAdditionalStore != NIL_RTCRSTORE)
491 {
492 uint32_t cRefs = RTCrStoreRelease(pDevExt->hAdditionalStore);
493 Assert(cRefs == 0); RT_NOREF(cRefs);
494 pDevExt->hAdditionalStore = NIL_RTCRSTORE;
495 }
496}
497
498#endif /* VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION */
499
500/**
501 * Stop the kernel module.
502 */
503static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData)
504{
505 RT_NOREF(pKModInfo, pvData);
506 int rc;
507 LogFlow(("VBoxDrvDarwinStop\n"));
508
509 /** @todo I've got a nagging feeling that we'll have to keep track of users and refuse
510 * unloading if we're busy. Investigate and implement this! */
511
512 /*
513 * Undo the work done during start (in reverse order).
514 */
515 if (g_pSleepNotifier)
516 {
517 g_pSleepNotifier->remove();
518 g_pSleepNotifier = NULL;
519 }
520
521 devfs_remove(g_hDevFsDeviceUsr);
522 g_hDevFsDeviceUsr = NULL;
523
524 devfs_remove(g_hDevFsDeviceSys);
525 g_hDevFsDeviceSys = NULL;
526
527 rc = cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
528 Assert(rc == g_iMajorDeviceNo);
529 g_iMajorDeviceNo = -1;
530
531 supdrvDeleteDevExt(&g_DevExt);
532
533 rc = RTSpinlockDestroy(g_Spinlock);
534 AssertRC(rc);
535 g_Spinlock = NIL_RTSPINLOCK;
536
537#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
538 supdrvDarwinDestroyCertStores(&g_DevExt);
539#endif
540
541 RTR0TermForced();
542
543 memset(&g_DevExt, 0, sizeof(g_DevExt));
544#ifdef DEBUG
545 printf("VBoxDrvDarwinStop - done\n");
546#endif
547 return KMOD_RETURN_SUCCESS;
548}
549
550
551/**
552 * Device open. Called on open /dev/vboxdrv
553 *
554 * @param Dev The device number.
555 * @param fFlags ???.
556 * @param fDevType ???.
557 * @param pProcess The process issuing this request.
558 */
559static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
560{
561 RT_NOREF(fFlags, fDevType);
562#ifdef DEBUG_DARWIN_GIP
563 char szName[128];
564 szName[0] = '\0';
565 proc_name(proc_pid(pProcess), szName, sizeof(szName));
566 Log(("VBoxDrvDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
567#endif
568
569 /*
570 * Only two minor devices numbers are allowed.
571 */
572 if (minor(Dev) != 0 && minor(Dev) != 1)
573 return EACCES;
574
575 /*
576 * The process issuing the request must be the current process.
577 */
578 RTPROCESS Process = RTProcSelf();
579 if ((int)Process != proc_pid(pProcess))
580 return EIO;
581
582 /*
583 * Find the session created by org_virtualbox_SupDrvClient, fail
584 * if no such session, and mark it as opened. We set the uid & gid
585 * here too, since that is more straight forward at this point.
586 */
587 const bool fUnrestricted = minor(Dev) == 0;
588 int rc = VINF_SUCCESS;
589 PSUPDRVSESSION pSession = NULL;
590 kauth_cred_t pCred = kauth_cred_proc_ref(pProcess);
591 if (pCred)
592 {
593#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
594 RTUID Uid = kauth_cred_getruid(pCred);
595 RTGID Gid = kauth_cred_getrgid(pCred);
596#else
597 RTUID Uid = pCred->cr_ruid;
598 RTGID Gid = pCred->cr_rgid;
599#endif
600 unsigned iHash = SESSION_HASH(Process);
601 RTSpinlockAcquire(g_Spinlock);
602
603 pSession = g_apSessionHashTab[iHash];
604 while (pSession && pSession->Process != Process)
605 pSession = pSession->pNextHash;
606 if (pSession)
607 {
608 if (!pSession->fOpened)
609 {
610 pSession->fOpened = true;
611 pSession->fUnrestricted = fUnrestricted;
612 pSession->Uid = Uid;
613 pSession->Gid = Gid;
614 }
615 else
616 rc = VERR_ALREADY_LOADED;
617 }
618 else
619 rc = VERR_GENERAL_FAILURE;
620
621 RTSpinlockRelease(g_Spinlock);
622#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
623 kauth_cred_unref(&pCred);
624#else /* 10.4 */
625 /* The 10.4u SDK headers and 10.4.11 kernel source have inconsistent definitions
626 of kauth_cred_unref(), so use the other (now deprecated) API for releasing it. */
627 kauth_cred_rele(pCred);
628#endif /* 10.4 */
629 }
630 else
631 rc = VERR_INVALID_PARAMETER;
632
633#ifdef DEBUG_DARWIN_GIP
634 OSDBGPRINT(("VBoxDrvDarwinOpen: pid=%d '%s' pSession=%p rc=%d\n", proc_pid(pProcess), szName, pSession, rc));
635#else
636 Log(("VBoxDrvDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess)));
637#endif
638 return VBoxDrvDarwinErr2DarwinErr(rc);
639}
640
641
642/**
643 * Close device.
644 */
645static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
646{
647 RT_NOREF(Dev, fFlags, fDevType, pProcess);
648 Log(("VBoxDrvDarwinClose: pid=%d\n", (int)RTProcSelf()));
649 Assert(proc_pid(pProcess) == (int)RTProcSelf());
650
651 /*
652 * Hand the session closing to org_virtualbox_SupDrvClient.
653 */
654 org_virtualbox_SupDrvClient::sessionClose(RTProcSelf());
655 return 0;
656}
657
658
659/**
660 * Device I/O Control entry point.
661 *
662 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
663 * @param Dev The device number (major+minor).
664 * @param iCmd The IOCtl command.
665 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
666 * @param fFlags Flag saying we're a character device (like we didn't know already).
667 * @param pProcess The process issuing this request.
668 */
669static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
670{
671 RT_NOREF(fFlags);
672 const bool fUnrestricted = minor(Dev) == 0;
673 const RTPROCESS Process = proc_pid(pProcess);
674 const unsigned iHash = SESSION_HASH(Process);
675 PSUPDRVSESSION pSession;
676
677#ifdef VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV
678 /*
679 * Refuse all I/O control calls if we've ever detected EFLAGS.AC being cleared.
680 *
681 * This isn't a problem, as there is absolutely nothing in the kernel context that
682 * depend on user context triggering cleanups. That would be pretty wild, right?
683 */
684 if (RT_UNLIKELY(g_DevExt.cBadContextCalls > 0))
685 {
686 SUPR0Printf("VBoxDrvDarwinIOCtl: EFLAGS.AC=0 detected %u times, refusing all I/O controls!\n", g_DevExt.cBadContextCalls);
687 return EDEVERR;
688 }
689#endif
690
691 /*
692 * Find the session.
693 */
694 RTSpinlockAcquire(g_Spinlock);
695
696 pSession = g_apSessionHashTab[iHash];
697 while (pSession && (pSession->Process != Process || pSession->fUnrestricted != fUnrestricted || !pSession->fOpened))
698 pSession = pSession->pNextHash;
699
700 if (RT_LIKELY(pSession))
701 supdrvSessionRetain(pSession);
702
703 RTSpinlockRelease(g_Spinlock);
704 if (RT_UNLIKELY(!pSession))
705 {
706 OSDBGPRINT(("VBoxDrvDarwinIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#lx\n",
707 (int)Process, iCmd));
708 return EINVAL;
709 }
710
711 /*
712 * Deal with the two high-speed IOCtl that takes it's arguments from
713 * the session and iCmd, and only returns a VBox status code.
714 */
715 int rc;
716 AssertCompile((SUP_IOCTL_FAST_DO_FIRST & 0xff) == (SUP_IOCTL_FLAG | 64));
717 if ( (uintptr_t)(iCmd - SUP_IOCTL_FAST_DO_FIRST) < (uintptr_t)32
718 && fUnrestricted)
719 rc = supdrvIOCtlFast(iCmd - SUP_IOCTL_FAST_DO_FIRST, *(uint32_t *)pData, &g_DevExt, pSession);
720 else
721 rc = VBoxDrvDarwinIOCtlSlow(pSession, iCmd, pData, pProcess);
722
723 supdrvSessionRelease(pSession);
724 return rc;
725}
726
727
728/**
729 * Alternative Device I/O Control entry point on hosts with SMAP support.
730 *
731 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
732 * @param Dev The device number (major+minor).
733 * @param iCmd The IOCtl command.
734 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
735 * @param fFlags Flag saying we're a character device (like we didn't know already).
736 * @param pProcess The process issuing this request.
737 */
738static int VBoxDrvDarwinIOCtlSMAP(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
739{
740 /*
741 * Allow VBox R0 code to touch R3 memory. Setting the AC bit disables the
742 * SMAP check.
743 */
744 RTCCUINTREG fSavedEfl = ASMAddFlags(X86_EFL_AC);
745
746 int rc = VBoxDrvDarwinIOCtl(Dev, iCmd, pData, fFlags, pProcess);
747
748#if defined(VBOX_STRICT) || defined(VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV)
749 /*
750 * Before we restore AC and the rest of EFLAGS, check if the IOCtl handler code
751 * accidentially modified it or some other important flag.
752 */
753 if (RT_UNLIKELY( (ASMGetFlags() & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF | X86_EFL_IOPL))
754 != ((fSavedEfl & (X86_EFL_AC | X86_EFL_IF | X86_EFL_DF | X86_EFL_IOPL)) | X86_EFL_AC) ))
755 {
756 char szTmp[48];
757 RTStrPrintf(szTmp, sizeof(szTmp), "iCmd=%#x: %#x->%#x!", iCmd, (uint32_t)fSavedEfl, (uint32_t)ASMGetFlags());
758 supdrvBadContext(&g_DevExt, "SUPDrv-darwin.cpp", __LINE__, szTmp);
759 }
760#endif
761
762 ASMSetFlags(fSavedEfl);
763 return rc;
764}
765
766
767/**
768 * Worker for VBoxDrvDarwinIOCtl that takes the slow IOCtl functions.
769 *
770 * @returns Darwin errno.
771 *
772 * @param pSession The session.
773 * @param iCmd The IOCtl command.
774 * @param pData Pointer to the kernel copy of the SUPDRVIOCTLDATA buffer.
775 * @param pProcess The calling process.
776 */
777static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
778{
779 RT_NOREF(pProcess);
780 LogFlow(("VBoxDrvDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));
781
782
783 /*
784 * Buffered or unbuffered?
785 */
786 PSUPREQHDR pHdr;
787 user_addr_t pUser = 0;
788 void *pvPageBuf = NULL;
789 uint32_t cbReq = IOCPARM_LEN(iCmd);
790 if ((IOC_DIRMASK & iCmd) == IOC_INOUT)
791 {
792 pHdr = (PSUPREQHDR)pData;
793 if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
794 {
795 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: cbReq=%#x < %#x; iCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), iCmd));
796 return EINVAL;
797 }
798 if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
799 {
800 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", pHdr->fFlags, iCmd));
801 return EINVAL;
802 }
803 if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
804 || pHdr->cbIn < sizeof(*pHdr)
805 || pHdr->cbOut < sizeof(*pHdr)))
806 {
807 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x) != %#x; iCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, iCmd));
808 return EINVAL;
809 }
810 }
811 else if ((IOC_DIRMASK & iCmd) == IOC_VOID && !cbReq)
812 {
813 /*
814 * Get the header and figure out how much we're gonna have to read.
815 */
816 IPRT_DARWIN_SAVE_EFL_AC();
817 SUPREQHDR Hdr;
818 pUser = (user_addr_t)*(void **)pData;
819 int rc = copyin(pUser, &Hdr, sizeof(Hdr));
820 if (RT_UNLIKELY(rc))
821 {
822 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
823 IPRT_DARWIN_RESTORE_EFL_AC();
824 return rc;
825 }
826 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
827 {
828 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", Hdr.fFlags, iCmd));
829 IPRT_DARWIN_RESTORE_EFL_AC();
830 return EINVAL;
831 }
832 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
833 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
834 || Hdr.cbOut < sizeof(Hdr)
835 || cbReq > _1M*16))
836 {
837 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x); iCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, iCmd));
838 IPRT_DARWIN_RESTORE_EFL_AC();
839 return EINVAL;
840 }
841
842 /*
843 * Allocate buffer and copy in the data.
844 */
845 pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
846 if (!pHdr)
847 pvPageBuf = pHdr = (PSUPREQHDR)IOMallocAligned(RT_ALIGN_Z(cbReq, PAGE_SIZE), 8);
848 if (RT_UNLIKELY(!pHdr))
849 {
850 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
851 IPRT_DARWIN_RESTORE_EFL_AC();
852 return ENOMEM;
853 }
854 rc = copyin(pUser, pHdr, Hdr.cbIn);
855 if (RT_UNLIKELY(rc))
856 {
857 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,%p,%#x) -> %#x; iCmd=%#lx\n",
858 (unsigned long long)pUser, pHdr, Hdr.cbIn, rc, iCmd));
859 if (pvPageBuf)
860 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
861 else
862 RTMemTmpFree(pHdr);
863 IPRT_DARWIN_RESTORE_EFL_AC();
864 return rc;
865 }
866 if (Hdr.cbIn < cbReq)
867 RT_BZERO((uint8_t *)pHdr + Hdr.cbIn, cbReq - Hdr.cbIn);
868 IPRT_DARWIN_RESTORE_EFL_AC();
869 }
870 else
871 {
872 Log(("VBoxDrvDarwinIOCtlSlow: huh? cbReq=%#x iCmd=%#lx\n", cbReq, iCmd));
873 return EINVAL;
874 }
875
876 /*
877 * Process the IOCtl.
878 */
879 int rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr, cbReq);
880 if (RT_LIKELY(!rc))
881 {
882 /*
883 * If not buffered, copy back the buffer before returning.
884 */
885 if (pUser)
886 {
887 IPRT_DARWIN_SAVE_EFL_AC();
888 uint32_t cbOut = pHdr->cbOut;
889 if (cbOut > cbReq)
890 {
891 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, iCmd));
892 cbOut = cbReq;
893 }
894 rc = copyout(pHdr, pUser, cbOut);
895 if (RT_UNLIKELY(rc))
896 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyout(%p,%llx,%#x) -> %d; uCmd=%#lx!\n",
897 pHdr, (unsigned long long)pUser, cbOut, rc, iCmd));
898
899 /* cleanup */
900 if (pvPageBuf)
901 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
902 else
903 RTMemTmpFree(pHdr);
904 IPRT_DARWIN_RESTORE_EFL_AC();
905 }
906 }
907 else
908 {
909 /*
910 * The request failed, just clean up.
911 */
912 if (pUser)
913 {
914 if (pvPageBuf)
915 {
916 IPRT_DARWIN_SAVE_EFL_AC();
917 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
918 IPRT_DARWIN_RESTORE_EFL_AC();
919 }
920 else
921 RTMemTmpFree(pHdr);
922 }
923
924 Log(("VBoxDrvDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
925 rc = EINVAL;
926 }
927
928 Log2(("VBoxDrvDarwinIOCtlSlow: returns %d\n", rc));
929 return rc;
930}
931
932
933/**
934 * The SUPDRV IDC entry point.
935 *
936 * @returns VBox status code, see supdrvIDC.
937 * @param uReq The request code.
938 * @param pReq The request.
939 */
940DECLEXPORT(int) VBOXCALL SUPDrvDarwinIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
941{
942 PSUPDRVSESSION pSession;
943
944 /*
945 * Some quick validations.
946 */
947 if (RT_UNLIKELY(!VALID_PTR(pReq)))
948 return VERR_INVALID_POINTER;
949
950 pSession = pReq->pSession;
951 if (pSession)
952 {
953 if (RT_UNLIKELY(!VALID_PTR(pSession)))
954 return VERR_INVALID_PARAMETER;
955 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
956 return VERR_INVALID_PARAMETER;
957 }
958 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
959 return VERR_INVALID_PARAMETER;
960
961 /*
962 * Do the job.
963 */
964 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
965}
966
967
968void VBOXCALL supdrvOSCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
969{
970 NOREF(pDevExt);
971 NOREF(pSession);
972}
973
974
975void VBOXCALL supdrvOSSessionHashTabInserted(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
976{
977 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
978}
979
980
981void VBOXCALL supdrvOSSessionHashTabRemoved(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, void *pvUser)
982{
983 NOREF(pDevExt); NOREF(pSession); NOREF(pvUser);
984}
985
986
987/**
988 * Initializes any OS specific object creator fields.
989 */
990void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
991{
992 NOREF(pObj);
993 NOREF(pSession);
994}
995
996
997/**
998 * Checks if the session can access the object.
999 *
1000 * @returns true if a decision has been made.
1001 * @returns false if the default access policy should be applied.
1002 *
1003 * @param pObj The object in question.
1004 * @param pSession The session wanting to access the object.
1005 * @param pszObjName The object name, can be NULL.
1006 * @param prc Where to store the result when returning true.
1007 */
1008bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
1009{
1010 NOREF(pObj);
1011 NOREF(pSession);
1012 NOREF(pszObjName);
1013 NOREF(prc);
1014 return false;
1015}
1016
1017/**
1018 * Callback for blah blah blah.
1019 */
1020IOReturn VBoxDrvDarwinSleepHandler(void * /* pvTarget */, void *pvRefCon, UInt32 uMessageType,
1021 IOService *pProvider, void *pvMsgArg, vm_size_t cbMsgArg)
1022{
1023 RT_NOREF(pProvider, pvMsgArg, cbMsgArg);
1024 LogFlow(("VBoxDrv: Got sleep/wake notice. Message type was %x\n", uMessageType));
1025
1026 if (uMessageType == kIOMessageSystemWillSleep)
1027 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
1028 else if (uMessageType == kIOMessageSystemHasPoweredOn)
1029 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
1030
1031 acknowledgeSleepWakeNotification(pvRefCon);
1032
1033 return 0;
1034}
1035
1036
1037#ifdef VBOX_WITH_HOST_VMX
1038/**
1039 * For cleaning up the mess we left behind on Yosemite with 4.3.28 and earlier.
1040 *
1041 * We ASSUME VT-x is supported by the CPU.
1042 *
1043 * @param idCpu Unused.
1044 * @param pvUser1 Unused.
1045 * @param pvUser2 Unused.
1046 */
1047static DECLCALLBACK(void) vboxdrvDarwinVmxEnableFix(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1048{
1049 RT_NOREF(idCpu, pvUser1, pvUser2);
1050 RTCCUINTREG uCr4 = ASMGetCR4();
1051 if (!(uCr4 & X86_CR4_VMXE))
1052 {
1053 uCr4 |= X86_CR4_VMXE;
1054 ASMSetCR4(uCr4);
1055 }
1056}
1057#endif
1058
1059
1060/**
1061 * @copydoc SUPR0EnableVTx
1062 */
1063int VBOXCALL supdrvOSEnableVTx(bool fEnable)
1064{
1065#ifdef VBOX_WITH_HOST_VMX
1066 int rc;
1067 if ( version_major >= 10 /* 10 = 10.6.x = Snow Leopard */
1068# ifdef VBOX_WITH_RAW_MODE
1069 && g_pfnVmxSuspend
1070 && g_pfnVmxResume
1071 && g_pVmxUseCount
1072# endif
1073 )
1074 {
1075 IPRT_DARWIN_SAVE_EFL_AC();
1076 if (fEnable)
1077 {
1078 /*
1079 * We screwed up on Yosemite and didn't notice that we weren't
1080 * calling host_vmxon. CR4.VMXE may therefore have been disabled
1081 * by us. So, first time around we make sure it's set so we won't
1082 * crash in the pre-4.3.28/5.0RC1 upgrade scenario.
1083 * See @bugref{7907}.
1084 */
1085 static bool volatile g_fDoneCleanup = false;
1086 if (!g_fDoneCleanup)
1087 {
1088 if (version_major == 14 /* 14 = 10.10 = yosemite */)
1089 {
1090 uint32_t fCaps;
1091 rc = supdrvQueryVTCapsInternal(&fCaps);
1092 if (RT_SUCCESS(rc))
1093 {
1094 if (fCaps & SUPVTCAPS_VT_X)
1095 rc = RTMpOnAll(vboxdrvDarwinVmxEnableFix, NULL, NULL);
1096 else
1097 rc = VERR_VMX_NO_VMX;
1098 }
1099 if (RT_FAILURE(rc))
1100 {
1101 IPRT_DARWIN_RESTORE_EFL_AC();
1102 return rc;
1103 }
1104 }
1105 g_fDoneCleanup = true;
1106 }
1107
1108 /*
1109 * Call the kernel.
1110 */
1111 AssertLogRelMsg(!g_pVmxUseCount || *g_pVmxUseCount >= 0,
1112 ("vmx_use_count=%d (@ %p, expected it to be a positive number\n",
1113 *g_pVmxUseCount, g_pVmxUseCount));
1114
1115 rc = host_vmxon(false /* exclusive */);
1116 if (rc == VMX_OK)
1117 rc = VINF_SUCCESS;
1118 else if (rc == VMX_UNSUPPORTED)
1119 rc = VERR_VMX_NO_VMX;
1120 else if (rc == VMX_INUSE)
1121 rc = VERR_VMX_IN_VMX_ROOT_MODE;
1122 else /* shouldn't happen, but just in case. */
1123 {
1124 LogRel(("host_vmxon returned %d\n", rc));
1125 rc = VERR_UNRESOLVED_ERROR;
1126 }
1127 LogRel(("VBoxDrv: host_vmxon -> vmx_use_count=%d rc=%Rrc\n", *g_pVmxUseCount, rc));
1128 }
1129 else
1130 {
1131 AssertLogRelMsgReturn(!g_pVmxUseCount || *g_pVmxUseCount >= 1,
1132 ("vmx_use_count=%d (@ %p, expected it to be a non-zero positive number\n",
1133 *g_pVmxUseCount, g_pVmxUseCount),
1134 VERR_WRONG_ORDER);
1135 host_vmxoff();
1136 rc = VINF_SUCCESS;
1137 LogRel(("VBoxDrv: host_vmxoff -> vmx_use_count=%d\n", *g_pVmxUseCount));
1138 }
1139 IPRT_DARWIN_RESTORE_EFL_AC();
1140 }
1141 else
1142 {
1143 /* In 10.5.x the host_vmxon is severely broken! Don't use it, it will
1144 frequnetly panic the host. */
1145 rc = VERR_NOT_SUPPORTED;
1146 }
1147 return rc;
1148#else
1149 return VERR_NOT_SUPPORTED;
1150#endif
1151}
1152
1153
1154/**
1155 * @copydoc SUPR0SuspendVTxOnCpu
1156 */
1157bool VBOXCALL supdrvOSSuspendVTxOnCpu(void)
1158{
1159#ifdef VBOX_WITH_HOST_VMX
1160 /*
1161 * Consult the VMX usage counter, don't try suspend if not enabled.
1162 *
1163 * Note! The host_vmxon/off code is still race prone since, but this is
1164 * currently the best we can do without always enable VMX when
1165 * loading the driver.
1166 */
1167 if ( g_pVmxUseCount
1168 && *g_pVmxUseCount > 0)
1169 {
1170 IPRT_DARWIN_SAVE_EFL_AC();
1171 g_pfnVmxSuspend();
1172 IPRT_DARWIN_RESTORE_EFL_AC();
1173 return true;
1174 }
1175 return false;
1176#else
1177 return false;
1178#endif
1179}
1180
1181
1182/**
1183 * @copydoc SUPR0ResumeVTxOnCpu
1184 */
1185void VBOXCALL supdrvOSResumeVTxOnCpu(bool fSuspended)
1186{
1187#ifdef VBOX_WITH_HOST_VMX
1188 /*
1189 * Don't consult the counter here, the state knows better.
1190 * We're executing with interrupts disabled and anyone racing us with
1191 * disabling VT-x will be waiting in the rendezvous code.
1192 */
1193 if ( fSuspended
1194 && g_pfnVmxResume)
1195 {
1196 IPRT_DARWIN_SAVE_EFL_AC();
1197 g_pfnVmxResume();
1198 IPRT_DARWIN_RESTORE_EFL_AC();
1199 }
1200 else
1201 Assert(!fSuspended);
1202#else
1203 Assert(!fSuspended);
1204#endif
1205}
1206
1207
1208bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
1209{
1210 NOREF(pDevExt);
1211 return false;
1212}
1213
1214
1215bool VBOXCALL supdrvOSAreCpusOfflinedOnSuspend(void)
1216{
1217 /** @todo verify this. */
1218 return false;
1219}
1220
1221
1222bool VBOXCALL supdrvOSAreTscDeltasInSync(void)
1223{
1224 return false;
1225}
1226
1227
1228#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1229
1230/**
1231 * @callback_method_impl{FNRTLDRIMPORT}
1232 */
1233static DECLCALLBACK(int) supdrvDarwinLdrOpenImportCallback(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
1234 unsigned uSymbol, PRTLDRADDR pValue, void *pvUser)
1235{
1236 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
1237
1238 /*
1239 * First consult the VMMR0 module if there is one fully loaded.
1240 * This is necessary as VMMR0 may overload assertion and logger symbols.
1241 */
1242 if (pDevExt->pvVMMR0)
1243 for (PSUPDRVLDRIMAGE pImage = pDevExt->pLdrImages; pImage; pImage = pImage->pNext)
1244 if (pImage->pvImage == pDevExt->pvVMMR0)
1245 {
1246 if ( pImage->uState == SUP_IOCTL_LDR_LOAD
1247 && pImage->hLdrMod != NIL_RTLDRMOD)
1248 {
1249 int rc = RTLdrGetSymbolEx(pImage->hLdrMod, pImage->pvImage, (uintptr_t)pImage->pvImage,
1250 UINT32_MAX, pszSymbol, pValue);
1251 if (RT_SUCCESS(rc))
1252 return VINF_SUCCESS;
1253 }
1254 break;
1255 }
1256
1257 /*
1258 * Then we consult the SUPDrv export table.
1259 */
1260 uintptr_t uValue = 0;
1261 int rc = supdrvLdrGetExportedSymbol(pszSymbol, &uValue);
1262 if (RT_SUCCESS(rc))
1263 {
1264 *pValue = uValue;
1265 return VINF_SUCCESS;
1266 }
1267
1268 /*
1269 * Failed.
1270 */
1271 printf("VBoxDrv: Unable to resolve symbol '%s'.\n", pszSymbol);
1272 RT_NOREF(hLdrMod, pszModule, uSymbol);
1273 return VERR_SYMBOL_NOT_FOUND;
1274}
1275
1276
1277/**
1278 * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK,
1279 * Verify that the signing certificate is sane.}
1280 */
1281static DECLCALLBACK(int) supdrvDarwinLdrOpenVerifyCertificatCallback(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths,
1282 uint32_t fFlags, void *pvUser, PRTERRINFO pErrInfo)
1283{
1284 RT_NOREF(pvUser); //PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
1285# ifdef DEBUG_bird
1286 printf("supdrvDarwinLdrOpenVerifyCertificatCallback: pCert=%p hCertPaths=%p\n", pCert, hCertPaths);
1287# endif
1288
1289# if 0
1290 /*
1291 * Test signing certificates normally doesn't have all the necessary
1292 * features required below. So, treat them as special cases.
1293 */
1294 if ( hCertPaths == NIL_RTCRX509CERTPATHS
1295 && RTCrX509Name_Compare(&pCert->TbsCertificate.Issuer, &pCert->TbsCertificate.Subject) == 0)
1296 {
1297 RTMsgInfo("Test signed.\n");
1298 return VINF_SUCCESS;
1299 }
1300# endif
1301
1302 /*
1303 * Standard code signing capabilites required.
1304 */
1305 int rc = RTCrPkcs7VerifyCertCallbackCodeSigning(pCert, hCertPaths, fFlags, NULL, pErrInfo);
1306 if ( RT_SUCCESS(rc)
1307 && (fFlags & RTCRPKCS7VCC_F_SIGNED_DATA))
1308 {
1309 uint32_t cDevIdApp = 0;
1310 uint32_t cDevIdKext = 0;
1311 for (uint32_t i = 0; i < pCert->TbsCertificate.T3.Extensions.cItems; i++)
1312 {
1313 PCRTCRX509EXTENSION pExt = pCert->TbsCertificate.T3.Extensions.papItems[i];
1314 if (RTAsn1ObjId_CompareWithString(&pExt->ExtnId, RTCR_APPLE_CS_DEVID_APPLICATION_OID) == 0)
1315 {
1316 cDevIdApp++;
1317 if (!pExt->Critical.fValue)
1318 rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
1319 "Dev ID Application certificate extension is not flagged critical");
1320 }
1321 else if (RTAsn1ObjId_CompareWithString(&pExt->ExtnId, RTCR_APPLE_CS_DEVID_KEXT_OID) == 0)
1322 {
1323 cDevIdKext++;
1324 if (!pExt->Critical.fValue)
1325 rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
1326 "Dev ID kext certificate extension is not flagged critical");
1327 }
1328 }
1329 if (cDevIdApp == 0)
1330 rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
1331 "Certificate is missing the 'Dev ID Application' extension");
1332 if (cDevIdKext == 0)
1333 rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
1334 "Certificate is missing the 'Dev ID kext' extension");
1335 }
1336
1337 return rc;
1338}
1339
1340
1341/**
1342 * @callback_method_impl{FNRTLDRVALIDATESIGNEDDATA}
1343 */
1344static DECLCALLBACK(int) supdrvDarwinLdrOpenVerifyCallback(RTLDRMOD hLdrMod, RTLDRSIGNATURETYPE enmSignature,
1345 void const *pvSignature, size_t cbSignature,
1346 void const *pvExternalData, size_t cbExternalData,
1347 PRTERRINFO pErrInfo, void *pvUser)
1348{
1349 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser;
1350 RT_NOREF_PV(hLdrMod); RT_NOREF_PV(cbSignature);
1351
1352 switch (enmSignature)
1353 {
1354 case RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA:
1355 if (pvExternalData)
1356 {
1357 PCRTCRPKCS7CONTENTINFO pContentInfo = (PCRTCRPKCS7CONTENTINFO)pvSignature;
1358 RTTIMESPEC ValidationTime;
1359 RTTimeNow(&ValidationTime);
1360
1361 return RTCrPkcs7VerifySignedDataWithExternalData(pContentInfo,
1362 RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY
1363 | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT
1364 | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT,
1365 pDevExt->hAdditionalStore, pDevExt->hRootStore, &ValidationTime,
1366 supdrvDarwinLdrOpenVerifyCertificatCallback, pDevExt,
1367 pvExternalData, cbExternalData, pErrInfo);
1368 }
1369 return RTErrInfoSetF(pErrInfo, VERR_NOT_SUPPORTED, "Expected external data with signature!");
1370
1371 default:
1372 return RTErrInfoSetF(pErrInfo, VERR_NOT_SUPPORTED, "Unsupported signature type: %d", enmSignature);
1373 }
1374}
1375
1376#endif /* VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION */
1377
1378int VBOXCALL supdrvOSLdrOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1379{
1380#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1381 /*
1382 * Initialize our members.
1383 */
1384 pImage->hLdrMod = NIL_RTLDRMOD;
1385 pImage->hMemAlloc = NIL_RTR0MEMOBJ;
1386
1387 /*
1388 * We have to double buffer the file to be avoid a potential race between
1389 * validation and actual image loading. This could be eliminated later by
1390 * baking the image validation into the RTLdrGetBits operation.
1391 *
1392 * Note! After calling RTLdrOpenInMemory, pvFile is owned by the loader and will be
1393 * freed via the RTFileReadAllFree callback when the loader module is closed.
1394 */
1395 void *pvFile = NULL;
1396 size_t cbFile = 0;
1397 int rc = RTFileReadAllEx(pszFilename, 0, _32M, RTFILE_RDALL_O_DENY_WRITE, &pvFile, &cbFile);
1398 if (RT_SUCCESS(rc))
1399 {
1400 PRTERRINFOSTATIC pErrInfo = (PRTERRINFOSTATIC)RTMemTmpAlloc(sizeof(RTERRINFOSTATIC));
1401 RTLDRMOD hLdrMod = NIL_RTLDRMOD;
1402 rc = RTLdrOpenInMemory(pszFilename, 0 /*fFlags*/, RTLDRARCH_HOST, cbFile,
1403 NULL /*pfnRead*/, RTFileReadAllFree, pvFile,
1404 &hLdrMod, pErrInfo ? RTErrInfoInitStatic(pErrInfo) : NULL);
1405 if (RT_SUCCESS(rc))
1406 {
1407 /*
1408 * Validate the image.
1409 */
1410 rc = RTLdrVerifySignature(hLdrMod, supdrvDarwinLdrOpenVerifyCallback, pDevExt,
1411 pErrInfo ? RTErrInfoInitStatic(pErrInfo) : NULL);
1412 if (RT_SUCCESS(rc))
1413 {
1414 /*
1415 * Allocate memory for the object and load it into it.
1416 */
1417 size_t cbImage = RTLdrSize(hLdrMod);
1418 if (cbImage == pImage->cbImageBits)
1419 {
1420 RTR0MEMOBJ hMemAlloc;
1421 rc = RTR0MemObjAllocPage(&hMemAlloc, cbImage, true /*fExecutable*/);
1422 if (RT_SUCCESS(rc))
1423 {
1424 void *pvImageBits = RTR0MemObjAddress(hMemAlloc);
1425 rc = RTLdrGetBits(hLdrMod, pvImageBits, (uintptr_t)pvImageBits,
1426 supdrvDarwinLdrOpenImportCallback, pDevExt);
1427 if (RT_SUCCESS(rc))
1428 {
1429 /*
1430 * Commit.
1431 */
1432 pImage->hMemAlloc = hMemAlloc;
1433 pImage->hLdrMod = hLdrMod;
1434 pImage->pvImage = pvImageBits;
1435 RTMemTmpFree(pErrInfo);
1436 /** @todo Call RTLdrDone. */
1437 return VINF_SUCCESS;
1438 }
1439
1440 RTR0MemObjFree(hMemAlloc, true /*fFreeMappings*/);
1441 }
1442 else
1443 printf("VBoxDrv: Failed to allocate %u bytes for %s: %d\n", (unsigned)cbImage, pszFilename, rc);
1444 }
1445 else
1446 {
1447 printf("VBoxDrv: Image size mismatch for %s: %#x, ring-3 says %#x\n",
1448 pszFilename, (unsigned)cbImage, (unsigned)pImage->cbImageBits);
1449 rc = VERR_LDR_MISMATCH_NATIVE;
1450 }
1451 }
1452 else if (pErrInfo && RTErrInfoIsSet(&pErrInfo->Core))
1453 printf("VBoxDrv: RTLdrOpenInMemory(%s) failed: %d - %s\n", pszFilename, rc, pErrInfo->Core.pszMsg);
1454 else
1455 printf("VBoxDrv: RTLdrOpenInMemory(%s) failed: %d\n", pszFilename, rc);
1456 RTLdrClose(hLdrMod);
1457 }
1458 else if (pErrInfo && RTErrInfoIsSet(&pErrInfo->Core))
1459 printf("VBoxDrv: RTLdrOpenInMemory(%s) failed: %d - %s\n", pszFilename, rc, pErrInfo->Core.pszMsg);
1460 else
1461 printf("VBoxDrv: RTLdrOpenInMemory(%s) failed: %d\n", pszFilename, rc);
1462 RTMemTmpFree(pErrInfo);
1463 }
1464 return rc;
1465#else /* !VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION */
1466 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
1467 return VERR_NOT_SUPPORTED;
1468#endif /* !VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION */
1469}
1470
1471
1472#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1473/**
1474 * @callback_method_impl{FNRTLDRENUMSYMS,
1475 * Worker for supdrvOSLdrValidatePointer.
1476 */
1477static DECLCALLBACK(int) supdrvDarwinLdrValidatePointerCallback(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol,
1478 RTLDRADDR Value, void *pvUser)
1479{
1480 RT_NOREF(hLdrMod, pszSymbol, uSymbol);
1481 if (Value == (uintptr_t)pvUser)
1482 return VINF_CALLBACK_RETURN;
1483 return VINF_SUCCESS;
1484}
1485#endif
1486
1487
1488int VBOXCALL supdrvOSLdrValidatePointer(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, void *pv,
1489 const uint8_t *pbImageBits, const char *pszSymbol)
1490{
1491#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1492 AssertReturn(pImage->hLdrMod != NIL_RTLDRMOD, VERR_INVALID_STATE);
1493
1494 /*
1495 * If we've got a symbol name, just to a lookup and compare addresses.
1496 */
1497 int rc;
1498 if (RT_C_IS_UPPER(*pszSymbol))
1499 {
1500 RTLDRADDR uValueFound;
1501 rc = RTLdrGetSymbolEx(pImage->hLdrMod, pImage->pvImage, (uintptr_t)pImage->pvImage, UINT32_MAX, pszSymbol, &uValueFound);
1502 if (RT_SUCCESS(rc))
1503 {
1504 if (uValueFound == (uintptr_t)pv)
1505 rc = VINF_SUCCESS;
1506 else
1507 {
1508 SUPR0Printf("SUPDrv: Different exports found for %s in %s: %RTptr, expected %p\n",
1509 pszSymbol, pImage->szName, (RTUINTPTR)uValueFound, pv);
1510 rc = VERR_LDR_BAD_FIXUP;
1511 }
1512 }
1513 else
1514 SUPR0Printf("SUPDrv: No export named %s (%p) in %s!\n", pszSymbol, pv, pImage->szName);
1515 }
1516 /*
1517 * Otherwise do a symbol enumeration and look for the entrypoint.
1518 */
1519 else
1520 {
1521 rc = RTLdrEnumSymbols(pImage->hLdrMod, 0 /*fFlags*/, pImage->pvImage, (uintptr_t)pImage->pvImage,
1522 supdrvDarwinLdrValidatePointerCallback, pv);
1523 if (rc == VINF_CALLBACK_RETURN)
1524 rc = VINF_SUCCESS;
1525 else if (RT_SUCCESS(rc))
1526 {
1527 SUPR0Printf("SUPDrv: No export with address %p (%s) in %s!\n", pv, pszSymbol, pImage->szName);
1528 rc = VERR_NOT_FOUND;
1529 }
1530 else
1531 SUPR0Printf("SUPDrv: RTLdrEnumSymbols failed on %s: %Rrc\n", pImage->szName, rc);
1532 }
1533 RT_NOREF(pDevExt, pbImageBits);
1534 return rc;
1535#else
1536 NOREF(pDevExt); NOREF(pImage); NOREF(pv); NOREF(pbImageBits); NOREF(pszSymbol);
1537 return VERR_NOT_SUPPORTED;
1538#endif
1539}
1540
1541
1542int VBOXCALL supdrvOSLdrQuerySymbol(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage,
1543 const char *pszSymbol, size_t cchSymbol, void **ppvSymbol)
1544{
1545#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1546 /*
1547 * Just hand the problem to RTLdrGetSymbolEx.
1548 */
1549 RTLDRADDR uValueFound;
1550 int rc = RTLdrGetSymbolEx(pImage->hLdrMod, pImage->pvImage, (uintptr_t)pImage->pvImage, UINT32_MAX, pszSymbol, &uValueFound);
1551 if (RT_SUCCESS(rc))
1552 {
1553 *ppvSymbol = (void *)(uintptr_t)uValueFound;
1554 return VINF_SUCCESS;
1555 }
1556 RT_NOREF(pDevExt, cchSymbol);
1557 return rc;
1558
1559#else
1560 RT_NOREF(pDevExt, pImage, pszSymbol, cchSymbol, ppvSymbol);
1561 return VERR_WRONG_ORDER;
1562#endif
1563}
1564
1565
1566int VBOXCALL supdrvOSLdrLoad(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const uint8_t *pbImageBits, PSUPLDRLOAD pReq)
1567{
1568#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1569 /* State paranoia. */
1570 AssertReturn(pImage->hLdrMod != NIL_RTLDRMOD, VERR_INVALID_STATE);
1571 AssertReturn(pImage->hMemAlloc != NIL_RTR0MEMOBJ, VERR_INVALID_STATE);
1572 AssertReturn(pImage->pvImage, VERR_INVALID_STATE);
1573
1574 /*
1575 * We should get an identical match with ring-3 here, so the code here is
1576 * trivial in comparision to SUPDrv-win.cpp.
1577 */
1578 if (!memcmp(pImage->pvImage, pbImageBits, pImage->cbImageBits))
1579 return VINF_SUCCESS;
1580
1581 /*
1582 * Try show what when wrong (code is copied from supdrvNtCompare).
1583 */
1584 uint32_t cbLeft = pImage->cbImageBits;
1585 const uint8_t *pbNativeBits = (const uint8_t *)pImage->pvImage;
1586 for (size_t off = 0; cbLeft > 0; off++, cbLeft--)
1587 if (pbNativeBits[off] != pbImageBits[off])
1588 {
1589 /* Note! We need to copy image bits into a temporary stack buffer here as we'd
1590 otherwise risk overwriting them while formatting the error message. */
1591 uint8_t abBytes[64];
1592 memcpy(abBytes, &pbImageBits[off], RT_MIN(64, cbLeft));
1593 supdrvLdrLoadError(VERR_LDR_MISMATCH_NATIVE, pReq,
1594 "Mismatch at %#x (%p) of %s loaded at %p:\n"
1595 "ring-0: %.*Rhxs\n"
1596 "ring-3: %.*Rhxs",
1597 off, &pbNativeBits[off], pImage->szName, pImage->pvImage,
1598 RT_MIN(64, cbLeft), &pbNativeBits[off],
1599 RT_MIN(64, cbLeft), &abBytes[0]);
1600 printf("SUPDrv: %s\n", pReq->u.Out.szError);
1601 break;
1602 }
1603
1604 RT_NOREF(pDevExt);
1605 return VERR_LDR_MISMATCH_NATIVE;
1606
1607#else
1608 NOREF(pDevExt); NOREF(pImage); NOREF(pbImageBits); NOREF(pReq);
1609 return VERR_NOT_SUPPORTED;
1610#endif
1611}
1612
1613
1614void VBOXCALL supdrvOSLdrUnload(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1615{
1616#ifdef VBOX_WITH_DARWIN_R0_DARWIN_IMAGE_VERIFICATION
1617 if (pImage->hLdrMod != NIL_RTLDRMOD)
1618 {
1619 int rc = RTLdrClose(pImage->hLdrMod);
1620 AssertRC(rc);
1621 pImage->hLdrMod = NIL_RTLDRMOD;
1622 }
1623 if (pImage->hMemAlloc != NIL_RTR0MEMOBJ)
1624 {
1625 RTR0MemObjFree(pImage->hMemAlloc, true /*fFreeMappings*/);
1626 pImage->hMemAlloc = NIL_RTR0MEMOBJ;
1627 }
1628 NOREF(pDevExt);
1629#else
1630 NOREF(pDevExt); NOREF(pImage);
1631#endif
1632}
1633
1634
1635void VBOXCALL supdrvOSLdrNotifyLoaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1636{
1637 NOREF(pDevExt); NOREF(pImage);
1638}
1639
1640
1641void VBOXCALL supdrvOSLdrNotifyOpened(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage, const char *pszFilename)
1642{
1643#if 1
1644 NOREF(pDevExt); NOREF(pImage); NOREF(pszFilename);
1645#else
1646 /*
1647 * Try store the image load address in NVRAM so we can retrived it on panic.
1648 * Note! This only works if you're root! - Acutally, it doesn't work at all at the moment. FIXME!
1649 */
1650 IORegistryEntry *pEntry = IORegistryEntry::fromPath("/options", gIODTPlane);
1651 if (pEntry)
1652 {
1653 char szVar[80];
1654 RTStrPrintf(szVar, sizeof(szVar), "vboximage"/*-%s*/, pImage->szName);
1655 char szValue[48];
1656 RTStrPrintf(szValue, sizeof(szValue), "%#llx,%#llx", (uint64_t)(uintptr_t)pImage->pvImage,
1657 (uint64_t)(uintptr_t)pImage->pvImage + pImage->cbImageBits - 1);
1658 bool fRc = pEntry->setProperty(szVar, szValue); NOREF(fRc);
1659 pEntry->release();
1660 SUPR0Printf("fRc=%d '%s'='%s'\n", fRc, szVar, szValue);
1661 }
1662 /*else
1663 SUPR0Printf("failed to find /options in gIODTPlane\n");*/
1664#endif
1665}
1666
1667
1668void VBOXCALL supdrvOSLdrNotifyUnloaded(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1669{
1670 NOREF(pDevExt); NOREF(pImage);
1671}
1672
1673
1674#ifdef SUPDRV_WITH_MSR_PROBER
1675
1676typedef struct SUPDRVDARWINMSRARGS
1677{
1678 RTUINT64U uValue;
1679 uint32_t uMsr;
1680 int rc;
1681} SUPDRVDARWINMSRARGS, *PSUPDRVDARWINMSRARGS;
1682
1683/**
1684 * On CPU worker for supdrvOSMsrProberRead.
1685 *
1686 * @param idCpu Ignored.
1687 * @param pvUser1 Pointer to a SUPDRVDARWINMSRARGS.
1688 * @param pvUser2 Ignored.
1689 */
1690static DECLCALLBACK(void) supdrvDarwinMsrProberReadOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1691{
1692 PSUPDRVDARWINMSRARGS pArgs = (PSUPDRVDARWINMSRARGS)pvUser1;
1693 if (g_pfnRdMsr64Carefully)
1694 pArgs->rc = g_pfnRdMsr64Carefully(pArgs->uMsr, &pArgs->uValue.u);
1695 else if (g_pfnRdMsrCarefully)
1696 pArgs->rc = g_pfnRdMsrCarefully(pArgs->uMsr, &pArgs->uValue.s.Lo, &pArgs->uValue.s.Hi);
1697 else
1698 pArgs->rc = 2;
1699 NOREF(idCpu); NOREF(pvUser2);
1700}
1701
1702
1703int VBOXCALL supdrvOSMsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue)
1704{
1705 if (!g_pfnRdMsr64Carefully && !g_pfnRdMsrCarefully)
1706 return VERR_NOT_SUPPORTED;
1707
1708 SUPDRVDARWINMSRARGS Args;
1709 Args.uMsr = uMsr;
1710 Args.uValue.u = 0;
1711 Args.rc = -1;
1712
1713 if (idCpu == NIL_RTCPUID)
1714 {
1715 IPRT_DARWIN_SAVE_EFL_AC();
1716 supdrvDarwinMsrProberReadOnCpu(idCpu, &Args, NULL);
1717 IPRT_DARWIN_RESTORE_EFL_AC();
1718 }
1719 else
1720 {
1721 int rc = RTMpOnSpecific(idCpu, supdrvDarwinMsrProberReadOnCpu, &Args, NULL);
1722 if (RT_FAILURE(rc))
1723 return rc;
1724 }
1725
1726 if (Args.rc)
1727 return VERR_ACCESS_DENIED;
1728 *puValue = Args.uValue.u;
1729 return VINF_SUCCESS;
1730}
1731
1732
1733/**
1734 * On CPU worker for supdrvOSMsrProberWrite.
1735 *
1736 * @param idCpu Ignored.
1737 * @param pvUser1 Pointer to a SUPDRVDARWINMSRARGS.
1738 * @param pvUser2 Ignored.
1739 */
1740static DECLCALLBACK(void) supdrvDarwinMsrProberWriteOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1741{
1742 PSUPDRVDARWINMSRARGS pArgs = (PSUPDRVDARWINMSRARGS)pvUser1;
1743 if (g_pfnWrMsr64Carefully)
1744 pArgs->rc = g_pfnWrMsr64Carefully(pArgs->uMsr, pArgs->uValue.u);
1745 else
1746 pArgs->rc = 2;
1747 NOREF(idCpu); NOREF(pvUser2);
1748}
1749
1750
1751int VBOXCALL supdrvOSMsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue)
1752{
1753 if (!g_pfnWrMsr64Carefully)
1754 return VERR_NOT_SUPPORTED;
1755
1756 SUPDRVDARWINMSRARGS Args;
1757 Args.uMsr = uMsr;
1758 Args.uValue.u = uValue;
1759 Args.rc = -1;
1760
1761 if (idCpu == NIL_RTCPUID)
1762 {
1763 IPRT_DARWIN_SAVE_EFL_AC();
1764 supdrvDarwinMsrProberWriteOnCpu(idCpu, &Args, NULL);
1765 IPRT_DARWIN_RESTORE_EFL_AC();
1766 }
1767 else
1768 {
1769 int rc = RTMpOnSpecific(idCpu, supdrvDarwinMsrProberWriteOnCpu, &Args, NULL);
1770 if (RT_FAILURE(rc))
1771 return rc;
1772 }
1773
1774 if (Args.rc)
1775 return VERR_ACCESS_DENIED;
1776 return VINF_SUCCESS;
1777}
1778
1779
1780/**
1781 * Worker for supdrvOSMsrProberModify.
1782 */
1783static DECLCALLBACK(void) supdrvDarwinMsrProberModifyOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
1784{
1785 RT_NOREF(idCpu, pvUser2);
1786 PSUPMSRPROBER pReq = (PSUPMSRPROBER)pvUser1;
1787 register uint32_t uMsr = pReq->u.In.uMsr;
1788 bool const fFaster = pReq->u.In.enmOp == SUPMSRPROBEROP_MODIFY_FASTER;
1789 uint64_t uBefore;
1790 uint64_t uWritten;
1791 uint64_t uAfter;
1792 int rcBefore, rcWrite, rcAfter, rcRestore;
1793 RTCCUINTREG fOldFlags;
1794
1795 /* Initialize result variables. */
1796 uBefore = uWritten = uAfter = 0;
1797 rcWrite = rcAfter = rcRestore = -1;
1798
1799 /*
1800 * Do the job.
1801 */
1802 fOldFlags = ASMIntDisableFlags();
1803 ASMCompilerBarrier(); /* paranoia */
1804 if (!fFaster)
1805 ASMWriteBackAndInvalidateCaches();
1806
1807 rcBefore = g_pfnRdMsr64Carefully(uMsr, &uBefore);
1808 if (rcBefore >= 0)
1809 {
1810 register uint64_t uRestore = uBefore;
1811 uWritten = uRestore;
1812 uWritten &= pReq->u.In.uArgs.Modify.fAndMask;
1813 uWritten |= pReq->u.In.uArgs.Modify.fOrMask;
1814
1815 rcWrite = g_pfnWrMsr64Carefully(uMsr, uWritten);
1816 rcAfter = g_pfnRdMsr64Carefully(uMsr, &uAfter);
1817 rcRestore = g_pfnWrMsr64Carefully(uMsr, uRestore);
1818
1819 if (!fFaster)
1820 {
1821 ASMWriteBackAndInvalidateCaches();
1822 ASMReloadCR3();
1823 ASMNopPause();
1824 }
1825 }
1826
1827 ASMCompilerBarrier(); /* paranoia */
1828 ASMSetFlags(fOldFlags);
1829
1830 /*
1831 * Write out the results.
1832 */
1833 pReq->u.Out.uResults.Modify.uBefore = uBefore;
1834 pReq->u.Out.uResults.Modify.uWritten = uWritten;
1835 pReq->u.Out.uResults.Modify.uAfter = uAfter;
1836 pReq->u.Out.uResults.Modify.fBeforeGp = rcBefore != 0;
1837 pReq->u.Out.uResults.Modify.fModifyGp = rcWrite != 0;
1838 pReq->u.Out.uResults.Modify.fAfterGp = rcAfter != 0;
1839 pReq->u.Out.uResults.Modify.fRestoreGp = rcRestore != 0;
1840 RT_ZERO(pReq->u.Out.uResults.Modify.afReserved);
1841}
1842
1843
1844int VBOXCALL supdrvOSMsrProberModify(RTCPUID idCpu, PSUPMSRPROBER pReq)
1845{
1846 if (!g_pfnWrMsr64Carefully || !g_pfnRdMsr64Carefully)
1847 return VERR_NOT_SUPPORTED;
1848 if (idCpu == NIL_RTCPUID)
1849 {
1850 IPRT_DARWIN_SAVE_EFL_AC();
1851 supdrvDarwinMsrProberModifyOnCpu(idCpu, pReq, NULL);
1852 IPRT_DARWIN_RESTORE_EFL_AC();
1853 return VINF_SUCCESS;
1854 }
1855 return RTMpOnSpecific(idCpu, supdrvDarwinMsrProberModifyOnCpu, pReq, NULL);
1856}
1857
1858#endif /* SUPDRV_WITH_MSR_PROBER */
1859
1860/**
1861 * Resume Bluetooth keyboard.
1862 * If there is no Bluetooth keyboard device connected to the system we just ignore this.
1863 */
1864static void supdrvDarwinResumeBluetoothKbd(void)
1865{
1866 OSDictionary *pDictionary = IOService::serviceMatching("AppleBluetoothHIDKeyboard");
1867 if (pDictionary)
1868 {
1869 OSIterator *pIter;
1870 IOBluetoothHIDDriver *pDriver;
1871
1872 pIter = IOService::getMatchingServices(pDictionary);
1873 if (pIter)
1874 {
1875 while ((pDriver = (IOBluetoothHIDDriver *)pIter->getNextObject()))
1876 if (pDriver->isKeyboard())
1877 (void)pDriver->hidControl(IOBTHID_CONTROL_EXIT_SUSPEND);
1878
1879 pIter->release();
1880 }
1881 pDictionary->release();
1882 }
1883}
1884
1885/**
1886 * Resume built-in keyboard on MacBook Air and Pro hosts.
1887 * If there is no built-in keyboard device attached to the system we just ignore this.
1888 */
1889static void supdrvDarwinResumeBuiltinKbd(void)
1890{
1891 /*
1892 * AppleUSBTCKeyboard KEXT is responsible for built-in keyboard management.
1893 * We resume keyboard by accessing to its IOService. */
1894 OSDictionary *pDictionary = IOService::serviceMatching("AppleUSBTCKeyboard");
1895 if (pDictionary)
1896 {
1897 OSIterator *pIter;
1898 IOUSBHIDDriver *pDriver;
1899
1900 pIter = IOService::getMatchingServices(pDictionary);
1901 if (pIter)
1902 {
1903 while ((pDriver = (IOUSBHIDDriver *)pIter->getNextObject()))
1904 if (pDriver->IsPortSuspended())
1905 pDriver->SuspendPort(false, 0);
1906
1907 pIter->release();
1908 }
1909 pDictionary->release();
1910 }
1911}
1912
1913
1914/**
1915 * Resume suspended keyboard devices (if any).
1916 */
1917int VBOXCALL supdrvDarwinResumeSuspendedKbds(void)
1918{
1919 IPRT_DARWIN_SAVE_EFL_AC();
1920 supdrvDarwinResumeBuiltinKbd();
1921 supdrvDarwinResumeBluetoothKbd();
1922 IPRT_DARWIN_RESTORE_EFL_AC();
1923 return 0;
1924}
1925
1926
1927/**
1928 * Converts an IPRT error code to a darwin error code.
1929 *
1930 * @returns corresponding darwin error code.
1931 * @param rc IPRT status code.
1932 */
1933static int VBoxDrvDarwinErr2DarwinErr(int rc)
1934{
1935 switch (rc)
1936 {
1937 case VINF_SUCCESS: return 0;
1938 case VERR_GENERAL_FAILURE: return EACCES;
1939 case VERR_INVALID_PARAMETER: return EINVAL;
1940 case VERR_INVALID_MAGIC: return EILSEQ;
1941 case VERR_INVALID_HANDLE: return ENXIO;
1942 case VERR_INVALID_POINTER: return EFAULT;
1943 case VERR_LOCK_FAILED: return ENOLCK;
1944 case VERR_ALREADY_LOADED: return EEXIST;
1945 case VERR_PERMISSION_DENIED: return EPERM;
1946 case VERR_VERSION_MISMATCH: return ENOSYS;
1947 }
1948
1949 return EPERM;
1950}
1951
1952
1953/**
1954 * Check if the CPU has SMAP support.
1955 */
1956static bool vboxdrvDarwinCpuHasSMAP(void)
1957{
1958 uint32_t uMaxId, uEAX, uEBX, uECX, uEDX;
1959 ASMCpuId(0, &uMaxId, &uEBX, &uECX, &uEDX);
1960 if ( ASMIsValidStdRange(uMaxId)
1961 && uMaxId >= 0x00000007)
1962 {
1963 ASMCpuId_Idx_ECX(0x00000007, 0, &uEAX, &uEBX, &uECX, &uEDX);
1964 if (uEBX & X86_CPUID_STEXT_FEATURE_EBX_SMAP)
1965 return true;
1966 }
1967#ifdef VBOX_WITH_EFLAGS_AC_SET_IN_VBOXDRV
1968 return true;
1969#else
1970 return false;
1971#endif
1972}
1973
1974
1975RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
1976{
1977 IPRT_DARWIN_SAVE_EFL_AC();
1978 va_list va;
1979 char szMsg[512];
1980
1981 va_start(va, pszFormat);
1982 RTStrPrintfV(szMsg, sizeof(szMsg) - 1, pszFormat, va);
1983 va_end(va);
1984 szMsg[sizeof(szMsg) - 1] = '\0';
1985
1986 printf("%s", szMsg);
1987
1988 IPRT_DARWIN_RESTORE_EFL_AC();
1989 return 0;
1990}
1991
1992
1993SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void)
1994{
1995 uint32_t fFlags = 0;
1996 if (g_DevCW.d_ioctl == VBoxDrvDarwinIOCtlSMAP)
1997 fFlags |= SUPKERNELFEATURES_SMAP;
1998 else
1999 Assert(!(ASMGetCR4() & X86_CR4_SMAP));
2000 return fFlags;
2001}
2002
2003
2004/*
2005 *
2006 * org_virtualbox_SupDrv
2007 *
2008 * - IOService diff resync -
2009 * - IOService diff resync -
2010 * - IOService diff resync -
2011 *
2012 */
2013
2014
2015/**
2016 * Initialize the object.
2017 */
2018bool org_virtualbox_SupDrv::init(OSDictionary *pDictionary)
2019{
2020 LogFlow(("IOService::init([%p], %p)\n", this, pDictionary));
2021 if (IOService::init(pDictionary))
2022 {
2023 /* init members. */
2024 return true;
2025 }
2026 return false;
2027}
2028
2029
2030/**
2031 * Free the object.
2032 */
2033void org_virtualbox_SupDrv::free(void)
2034{
2035 LogFlow(("IOService::free([%p])\n", this));
2036 IOService::free();
2037}
2038
2039
2040/**
2041 * Check if it's ok to start this service.
2042 * It's always ok by us, so it's up to IOService to decide really.
2043 */
2044IOService *org_virtualbox_SupDrv::probe(IOService *pProvider, SInt32 *pi32Score)
2045{
2046 LogFlow(("IOService::probe([%p])\n", this));
2047 return IOService::probe(pProvider, pi32Score);
2048}
2049
2050
2051/**
2052 * Start this service.
2053 */
2054bool org_virtualbox_SupDrv::start(IOService *pProvider)
2055{
2056 LogFlow(("org_virtualbox_SupDrv::start([%p])\n", this));
2057
2058 if (IOService::start(pProvider))
2059 {
2060 /* register the service. */
2061 registerService();
2062 return true;
2063 }
2064 return false;
2065}
2066
2067
2068/**
2069 * Stop this service.
2070 */
2071void org_virtualbox_SupDrv::stop(IOService *pProvider)
2072{
2073 LogFlow(("org_virtualbox_SupDrv::stop([%p], %p)\n", this, pProvider));
2074 IOService::stop(pProvider);
2075}
2076
2077
2078/**
2079 * Termination request.
2080 *
2081 * @return true if we're ok with shutting down now, false if we're not.
2082 * @param fOptions Flags.
2083 */
2084bool org_virtualbox_SupDrv::terminate(IOOptionBits fOptions)
2085{
2086 bool fRc;
2087 LogFlow(("org_virtualbox_SupDrv::terminate: reference_count=%d g_cSessions=%d (fOptions=%#x)\n",
2088 KMOD_INFO_NAME.reference_count, ASMAtomicUoReadS32(&g_cSessions), fOptions));
2089 if ( KMOD_INFO_NAME.reference_count != 0
2090 || ASMAtomicUoReadS32(&g_cSessions))
2091 fRc = false;
2092 else
2093 fRc = IOService::terminate(fOptions);
2094 LogFlow(("org_virtualbox_SupDrv::terminate: returns %d\n", fRc));
2095 return fRc;
2096}
2097
2098
2099/*
2100 *
2101 * org_virtualbox_SupDrvClient
2102 *
2103 */
2104
2105
2106/**
2107 * Initializer called when the client opens the service.
2108 */
2109bool org_virtualbox_SupDrvClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type)
2110{
2111 LogFlow(("org_virtualbox_SupDrvClient::initWithTask([%p], %#x, %p, %#x) (cur pid=%d proc=%p)\n",
2112 this, OwningTask, pvSecurityId, u32Type, RTProcSelf(), RTR0ProcHandleSelf()));
2113 AssertMsg((RTR0PROCESS)OwningTask == RTR0ProcHandleSelf(), ("%p %p\n", OwningTask, RTR0ProcHandleSelf()));
2114
2115 if (!OwningTask)
2116 return false;
2117
2118 if (u32Type != SUP_DARWIN_IOSERVICE_COOKIE)
2119 {
2120 VBOX_RETRIEVE_CUR_PROC_NAME(szProcName);
2121 LogRelMax(10,("org_virtualbox_SupDrvClient::initWithTask: Bad cookie %#x (%s)\n", u32Type, szProcName));
2122 return false;
2123 }
2124
2125 if (IOUserClient::initWithTask(OwningTask, pvSecurityId , u32Type))
2126 {
2127 /*
2128 * In theory we have to call task_reference() to make sure that the task is
2129 * valid during the lifetime of this object. The pointer is only used to check
2130 * for the context this object is called in though and never dereferenced
2131 * or passed to anything which might, so we just skip this step.
2132 */
2133 m_Task = OwningTask;
2134 m_pSession = NULL;
2135 m_pProvider = NULL;
2136 return true;
2137 }
2138 return false;
2139}
2140
2141
2142/**
2143 * Start the client service.
2144 */
2145bool org_virtualbox_SupDrvClient::start(IOService *pProvider)
2146{
2147 LogFlow(("org_virtualbox_SupDrvClient::start([%p], %p) (cur pid=%d proc=%p)\n",
2148 this, pProvider, RTProcSelf(), RTR0ProcHandleSelf() ));
2149 AssertMsgReturn((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(),
2150 ("%p %p\n", m_Task, RTR0ProcHandleSelf()),
2151 false);
2152
2153 if (IOUserClient::start(pProvider))
2154 {
2155 m_pProvider = OSDynamicCast(org_virtualbox_SupDrv, pProvider);
2156 if (m_pProvider)
2157 {
2158 Assert(!m_pSession);
2159
2160 /*
2161 * Create a new session.
2162 */
2163 int rc = supdrvCreateSession(&g_DevExt, true /* fUser */, false /*fUnrestricted*/, &m_pSession);
2164 if (RT_SUCCESS(rc))
2165 {
2166 m_pSession->fOpened = false;
2167 /* The Uid, Gid and fUnrestricted fields are set on open. */
2168
2169 /*
2170 * Insert it into the hash table, checking that there isn't
2171 * already one for this process first. (One session per proc!)
2172 */
2173 unsigned iHash = SESSION_HASH(m_pSession->Process);
2174 RTSpinlockAcquire(g_Spinlock);
2175
2176 PSUPDRVSESSION pCur = g_apSessionHashTab[iHash];
2177 while (pCur && pCur->Process != m_pSession->Process)
2178 pCur = pCur->pNextHash;
2179 if (!pCur)
2180 {
2181 m_pSession->pNextHash = g_apSessionHashTab[iHash];
2182 g_apSessionHashTab[iHash] = m_pSession;
2183 m_pSession->pvSupDrvClient = this;
2184 ASMAtomicIncS32(&g_cSessions);
2185 rc = VINF_SUCCESS;
2186 }
2187 else
2188 rc = VERR_ALREADY_LOADED;
2189
2190 RTSpinlockRelease(g_Spinlock);
2191 if (RT_SUCCESS(rc))
2192 {
2193 Log(("org_virtualbox_SupDrvClient::start: created session %p for pid %d\n", m_pSession, (int)RTProcSelf()));
2194 return true;
2195 }
2196
2197 LogFlow(("org_virtualbox_SupDrvClient::start: already got a session for this process (%p)\n", pCur));
2198 supdrvSessionRelease(m_pSession);
2199 }
2200
2201 m_pSession = NULL;
2202 LogFlow(("org_virtualbox_SupDrvClient::start: rc=%Rrc from supdrvCreateSession\n", rc));
2203 }
2204 else
2205 LogFlow(("org_virtualbox_SupDrvClient::start: %p isn't org_virtualbox_SupDrv\n", pProvider));
2206 }
2207 return false;
2208}
2209
2210
2211/**
2212 * Common worker for clientClose and VBoxDrvDarwinClose.
2213 */
2214/* static */ void org_virtualbox_SupDrvClient::sessionClose(RTPROCESS Process)
2215{
2216 /*
2217 * Find the session and remove it from the hash table.
2218 *
2219 * Note! Only one session per process. (Both start() and
2220 * VBoxDrvDarwinOpen makes sure this is so.)
2221 */
2222 const unsigned iHash = SESSION_HASH(Process);
2223 RTSpinlockAcquire(g_Spinlock);
2224 PSUPDRVSESSION pSession = g_apSessionHashTab[iHash];
2225 if (pSession)
2226 {
2227 if (pSession->Process == Process)
2228 {
2229 g_apSessionHashTab[iHash] = pSession->pNextHash;
2230 pSession->pNextHash = NULL;
2231 ASMAtomicDecS32(&g_cSessions);
2232 }
2233 else
2234 {
2235 PSUPDRVSESSION pPrev = pSession;
2236 pSession = pSession->pNextHash;
2237 while (pSession)
2238 {
2239 if (pSession->Process == Process)
2240 {
2241 pPrev->pNextHash = pSession->pNextHash;
2242 pSession->pNextHash = NULL;
2243 ASMAtomicDecS32(&g_cSessions);
2244 break;
2245 }
2246
2247 /* next */
2248 pPrev = pSession;
2249 pSession = pSession->pNextHash;
2250 }
2251 }
2252 }
2253 RTSpinlockRelease(g_Spinlock);
2254 if (!pSession)
2255 {
2256 Log(("SupDrvClient::sessionClose: pSession == NULL, pid=%d; freed already?\n", (int)Process));
2257 return;
2258 }
2259
2260 /*
2261 * Remove it from the client object.
2262 */
2263 org_virtualbox_SupDrvClient *pThis = (org_virtualbox_SupDrvClient *)pSession->pvSupDrvClient;
2264 pSession->pvSupDrvClient = NULL;
2265 if (pThis)
2266 {
2267 Assert(pThis->m_pSession == pSession);
2268 pThis->m_pSession = NULL;
2269 }
2270
2271 /*
2272 * Close the session.
2273 */
2274 supdrvSessionRelease(pSession);
2275}
2276
2277
2278/**
2279 * Client exits normally.
2280 */
2281IOReturn org_virtualbox_SupDrvClient::clientClose(void)
2282{
2283 LogFlow(("org_virtualbox_SupDrvClient::clientClose([%p]) (cur pid=%d proc=%p)\n", this, RTProcSelf(), RTR0ProcHandleSelf()));
2284 AssertMsg((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(), ("%p %p\n", m_Task, RTR0ProcHandleSelf()));
2285
2286 /*
2287 * Clean up the session if it's still around.
2288 *
2289 * We cannot rely 100% on close, and in the case of a dead client
2290 * we'll end up hanging inside vm_map_remove() if we postpone it.
2291 */
2292 if (m_pSession)
2293 {
2294 sessionClose(RTProcSelf());
2295 Assert(!m_pSession);
2296 }
2297
2298 m_pProvider = NULL;
2299 terminate();
2300
2301 return kIOReturnSuccess;
2302}
2303
2304
2305/**
2306 * The client exits abnormally / forgets to do cleanups. (logging)
2307 */
2308IOReturn org_virtualbox_SupDrvClient::clientDied(void)
2309{
2310 LogFlow(("IOService::clientDied([%p]) m_Task=%p R0Process=%p Process=%d\n", this, m_Task, RTR0ProcHandleSelf(), RTProcSelf()));
2311
2312 /* IOUserClient::clientDied() calls clientClose, so we'll just do the work there. */
2313 return IOUserClient::clientDied();
2314}
2315
2316
2317/**
2318 * Terminate the service (initiate the destruction). (logging)
2319 */
2320bool org_virtualbox_SupDrvClient::terminate(IOOptionBits fOptions)
2321{
2322 LogFlow(("IOService::terminate([%p], %#x)\n", this, fOptions));
2323 return IOUserClient::terminate(fOptions);
2324}
2325
2326
2327/**
2328 * The final stage of the client service destruction. (logging)
2329 */
2330bool org_virtualbox_SupDrvClient::finalize(IOOptionBits fOptions)
2331{
2332 LogFlow(("IOService::finalize([%p], %#x)\n", this, fOptions));
2333 return IOUserClient::finalize(fOptions);
2334}
2335
2336
2337/**
2338 * Stop the client service. (logging)
2339 */
2340void org_virtualbox_SupDrvClient::stop(IOService *pProvider)
2341{
2342 LogFlow(("IOService::stop([%p])\n", this));
2343 IOUserClient::stop(pProvider);
2344}
2345
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