VirtualBox

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

最後變更 在這個檔案從15130是 15130,由 vboxsync 提交於 16 年 前

VBoxDrvTiger.kext (#3202).

檔案大小: 33.9 KB
 
1/* $Id: $ */
2/** @file
3 *
4 * VBox host drivers - Ring-0 support drivers - Darwin host:
5 * Darwin driver C code
6 */
7
8/*
9 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.alldomusa.eu.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * The contents of this file may alternatively be used under the terms
20 * of the Common Development and Distribution License Version 1.0
21 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
22 * VirtualBox OSE distribution, in which case the provisions of the
23 * CDDL are applicable instead of those of the GPL.
24 *
25 * You may elect to license modified versions of this file under the
26 * terms and conditions of either the GPL or the CDDL or both.
27 *
28 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
29 * Clara, CA 95054 USA or visit http://www.sun.com if you need
30 * additional information or have any questions.
31 */
32
33/*******************************************************************************
34* Header Files *
35*******************************************************************************/
36#define LOG_GROUP LOG_GROUP_SUP_DRV
37/*
38 * Deal with conflicts first.
39 * PVM - BSD mess, that FreeBSD has correct a long time ago.
40 * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
41 */
42#include <iprt/types.h>
43#include <sys/param.h>
44#undef PVM
45
46#include <IOKit/IOLib.h> /* Assert as function */
47
48#include "../SUPDrvInternal.h"
49#include <VBox/version.h>
50#include <iprt/initterm.h>
51#include <iprt/assert.h>
52#include <iprt/spinlock.h>
53#include <iprt/semaphore.h>
54#include <iprt/process.h>
55#include <iprt/alloc.h>
56#include <iprt/power.h>
57#include <VBox/err.h>
58#include <VBox/log.h>
59
60#include <mach/kmod.h>
61#include <miscfs/devfs/devfs.h>
62#include <sys/conf.h>
63#include <sys/errno.h>
64#include <sys/ioccom.h>
65#include <sys/malloc.h>
66#include <sys/proc.h>
67#include <IOKit/IOService.h>
68#include <IOKit/IOUserclient.h>
69#include <IOKit/pwr_mgt/RootDomain.h>
70
71#ifdef VBOX_WITH_HOST_VMX
72__BEGIN_DECLS
73# include <i386/vmx.h>
74__END_DECLS
75#endif
76
77
78/*******************************************************************************
79* Defined Constants And Macros *
80*******************************************************************************/
81
82/** The module name. */
83#define DEVICE_NAME "vboxdrv"
84
85
86
87/*******************************************************************************
88* Internal Functions *
89*******************************************************************************/
90__BEGIN_DECLS
91static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData);
92static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData);
93
94static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
95static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
96static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
97static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess);
98
99static int VBoxDrvDarwinErr2DarwinErr(int rc);
100
101static IOReturn VBoxDrvDarwinSleepHandler(void *pvTarget, void *pvRefCon, UInt32 uMessageType, IOService *pProvider, void *pvMessageArgument, vm_size_t argSize);
102__END_DECLS
103
104
105/*******************************************************************************
106* Structures and Typedefs *
107*******************************************************************************/
108/**
109 * The service class.
110 * This is just a formality really.
111 */
112class org_virtualbox_SupDrv : public IOService
113{
114 OSDeclareDefaultStructors(org_virtualbox_SupDrv);
115
116public:
117 virtual bool init(OSDictionary *pDictionary = 0);
118 virtual void free(void);
119 virtual bool start(IOService *pProvider);
120 virtual void stop(IOService *pProvider);
121 virtual IOService *probe(IOService *pProvider, SInt32 *pi32Score);
122 virtual bool terminate(IOOptionBits fOptions);
123};
124
125OSDefineMetaClassAndStructors(org_virtualbox_SupDrv, IOService);
126
127
128/**
129 * An attempt at getting that clientDied() notification.
130 * I don't think it'll work as I cannot figure out where/what creates the correct
131 * port right.
132 */
133class org_virtualbox_SupDrvClient : public IOUserClient
134{
135 OSDeclareDefaultStructors(org_virtualbox_SupDrvClient);
136
137private:
138 PSUPDRVSESSION m_pSession; /**< The session. */
139 task_t m_Task; /**< The client task. */
140 org_virtualbox_SupDrv *m_pProvider; /**< The service provider. */
141
142public:
143 virtual bool initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type);
144 virtual bool start(IOService *pProvider);
145 static void sessionClose(RTPROCESS Process);
146 virtual IOReturn clientClose(void);
147 virtual IOReturn clientDied(void);
148 virtual bool terminate(IOOptionBits fOptions = 0);
149 virtual bool finalize(IOOptionBits fOptions);
150 virtual void stop(IOService *pProvider);
151};
152
153OSDefineMetaClassAndStructors(org_virtualbox_SupDrvClient, IOUserClient);
154
155
156
157/*******************************************************************************
158* Global Variables *
159*******************************************************************************/
160/**
161 * Declare the module stuff.
162 */
163__BEGIN_DECLS
164extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
165extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
166
167KMOD_EXPLICIT_DECL(VBoxDrv, VBOX_VERSION_STRING, _start, _stop)
168DECLHIDDEN(kmod_start_func_t *) _realmain = VBoxDrvDarwinStart;
169DECLHIDDEN(kmod_stop_func_t *) _antimain = VBoxDrvDarwinStop;
170DECLHIDDEN(int) _kext_apple_cc = __APPLE_CC__;
171__END_DECLS
172
173
174/**
175 * Device extention & session data association structure.
176 */
177static SUPDRVDEVEXT g_DevExt;
178
179/**
180 * The character device switch table for the driver.
181 */
182static struct cdevsw g_DevCW =
183{
184 /** @todo g++ doesn't like this syntax - it worked with gcc before renaming to .cpp. */
185 /*.d_open = */VBoxDrvDarwinOpen,
186 /*.d_close = */VBoxDrvDarwinClose,
187 /*.d_read = */eno_rdwrt,
188 /*.d_write = */eno_rdwrt,
189 /*.d_ioctl = */VBoxDrvDarwinIOCtl,
190 /*.d_stop = */eno_stop,
191 /*.d_reset = */eno_reset,
192 /*.d_ttys = */NULL,
193 /*.d_select= */eno_select,
194 /*.d_mmap = */eno_mmap,
195 /*.d_strategy = */eno_strat,
196 /*.d_getc = */eno_getc,
197 /*.d_putc = */eno_putc,
198 /*.d_type = */0
199};
200
201/** Major device number. */
202static int g_iMajorDeviceNo = -1;
203/** Registered devfs device handle. */
204static void *g_hDevFsDevice = NULL;
205
206/** Spinlock protecting g_apSessionHashTab. */
207static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
208/** Hash table */
209static PSUPDRVSESSION g_apSessionHashTab[19];
210/** Calculates the index into g_apSessionHashTab.*/
211#define SESSION_HASH(pid) ((pid) % RT_ELEMENTS(g_apSessionHashTab))
212/** The number of open sessions. */
213static int32_t volatile g_cSessions = 0;
214/** The notifier handle for the sleep callback handler. */
215static IONotifier *g_pSleepNotifier = NULL;
216
217
218
219/**
220 * Start the kernel module.
221 */
222static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData)
223{
224 int rc;
225#ifdef DEBUG
226 printf("VBoxDrvDarwinStart\n");
227#endif
228
229 /*
230 * Initialize IPRT.
231 */
232 rc = RTR0Init(0);
233 if (RT_SUCCESS(rc))
234 {
235 /*
236 * Initialize the device extension.
237 */
238 rc = supdrvInitDevExt(&g_DevExt);
239 if (RT_SUCCESS(rc))
240 {
241 /*
242 * Initialize the session hash table.
243 */
244 memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab)); /* paranoia */
245 rc = RTSpinlockCreate(&g_Spinlock);
246 if (RT_SUCCESS(rc))
247 {
248 /*
249 * Registering ourselves as a character device.
250 */
251 g_iMajorDeviceNo = cdevsw_add(-1, &g_DevCW);
252 if (g_iMajorDeviceNo >= 0)
253 {
254#ifdef VBOX_WITH_HARDENING
255 g_hDevFsDevice = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
256 UID_ROOT, GID_WHEEL, 0600, DEVICE_NAME);
257#else
258 g_hDevFsDevice = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
259 UID_ROOT, GID_WHEEL, 0666, DEVICE_NAME);
260#endif
261 if (g_hDevFsDevice)
262 {
263 LogRel(("VBoxDrv: version " VBOX_VERSION_STRING " r%d; IOCtl version %#x; IDC version %#x; dev major=%d\n",
264 VBOX_SVN_REV, SUPDRV_IOC_VERSION, SUPDRV_IDC_VERSION, g_iMajorDeviceNo));
265
266 /* Register a sleep/wakeup notification callback */
267 g_pSleepNotifier = registerPrioritySleepWakeInterest(&VBoxDrvDarwinSleepHandler, &g_DevExt, NULL);
268 if (g_pSleepNotifier == NULL)
269 LogRel(("VBoxDrv: register for sleep/wakeup events failed\n"));
270
271 return KMOD_RETURN_SUCCESS;
272 }
273
274 LogRel(("VBoxDrv: devfs_make_node(makedev(%d,0),,,,%s) failed\n", g_iMajorDeviceNo, DEVICE_NAME));
275 cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
276 g_iMajorDeviceNo = -1;
277 }
278 else
279 LogRel(("VBoxDrv: cdevsw_add failed (%d)\n", g_iMajorDeviceNo));
280 RTSpinlockDestroy(g_Spinlock);
281 g_Spinlock = NIL_RTSPINLOCK;
282 }
283 else
284 LogRel(("VBoxDrv: RTSpinlockCreate failed (rc=%d)\n", rc));
285 supdrvDeleteDevExt(&g_DevExt);
286 }
287 else
288 printf("VBoxDrv: failed to initialize device extension (rc=%d)\n", rc);
289 RTR0Term();
290 }
291 else
292 printf("VBoxDrv: failed to initialize IPRT (rc=%d)\n", rc);
293
294 memset(&g_DevExt, 0, sizeof(g_DevExt));
295 return KMOD_RETURN_FAILURE;
296}
297
298
299/**
300 * Stop the kernel module.
301 */
302static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData)
303{
304 int rc;
305 LogFlow(("VBoxDrvDarwinStop\n"));
306
307 /** @todo I've got a nagging feeling that we'll have to keep track of users and refuse
308 * unloading if we're busy. Investigate and implement this! */
309
310 /*
311 * Undo the work done during start (in reverse order).
312 */
313 if (g_pSleepNotifier)
314 {
315 g_pSleepNotifier->remove();
316 g_pSleepNotifier = NULL;
317 }
318
319 devfs_remove(g_hDevFsDevice);
320 g_hDevFsDevice = NULL;
321
322 rc = cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
323 Assert(rc == g_iMajorDeviceNo);
324 g_iMajorDeviceNo = -1;
325
326 supdrvDeleteDevExt(&g_DevExt);
327
328 rc = RTSpinlockDestroy(g_Spinlock);
329 AssertRC(rc);
330 g_Spinlock = NIL_RTSPINLOCK;
331
332 RTR0Term();
333
334 memset(&g_DevExt, 0, sizeof(g_DevExt));
335#ifdef DEBUG
336 printf("VBoxDrvDarwinStop - done\n");
337#endif
338 return KMOD_RETURN_SUCCESS;
339}
340
341
342/**
343 * Device open. Called on open /dev/vboxdrv
344 *
345 * @param pInode Pointer to inode info structure.
346 * @param pFilp Associated file pointer.
347 */
348static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
349{
350#ifdef DEBUG_DARWIN_GIP
351 char szName[128];
352 szName[0] = '\0';
353 proc_name(proc_pid(pProcess), szName, sizeof(szName));
354 Log(("VBoxDrvDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
355#endif
356
357 /*
358 * Find the session created by org_virtualbox_SupDrvClient, fail
359 * if no such session, and mark it as opened. We set the uid & gid
360 * here too, since that is more straight forward at this point.
361 */
362 int rc = VINF_SUCCESS;
363 PSUPDRVSESSION pSession = NULL;
364 struct ucred *pCred = proc_ucred(pProcess);
365 if (pCred)
366 {
367 RTUID Uid = pCred->cr_ruid;
368 RTGID Gid = pCred->cr_rgid;
369 RTPROCESS Process = RTProcSelf();
370 unsigned iHash = SESSION_HASH(Process);
371 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
372 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
373
374 pSession = g_apSessionHashTab[iHash];
375 if (pSession && pSession->Process != Process)
376 {
377 do pSession = pSession->pNextHash;
378 while (pSession && pSession->Process != Process);
379 }
380 if (pSession)
381 {
382 if (!pSession->fOpened)
383 {
384 pSession->fOpened = true;
385 pSession->Uid = Uid;
386 pSession->Gid = Gid;
387 }
388 else
389 rc = VERR_ALREADY_LOADED;
390 }
391 else
392 rc = VERR_GENERAL_FAILURE;
393
394 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
395 }
396 else
397 rc = SUPDRV_ERR_INVALID_PARAM;
398
399#ifdef DEBUG_DARWIN_GIP
400 OSDBGPRINT(("VBoxDrvDarwinOpen: pid=%d '%s' pSession=%p rc=%d\n", proc_pid(pProcess), szName, pSession, rc));
401#else
402 Log(("VBoxDrvDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess)));
403#endif
404 return VBoxDrvDarwinErr2DarwinErr(rc);
405}
406
407
408/**
409 * Close device.
410 */
411static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
412{
413 Log(("VBoxDrvDarwinClose: pid=%d\n", (int)RTProcSelf()));
414 Assert(proc_pid(pProcess) == (int)RTProcSelf());
415
416 /*
417 * Hand the session closing to org_virtualbox_SupDrvClient.
418 */
419 org_virtualbox_SupDrvClient::sessionClose(RTProcSelf());
420 return 0;
421}
422
423
424/**
425 * Device I/O Control entry point.
426 *
427 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
428 * @param Dev The device number (major+minor).
429 * @param iCmd The IOCtl command.
430 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
431 * @param fFlags Flag saying we're a character device (like we didn't know already).
432 * @param pProcess The process issuing this request.
433 */
434static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
435{
436 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
437 const RTPROCESS Process = proc_pid(pProcess);
438 const unsigned iHash = SESSION_HASH(Process);
439 PSUPDRVSESSION pSession;
440
441 /*
442 * Find the session.
443 */
444 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
445 pSession = g_apSessionHashTab[iHash];
446 if (pSession && pSession->Process != Process)
447 {
448 do pSession = pSession->pNextHash;
449 while (pSession && pSession->Process != Process);
450 }
451 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
452 if (!pSession)
453 {
454 OSDBGPRINT(("VBoxDrvDarwinIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
455 (int)Process, iCmd));
456 return EINVAL;
457 }
458
459 /*
460 * Deal with the two high-speed IOCtl that takes it's arguments from
461 * the session and iCmd, and only returns a VBox status code.
462 */
463 if ( iCmd == SUP_IOCTL_FAST_DO_RAW_RUN
464 || iCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
465 || iCmd == SUP_IOCTL_FAST_DO_NOP)
466 return supdrvIOCtlFast(iCmd, *(uint32_t *)pData, &g_DevExt, pSession);
467 return VBoxDrvDarwinIOCtlSlow(pSession, iCmd, pData, pProcess);
468}
469
470
471/**
472 * Worker for VBoxDrvDarwinIOCtl that takes the slow IOCtl functions.
473 *
474 * @returns Darwin errno.
475 *
476 * @param pSession The session.
477 * @param iCmd The IOCtl command.
478 * @param pData Pointer to the kernel copy of the SUPDRVIOCTLDATA buffer.
479 * @param pProcess The calling process.
480 */
481static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
482{
483 LogFlow(("VBoxDrvDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));
484
485
486 /*
487 * Buffered or unbuffered?
488 */
489 PSUPREQHDR pHdr;
490 user_addr_t pUser = 0;
491 void *pvPageBuf = NULL;
492 uint32_t cbReq = IOCPARM_LEN(iCmd);
493 if ((IOC_DIRMASK & iCmd) == IOC_INOUT)
494 {
495 pHdr = (PSUPREQHDR)pData;
496 if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
497 {
498 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: cbReq=%#x < %#x; iCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), iCmd));
499 return EINVAL;
500 }
501 if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
502 {
503 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", pHdr->fFlags, iCmd));
504 return EINVAL;
505 }
506 if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
507 || pHdr->cbIn < sizeof(*pHdr)
508 || pHdr->cbOut < sizeof(*pHdr)))
509 {
510 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x) != %#x; iCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, iCmd));
511 return EINVAL;
512 }
513 }
514 else if ((IOC_DIRMASK & iCmd) == IOC_VOID && !cbReq)
515 {
516 /*
517 * Get the header and figure out how much we're gonna have to read.
518 */
519 SUPREQHDR Hdr;
520 pUser = (user_addr_t)*(void **)pData;
521 int rc = copyin(pUser, &Hdr, sizeof(Hdr));
522 if (RT_UNLIKELY(rc))
523 {
524 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
525 return rc;
526 }
527 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
528 {
529 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", Hdr.fFlags, iCmd));
530 return EINVAL;
531 }
532 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
533 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
534 || Hdr.cbOut < sizeof(Hdr)
535 || cbReq > _1M*16))
536 {
537 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x); iCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, iCmd));
538 return EINVAL;
539 }
540
541 /*
542 * Allocate buffer and copy in the data.
543 */
544 pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
545 if (!pHdr)
546 pvPageBuf = pHdr = (PSUPREQHDR)IOMallocAligned(RT_ALIGN_Z(cbReq, PAGE_SIZE), 8);
547 if (RT_UNLIKELY(!pHdr))
548 {
549 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
550 return ENOMEM;
551 }
552 rc = copyin(pUser, pHdr, Hdr.cbIn);
553 if (RT_UNLIKELY(rc))
554 {
555 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,%p,%#x) -> %#x; iCmd=%#lx\n",
556 (unsigned long long)pUser, pHdr, Hdr.cbIn, rc, iCmd));
557 if (pvPageBuf)
558 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
559 else
560 RTMemTmpFree(pHdr);
561 return rc;
562 }
563 }
564 else
565 {
566 Log(("VBoxDrvDarwinIOCtlSlow: huh? cbReq=%#x iCmd=%#lx\n", cbReq, iCmd));
567 return EINVAL;
568 }
569
570 /*
571 * Process the IOCtl.
572 */
573 int rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
574 if (RT_LIKELY(!rc))
575 {
576 /*
577 * If not buffered, copy back the buffer before returning.
578 */
579 if (pUser)
580 {
581 uint32_t cbOut = pHdr->cbOut;
582 if (cbOut > cbReq)
583 {
584 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, iCmd));
585 cbOut = cbReq;
586 }
587 rc = copyout(pHdr, pUser, cbOut);
588 if (RT_UNLIKELY(rc))
589 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyout(%p,%llx,%#x) -> %d; uCmd=%#lx!\n",
590 pHdr, (unsigned long long)pUser, cbOut, rc, iCmd));
591
592 /* cleanup */
593 if (pvPageBuf)
594 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
595 else
596 RTMemTmpFree(pHdr);
597 }
598 }
599 else
600 {
601 /*
602 * The request failed, just clean up.
603 */
604 if (pUser)
605 {
606 if (pvPageBuf)
607 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
608 else
609 RTMemTmpFree(pHdr);
610 }
611
612 Log(("VBoxDrvDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
613 rc = EINVAL;
614 }
615
616 Log2(("VBoxDrvDarwinIOCtlSlow: returns %d\n", rc));
617 return rc;
618}
619
620
621/**
622 * The SUPDRV IDC entry point.
623 *
624 * @returns VBox status code, see supdrvIDC.
625 * @param iReq The request code.
626 * @param pReq The request.
627 */
628int VBOXCALL SUPDrvDarwinIDC(uint32_t uReq, PSUPDRVIDCREQHDR pReq)
629{
630 PSUPDRVSESSION pSession;
631
632 /*
633 * Some quick validations.
634 */
635 if (RT_UNLIKELY(!VALID_PTR(pReq)))
636 return VERR_INVALID_POINTER;
637
638 pSession = pReq->pSession;
639 if (pSession)
640 {
641 if (RT_UNLIKELY(!VALID_PTR(pSession)))
642 return VERR_INVALID_PARAMETER;
643 if (RT_UNLIKELY(pSession->pDevExt != &g_DevExt))
644 return VERR_INVALID_PARAMETER;
645 }
646 else if (RT_UNLIKELY(uReq != SUPDRV_IDC_REQ_CONNECT))
647 return VERR_INVALID_PARAMETER;
648
649 /*
650 * Do the job.
651 */
652 return supdrvIDC(uReq, &g_DevExt, pSession, pReq);
653}
654
655
656/**
657 * Initializes any OS specific object creator fields.
658 */
659void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
660{
661 NOREF(pObj);
662 NOREF(pSession);
663}
664
665
666/**
667 * Checks if the session can access the object.
668 *
669 * @returns true if a decision has been made.
670 * @returns false if the default access policy should be applied.
671 *
672 * @param pObj The object in question.
673 * @param pSession The session wanting to access the object.
674 * @param pszObjName The object name, can be NULL.
675 * @param prc Where to store the result when returning true.
676 */
677bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
678{
679 NOREF(pObj);
680 NOREF(pSession);
681 NOREF(pszObjName);
682 NOREF(prc);
683 return false;
684}
685
686/**
687 * Callback for blah blah blah.
688 */
689IOReturn VBoxDrvDarwinSleepHandler(void * /* pvTarget */, void *pvRefCon, UInt32 uMessageType, IOService * /* pProvider */, void * /* pvMessageArgument */, vm_size_t /* argSize */)
690{
691 LogFlow(("VBoxDrv: Got sleep/wake notice. Message type was %X\n", (uint)uMessageType));
692
693 if (uMessageType == kIOMessageSystemWillSleep)
694 RTPowerSignalEvent(RTPOWEREVENT_SUSPEND);
695 else if (uMessageType == kIOMessageSystemHasPoweredOn)
696 RTPowerSignalEvent(RTPOWEREVENT_RESUME);
697
698 acknowledgeSleepWakeNotification(pvRefCon);
699
700 return 0;
701}
702
703
704/**
705 * Enables or disables VT-x using kernel functions.
706 *
707 * @returns VBox status code. VERR_NOT_SUPPORTED has a special meaning.
708 * @param fEnable Whether to enable or disable.
709 */
710int VBOXCALL supdrvOSEnableVTx(bool fEnable)
711{
712#ifdef VBOX_WITH_HOST_VMX
713 int rc;
714 if (fEnable)
715 {
716 rc = host_vmxon(false /* exclusive */);
717 if (rc == 0 /* all ok */)
718 rc = VINF_SUCCESS;
719 else if (rc == 1 /* unsupported */)
720 rc = VERR_VMX_NO_VMX;
721 else if (rc == 2 /* exclusive user */)
722 rc = VERR_VMX_IN_VMX_ROOT_MODE;
723 else /* shouldn't happen, but just in case. */
724 {
725 LogRel(("host_vmxon returned %d\n", rc));
726 rc = VERR_UNRESOLVED_ERROR;
727 }
728 }
729 else
730 {
731 host_vmxoff();
732 rc = VINF_SUCCESS;
733 }
734 return rc;
735#else
736 return VERR_NOT_SUPPORTED;
737#endif
738}
739
740
741bool VBOXCALL supdrvOSGetForcedAsyncTscMode(PSUPDRVDEVEXT pDevExt)
742{
743 NOREF(pDevExt);
744 return false;
745}
746
747
748/**
749 * Converts a supdrv error code to a darwin error code.
750 *
751 * @returns corresponding darwin error code.
752 * @param rc supdrv error code (SUPDRV_ERR_* defines).
753 */
754static int VBoxDrvDarwinErr2DarwinErr(int rc)
755{
756 switch (rc)
757 {
758 case 0: return 0;
759 case SUPDRV_ERR_GENERAL_FAILURE: return EACCES;
760 case SUPDRV_ERR_INVALID_PARAM: return EINVAL;
761 case SUPDRV_ERR_INVALID_MAGIC: return EILSEQ;
762 case SUPDRV_ERR_INVALID_HANDLE: return ENXIO;
763 case SUPDRV_ERR_INVALID_POINTER: return EFAULT;
764 case SUPDRV_ERR_LOCK_FAILED: return ENOLCK;
765 case SUPDRV_ERR_ALREADY_LOADED: return EEXIST;
766 case SUPDRV_ERR_PERMISSION_DENIED: return EPERM;
767 case SUPDRV_ERR_VERSION_MISMATCH: return ENOSYS;
768 }
769
770 return EPERM;
771}
772
773
774/** @todo move this to assembly where a simple "jmp printf" will to the trick. */
775RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
776{
777 va_list args;
778 char szMsg[512];
779
780 va_start(args, pszFormat);
781 vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
782 va_end(args);
783
784 szMsg[sizeof(szMsg) - 1] = '\0';
785 printf("%s", szMsg);
786 return 0;
787}
788
789
790/*
791 *
792 * org_virtualbox_SupDrv
793 *
794 */
795
796
797/**
798 * Initialize the object.
799 */
800bool org_virtualbox_SupDrv::init(OSDictionary *pDictionary)
801{
802 LogFlow(("org_virtualbox_SupDrv::init([%p], %p)\n", this, pDictionary));
803 if (IOService::init(pDictionary))
804 {
805 /* init members. */
806 return true;
807 }
808 return false;
809}
810
811
812/**
813 * Free the object.
814 */
815void org_virtualbox_SupDrv::free(void)
816{
817 LogFlow(("IOService::free([%p])\n", this));
818 IOService::free();
819}
820
821
822/**
823 * Check if it's ok to start this service.
824 * It's always ok by us, so it's up to IOService to decide really.
825 */
826IOService *org_virtualbox_SupDrv::probe(IOService *pProvider, SInt32 *pi32Score)
827{
828 LogFlow(("org_virtualbox_SupDrv::probe([%p])\n", this));
829 return IOService::probe(pProvider, pi32Score);
830}
831
832
833/**
834 * Start this service.
835 */
836bool org_virtualbox_SupDrv::start(IOService *pProvider)
837{
838 LogFlow(("org_virtualbox_SupDrv::start([%p])\n", this));
839
840 if (IOService::start(pProvider))
841 {
842 /* register the service. */
843 registerService();
844 return true;
845 }
846 return false;
847}
848
849
850/**
851 * Stop this service.
852 */
853void org_virtualbox_SupDrv::stop(IOService *pProvider)
854{
855 LogFlow(("org_virtualbox_SupDrv::stop([%p], %p)\n", this, pProvider));
856 IOService::stop(pProvider);
857}
858
859
860/**
861 * Termination request.
862 *
863 * @return true if we're ok with shutting down now, false if we're not.
864 * @param fOptions Flags.
865 */
866bool org_virtualbox_SupDrv::terminate(IOOptionBits fOptions)
867{
868 bool fRc;
869 LogFlow(("org_virtualbox_SupDrv::terminate: reference_count=%d g_cSessions=%d (fOptions=%#x)\n",
870 KMOD_INFO_NAME.reference_count, ASMAtomicUoReadS32(&g_cSessions), fOptions));
871 if ( KMOD_INFO_NAME.reference_count != 0
872 || ASMAtomicUoReadS32(&g_cSessions))
873 fRc = false;
874 else
875 fRc = IOService::terminate(fOptions);
876 LogFlow(("org_virtualbox_SupDrv::terminate: returns %d\n", fRc));
877 return fRc;
878}
879
880
881/*
882 *
883 * org_virtualbox_SupDrvClient
884 *
885 */
886
887
888/**
889 * Initializer called when the client opens the service.
890 */
891bool org_virtualbox_SupDrvClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type)
892{
893 LogFlow(("org_virtualbox_SupDrvClient::initWithTask([%p], %#x, %p, %#x) (cur pid=%d proc=%p)\n",
894 this, OwningTask, pvSecurityId, u32Type, RTProcSelf(), RTR0ProcHandleSelf()));
895 AssertMsg((RTR0PROCESS)OwningTask == RTR0ProcHandleSelf(), ("%p %p\n", OwningTask, RTR0ProcHandleSelf()));
896
897 if (!OwningTask)
898 return false;
899 if (IOUserClient::initWithTask(OwningTask, pvSecurityId , u32Type))
900 {
901 m_Task = OwningTask;
902 m_pSession = NULL;
903 m_pProvider = NULL;
904 return true;
905 }
906 return false;
907}
908
909
910/**
911 * Start the client service.
912 */
913bool org_virtualbox_SupDrvClient::start(IOService *pProvider)
914{
915 LogFlow(("org_virtualbox_SupDrvClient::start([%p], %p) (cur pid=%d proc=%p)\n",
916 this, pProvider, RTProcSelf(), RTR0ProcHandleSelf() ));
917 AssertMsgReturn((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(),
918 ("%p %p\n", m_Task, RTR0ProcHandleSelf()),
919 false);
920
921 if (IOUserClient::start(pProvider))
922 {
923 m_pProvider = OSDynamicCast(org_virtualbox_SupDrv, pProvider);
924 if (m_pProvider)
925 {
926 Assert(!m_pSession);
927
928 /*
929 * Create a new session.
930 */
931 int rc = supdrvCreateSession(&g_DevExt, true /* fUser */, &m_pSession);
932 if (RT_SUCCESS(rc))
933 {
934 m_pSession->fOpened = false;
935 /* The Uid and Gid fields are set on open. */
936
937 /*
938 * Insert it into the hash table, checking that there isn't
939 * already one for this process first.
940 */
941 unsigned iHash = SESSION_HASH(m_pSession->Process);
942 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
943 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
944
945 PSUPDRVSESSION pCur = g_apSessionHashTab[iHash];
946 if (pCur && pCur->Process != m_pSession->Process)
947 {
948 do pCur = pCur->pNextHash;
949 while (pCur && pCur->Process != m_pSession->Process);
950 }
951 if (!pCur)
952 {
953 m_pSession->pNextHash = g_apSessionHashTab[iHash];
954 g_apSessionHashTab[iHash] = m_pSession;
955 m_pSession->pvSupDrvClient = this;
956 ASMAtomicIncS32(&g_cSessions);
957 rc = VINF_SUCCESS;
958 }
959 else
960 rc = VERR_ALREADY_LOADED;
961
962 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
963 if (RT_SUCCESS(rc))
964 {
965 Log(("org_virtualbox_SupDrvClient::start: created session %p for pid %d\n", m_pSession, (int)RTProcSelf()));
966 return true;
967 }
968
969 LogFlow(("org_virtualbox_SupDrvClient::start: already got a session for this process (%p)\n", pCur));
970 supdrvCloseSession(&g_DevExt, m_pSession);
971 }
972
973 m_pSession = NULL;
974 LogFlow(("org_virtualbox_SupDrvClient::start: rc=%Rrc from supdrvCreateSession\n", rc));
975 }
976 else
977 LogFlow(("org_virtualbox_SupDrvClient::start: %p isn't org_virtualbox_SupDrv\n", pProvider));
978 }
979 return false;
980}
981
982
983/**
984 * Common worker for clientClose and VBoxDrvDarwinClose.
985 *
986 * It will
987 */
988/* static */ void org_virtualbox_SupDrvClient::sessionClose(RTPROCESS Process)
989{
990 /*
991 * Look for the session.
992 */
993 const unsigned iHash = SESSION_HASH(Process);
994 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
995 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
996 PSUPDRVSESSION pSession = g_apSessionHashTab[iHash];
997 if (pSession)
998 {
999 if (pSession->Process == Process)
1000 {
1001 g_apSessionHashTab[iHash] = pSession->pNextHash;
1002 pSession->pNextHash = NULL;
1003 ASMAtomicDecS32(&g_cSessions);
1004 }
1005 else
1006 {
1007 PSUPDRVSESSION pPrev = pSession;
1008 pSession = pSession->pNextHash;
1009 while (pSession)
1010 {
1011 if (pSession->Process == Process)
1012 {
1013 pPrev->pNextHash = pSession->pNextHash;
1014 pSession->pNextHash = NULL;
1015 ASMAtomicDecS32(&g_cSessions);
1016 break;
1017 }
1018
1019 /* next */
1020 pPrev = pSession;
1021 pSession = pSession->pNextHash;
1022 }
1023 }
1024 }
1025 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
1026 if (!pSession)
1027 {
1028 Log(("SupDrvClient::sessionClose: pSession == NULL, pid=%d; freed already?\n", (int)Process));
1029 return;
1030 }
1031
1032 /*
1033 * Remove it from the client object.
1034 */
1035 org_virtualbox_SupDrvClient *pThis = (org_virtualbox_SupDrvClient *)pSession->pvSupDrvClient;
1036 pSession->pvSupDrvClient = NULL;
1037 if (pThis)
1038 {
1039 Assert(pThis->m_pSession == pSession);
1040 pThis->m_pSession = NULL;
1041 }
1042
1043 /*
1044 * Close the session.
1045 */
1046 supdrvCloseSession(&g_DevExt, pSession);
1047}
1048
1049
1050/**
1051 * Client exits normally.
1052 */
1053IOReturn org_virtualbox_SupDrvClient::clientClose(void)
1054{
1055 LogFlow(("org_virtualbox_SupDrvClient::clientClose([%p]) (cur pid=%d proc=%p)\n", this, RTProcSelf(), RTR0ProcHandleSelf()));
1056 AssertMsg((RTR0PROCESS)m_Task == RTR0ProcHandleSelf(), ("%p %p\n", m_Task, RTR0ProcHandleSelf()));
1057
1058 /*
1059 * Clean up the session if it's still around.
1060 *
1061 * We cannot rely 100% on close, and in the case of a dead client
1062 * we'll end up hanging inside vm_map_remove() if we postpone it.
1063 */
1064 if (m_pSession)
1065 {
1066 sessionClose(RTProcSelf());
1067 Assert(!m_pSession);
1068 }
1069
1070 m_pProvider = NULL;
1071 terminate();
1072
1073 return kIOReturnSuccess;
1074}
1075
1076
1077/**
1078 * The client exits abnormally / forgets to do cleanups. (logging)
1079 */
1080IOReturn org_virtualbox_SupDrvClient::clientDied(void)
1081{
1082 LogFlow(("org_virtualbox_SupDrvClient::clientDied([%p]) m_Task=%p R0Process=%p Process=%d\n",
1083 this, m_Task, RTR0ProcHandleSelf(), RTProcSelf()));
1084
1085 /* IOUserClient::clientDied() calls clientClose, so we'll just do the work there. */
1086 return IOUserClient::clientDied();
1087}
1088
1089
1090/**
1091 * Terminate the service (initiate the destruction). (logging)
1092 */
1093bool org_virtualbox_SupDrvClient::terminate(IOOptionBits fOptions)
1094{
1095 LogFlow(("org_virtualbox_SupDrvClient::terminate([%p], %#x)\n", this, fOptions));
1096 return IOUserClient::terminate(fOptions);
1097}
1098
1099
1100/**
1101 * The final stage of the client service destruction. (logging)
1102 */
1103bool org_virtualbox_SupDrvClient::finalize(IOOptionBits fOptions)
1104{
1105 LogFlow(("org_virtualbox_SupDrvClient::finalize([%p], %#x)\n", this, fOptions));
1106 return IOUserClient::finalize(fOptions);
1107}
1108
1109
1110/**
1111 * Stop the client service. (logging)
1112 */
1113void org_virtualbox_SupDrvClient::stop(IOService *pProvider)
1114{
1115 LogFlow(("org_virtualbox_SupDrvClient::stop([%p])\n", this));
1116 IOUserClient::stop(pProvider);
1117}
1118
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette