VirtualBox

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

Last change on this file since 95087 was 95087, checked in by vboxsync, 2 years ago

SUPDrv: bugref:10209: Added stubs for host FPU begin/end operations.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use