VirtualBox

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

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

SUPDrv: Adding supdrvOSLdrQuerySymbol so we don't have to save a copy of the symbol table for native modules. bugref:9232

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