VirtualBox

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

Last change on this file since 82890 was 82858, checked in by vboxsync, 5 years ago

SUPDrv-darwin: kprint the module addresses and SUPR0Printf stuff.

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