VirtualBox

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

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

IPRT,SUPDrv: Added cbImage parameter to FNRTLDRRDRMEMDTOR; sketched the basics for darwin module verification. bugref:9232 [build fix[

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