VirtualBox

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

Last change on this file since 9334 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

File size: 27.6 KB
Line 
1/** @file
2 * VBox host drivers - Ring-0 support drivers - Darwin host:
3 * Darwin driver C code
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35/*
36 * Deal with conflicts first.
37 * PVM - BSD mess, that FreeBSD has correct a long time ago.
38 * iprt/types.h before sys/param.h - prevents UINT32_C and friends.
39 */
40#include <iprt/types.h>
41#include <sys/param.h>
42#undef PVM
43
44#include <IOKit/IOLib.h> /* Assert as function */
45
46#include "SUPDRV.h"
47#include <VBox/version.h>
48#include <iprt/initterm.h>
49#include <iprt/assert.h>
50#include <iprt/spinlock.h>
51#include <iprt/semaphore.h>
52#include <iprt/process.h>
53#include <iprt/alloc.h>
54
55#include <mach/kmod.h>
56#include <miscfs/devfs/devfs.h>
57#include <sys/conf.h>
58#include <sys/errno.h>
59#include <sys/ioccom.h>
60#include <sys/malloc.h>
61#include <sys/proc.h>
62#include <IOKit/IOService.h>
63#include <IOKit/IOUserclient.h>
64
65
66/*******************************************************************************
67* Defined Constants And Macros *
68*******************************************************************************/
69
70/** The module name. */
71#define DEVICE_NAME "vboxdrv"
72
73
74
75/*******************************************************************************
76* Internal Functions *
77*******************************************************************************/
78__BEGIN_DECLS
79static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData);
80static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData);
81
82static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
83static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
84static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
85static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess);
86
87static int VBoxDrvDarwinErr2DarwinErr(int rc);
88__END_DECLS
89
90
91/*******************************************************************************
92* Structures and Typedefs *
93*******************************************************************************/
94/**
95 * The service class.
96 * This is just a formality really.
97 */
98class org_virtualbox_SupDrv : public IOService
99{
100 OSDeclareDefaultStructors(org_virtualbox_SupDrv)
101
102public:
103 virtual bool init(OSDictionary *pDictionary = 0);
104 virtual void free(void);
105 virtual bool start(IOService *pProvider);
106 virtual void stop(IOService *pProvider);
107 virtual IOService *probe(IOService *pProvider, SInt32 *pi32Score);
108};
109
110OSDefineMetaClassAndStructors(org_virtualbox_SupDrv, IOService)
111
112
113/**
114 * An attempt at getting that clientDied() notification.
115 * I don't think it'll work as I cannot figure out where/what creates the correct
116 * port right.
117 */
118class org_virtualbox_SupDrvClient : public IOUserClient
119{
120 OSDeclareDefaultStructors(org_virtualbox_SupDrvClient)
121
122private:
123 PSUPDRVSESSION m_pSession; /**< The session. */
124 task_t m_Task; /**< The client task. */
125 org_virtualbox_SupDrv *m_pProvider; /**< The service provider. */
126
127public:
128 virtual bool initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type);
129 virtual bool start(IOService *pProvider);
130 virtual IOReturn clientClose(void);
131 virtual IOReturn clientDied(void);
132 virtual bool terminate(IOOptionBits fOptions = 0);
133 virtual bool finalize(IOOptionBits fOptions);
134 virtual void stop(IOService *pProvider);
135};
136
137OSDefineMetaClassAndStructors(org_virtualbox_SupDrvClient, IOUserClient)
138
139
140
141/*******************************************************************************
142* Global Variables *
143*******************************************************************************/
144/**
145 * Declare the module stuff.
146 */
147__BEGIN_DECLS
148extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
149extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
150__private_extern__ kmod_start_func_t *_realmain;
151__private_extern__ kmod_stop_func_t *_antimain;
152__private_extern__ int _kext_apple_cc;
153
154KMOD_EXPLICIT_DECL(VBoxDrv, VBOX_VERSION_STRING, _start, _stop)
155kmod_start_func_t *_realmain = VBoxDrvDarwinStart;
156kmod_stop_func_t *_antimain = VBoxDrvDarwinStop;
157int _kext_apple_cc = __APPLE_CC__;
158__END_DECLS
159
160
161/**
162 * Device extention & session data association structure.
163 */
164static SUPDRVDEVEXT g_DevExt;
165
166/**
167 * The character device switch table for the driver.
168 */
169static struct cdevsw g_DevCW =
170{
171 /** @todo g++ doesn't like this syntax - it worked with gcc before renaming to .cpp. */
172 /*.d_open = */VBoxDrvDarwinOpen,
173 /*.d_close = */VBoxDrvDarwinClose,
174 /*.d_read = */eno_rdwrt,
175 /*.d_write = */eno_rdwrt,
176 /*.d_ioctl = */VBoxDrvDarwinIOCtl,
177 /*.d_stop = */eno_stop,
178 /*.d_reset = */eno_reset,
179 /*.d_ttys = */NULL,
180 /*.d_select= */eno_select,
181 /*.d_mmap = */eno_mmap,
182 /*.d_strategy = */eno_strat,
183 /*.d_getc = */eno_getc,
184 /*.d_putc = */eno_putc,
185 /*.d_type = */0
186};
187
188/** Major device number. */
189static int g_iMajorDeviceNo = -1;
190/** Registered devfs device handle. */
191static void *g_hDevFsDevice = NULL;
192
193/** Spinlock protecting g_apSessionHashTab. */
194static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
195/** Hash table */
196static PSUPDRVSESSION g_apSessionHashTab[19];
197/** Calculates the index into g_apSessionHashTab.*/
198#define SESSION_HASH(pid) ((pid) % RT_ELEMENTS(g_apSessionHashTab))
199
200
201/**
202 * Start the kernel module.
203 */
204static kern_return_t VBoxDrvDarwinStart(struct kmod_info *pKModInfo, void *pvData)
205{
206 int rc;
207 dprintf(("VBoxDrvDarwinStart\n"));
208
209 /*
210 * Initialize IPRT.
211 */
212 rc = RTR0Init(0);
213 if (RT_SUCCESS(rc))
214 {
215 /*
216 * Initialize the device extension.
217 */
218 rc = supdrvInitDevExt(&g_DevExt);
219 if (RT_SUCCESS(rc))
220 {
221 /*
222 * Initialize the session hash table.
223 */
224 memset(g_apSessionHashTab, 0, sizeof(g_apSessionHashTab)); /* paranoia */
225 rc = RTSpinlockCreate(&g_Spinlock);
226 if (RT_SUCCESS(rc))
227 {
228 /*
229 * Registering ourselves as a character device.
230 */
231 g_iMajorDeviceNo = cdevsw_add(-1, &g_DevCW);
232 if (g_iMajorDeviceNo >= 0)
233 {
234 /** @todo the UID, GID and mode mask should be configurable! This isn't very secure... */
235 g_hDevFsDevice = devfs_make_node(makedev(g_iMajorDeviceNo, 0), DEVFS_CHAR,
236 UID_ROOT, GID_WHEEL, 0666, DEVICE_NAME);
237 if (g_hDevFsDevice)
238 {
239 OSDBGPRINT(("VBoxDrv: Successfully started. (major=%d)\n", g_iMajorDeviceNo));
240 return KMOD_RETURN_SUCCESS;
241 }
242
243 OSDBGPRINT(("VBoxDrv: devfs_make_node(makedev(%d,0),,,,%s) failed\n",
244 g_iMajorDeviceNo, DEVICE_NAME));
245 cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
246 g_iMajorDeviceNo = -1;
247 }
248 else
249 OSDBGPRINT(("VBoxDrv: cdevsw_add failed (%d)\n", g_iMajorDeviceNo));
250 RTSpinlockDestroy(g_Spinlock);
251 g_Spinlock = NIL_RTSPINLOCK;
252 }
253 else
254 OSDBGPRINT(("VBoxDrv: RTSpinlockCreate failed (rc=%d)\n", rc));
255 supdrvDeleteDevExt(&g_DevExt);
256 }
257 else
258 OSDBGPRINT(("VBoxDrv: failed to initialize device extension (rc=%d)\n", rc));
259 RTR0Term();
260 }
261 else
262 OSDBGPRINT(("VBoxDrv: failed to initialize IPRT (rc=%d)\n", rc));
263
264 memset(&g_DevExt, 0, sizeof(g_DevExt));
265 return KMOD_RETURN_FAILURE;
266}
267
268
269/**
270 * Stop the kernel module.
271 */
272static kern_return_t VBoxDrvDarwinStop(struct kmod_info *pKModInfo, void *pvData)
273{
274 int rc;
275 dprintf(("VBoxDrvDarwinStop\n"));
276
277 /** @todo I've got a nagging feeling that we'll have to keep track of users and refuse
278 * unloading if we're busy. Investigate and implement this! */
279
280 /*
281 * Undo the work done during start (in reverse order).
282 */
283 devfs_remove(g_hDevFsDevice);
284 g_hDevFsDevice = NULL;
285
286 rc = cdevsw_remove(g_iMajorDeviceNo, &g_DevCW);
287 Assert(rc == g_iMajorDeviceNo);
288 g_iMajorDeviceNo = -1;
289
290 supdrvDeleteDevExt(&g_DevExt);
291
292 rc = RTSpinlockDestroy(g_Spinlock);
293 AssertRC(rc);
294 g_Spinlock = NIL_RTSPINLOCK;
295
296 RTR0Term();
297
298 memset(&g_DevExt, 0, sizeof(g_DevExt));
299 dprintf(("VBoxDrvDarwinStop - done\n"));
300 return KMOD_RETURN_SUCCESS;
301}
302
303
304/**
305 * Device open. Called on open /dev/vboxdrv
306 *
307 * @param pInode Pointer to inode info structure.
308 * @param pFilp Associated file pointer.
309 */
310static int VBoxDrvDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
311{
312 int rc;
313 PSUPDRVSESSION pSession;
314#ifdef DEBUG_DARWIN_GIP
315 char szName[128];
316 szName[0] = '\0';
317 proc_name(proc_pid(pProcess), szName, sizeof(szName));
318 dprintf(("VBoxDrvDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
319#endif
320
321 /*
322 * Create a new session.
323 */
324 rc = supdrvCreateSession(&g_DevExt, &pSession);
325 if (RT_SUCCESS(rc))
326 {
327 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
328 unsigned iHash;
329 struct ucred *pCred = proc_ucred(pProcess);
330 if (pCred)
331 {
332 pSession->Uid = pCred->cr_uid;
333 pSession->Gid = pCred->cr_gid;
334 }
335 pSession->Process = RTProcSelf();
336 pSession->R0Process = RTR0ProcHandleSelf();
337
338 /*
339 * Insert it into the hash table.
340 */
341 iHash = SESSION_HASH(pSession->Process);
342 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
343 pSession->pNextHash = g_apSessionHashTab[iHash];
344 g_apSessionHashTab[iHash] = pSession;
345 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
346 }
347
348#ifdef DEBUG_DARWIN_GIP
349 OSDBGPRINT(("VBoxDrvDarwinOpen: pid=%d '%s' pSession=%p rc=%d\n", proc_pid(pProcess), szName, pSession, rc));
350#else
351 dprintf(("VBoxDrvDarwinOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, proc_pid(pProcess)));
352#endif
353 return VBoxDrvDarwinErr2DarwinErr(rc);
354}
355
356
357/**
358 * Close device.
359 */
360static int VBoxDrvDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
361{
362 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
363 const RTPROCESS Process = proc_pid(pProcess);
364 const unsigned iHash = SESSION_HASH(Process);
365 PSUPDRVSESSION pSession;
366
367 dprintf(("VBoxDrvDarwinClose: pid=%d\n", (int)Process));
368
369 /*
370 * Remove from the hash table.
371 */
372 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
373 pSession = g_apSessionHashTab[iHash];
374 if (pSession)
375 {
376 if (pSession->Process == Process)
377 {
378 g_apSessionHashTab[iHash] = pSession->pNextHash;
379 pSession->pNextHash = NULL;
380 }
381 else
382 {
383 PSUPDRVSESSION pPrev = pSession;
384 pSession = pSession->pNextHash;
385 while (pSession)
386 {
387 if (pSession->Process == Process)
388 {
389 pPrev->pNextHash = pSession->pNextHash;
390 pSession->pNextHash = NULL;
391 break;
392 }
393
394 /* next */
395 pPrev = pSession;
396 pSession = pSession->pNextHash;
397 }
398 }
399 }
400 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
401 if (!pSession)
402 {
403 OSDBGPRINT(("VBoxDrvDarwinClose: WHAT?!? pSession == NULL! This must be a mistake... pid=%d (close)\n",
404 (int)Process));
405 return EINVAL;
406 }
407
408 /*
409 * Close the session.
410 */
411 supdrvCloseSession(&g_DevExt, pSession);
412 return 0;
413}
414
415
416/**
417 * Device I/O Control entry point.
418 *
419 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
420 * @param Dev The device number (major+minor).
421 * @param iCmd The IOCtl command.
422 * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
423 * @param fFlags Flag saying we're a character device (like we didn't know already).
424 * @param pProcess The process issuing this request.
425 */
426static int VBoxDrvDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
427{
428 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
429 const RTPROCESS Process = proc_pid(pProcess);
430 const unsigned iHash = SESSION_HASH(Process);
431 PSUPDRVSESSION pSession;
432
433 /*
434 * Find the session.
435 */
436 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
437 pSession = g_apSessionHashTab[iHash];
438 if (pSession && pSession->Process != Process)
439 {
440 do pSession = pSession->pNextHash;
441 while (pSession && pSession->Process != Process);
442 }
443 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
444 if (!pSession)
445 {
446 OSDBGPRINT(("VBoxDrvDarwinIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
447 (int)Process, iCmd));
448 return EINVAL;
449 }
450
451 /*
452 * Deal with the two high-speed IOCtl that takes it's arguments from
453 * the session and iCmd, and only returns a VBox status code.
454 */
455 if ( iCmd == SUP_IOCTL_FAST_DO_RAW_RUN
456 || iCmd == SUP_IOCTL_FAST_DO_HWACC_RUN
457 || iCmd == SUP_IOCTL_FAST_DO_NOP)
458 return supdrvIOCtlFast(iCmd, &g_DevExt, pSession);
459 return VBoxDrvDarwinIOCtlSlow(pSession, iCmd, pData, pProcess);
460}
461
462
463/**
464 * Worker for VBoxDrvDarwinIOCtl that takes the slow IOCtl functions.
465 *
466 * @returns Darwin errno.
467 *
468 * @param pSession The session.
469 * @param iCmd The IOCtl command.
470 * @param pData Pointer to the kernel copy of the SUPDRVIOCTLDATA buffer.
471 * @param pProcess The calling process.
472 */
473static int VBoxDrvDarwinIOCtlSlow(PSUPDRVSESSION pSession, u_long iCmd, caddr_t pData, struct proc *pProcess)
474{
475 dprintf(("VBoxDrvDarwinIOCtlSlow: pSession=%p iCmd=%p pData=%p pProcess=%p\n", pSession, iCmd, pData, pProcess));
476
477
478 /*
479 * Buffered or unbuffered?
480 */
481 PSUPREQHDR pHdr;
482 user_addr_t pUser = 0;
483 void *pvPageBuf = NULL;
484 uint32_t cbReq = IOCPARM_LEN(iCmd);
485 if ((IOC_DIRMASK & iCmd) == IOC_INOUT)
486 {
487 pHdr = (PSUPREQHDR)pData;
488 if (RT_UNLIKELY(cbReq < sizeof(*pHdr)))
489 {
490 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: cbReq=%#x < %#x; iCmd=%#lx\n", cbReq, (int)sizeof(*pHdr), iCmd));
491 return EINVAL;
492 }
493 if (RT_UNLIKELY((pHdr->fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
494 {
495 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", pHdr->fFlags, iCmd));
496 return EINVAL;
497 }
498 if (RT_UNLIKELY( RT_MAX(pHdr->cbIn, pHdr->cbOut) != cbReq
499 || pHdr->cbIn < sizeof(*pHdr)
500 || pHdr->cbOut < sizeof(*pHdr)))
501 {
502 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x) != %#x; iCmd=%#lx\n", pHdr->cbIn, pHdr->cbOut, cbReq, iCmd));
503 return EINVAL;
504 }
505 }
506 else if ((IOC_DIRMASK & iCmd) == IOC_VOID && !cbReq)
507 {
508 /*
509 * Get the header and figure out how much we're gonna have to read.
510 */
511 SUPREQHDR Hdr;
512 pUser = (user_addr_t)*(void **)pData;
513 int rc = copyin(pUser, &Hdr, sizeof(Hdr));
514 if (RT_UNLIKELY(rc))
515 {
516 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,Hdr,) -> %#x; iCmd=%#lx\n", (unsigned long long)pUser, rc, iCmd));
517 return rc;
518 }
519 if (RT_UNLIKELY((Hdr.fFlags & SUPREQHDR_FLAGS_MAGIC_MASK) != SUPREQHDR_FLAGS_MAGIC))
520 {
521 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: bad magic fFlags=%#x; iCmd=%#lx\n", Hdr.fFlags, iCmd));
522 return EINVAL;
523 }
524 cbReq = RT_MAX(Hdr.cbIn, Hdr.cbOut);
525 if (RT_UNLIKELY( Hdr.cbIn < sizeof(Hdr)
526 || Hdr.cbOut < sizeof(Hdr)
527 || cbReq > _1M*16))
528 {
529 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: max(%#x,%#x); iCmd=%#lx\n", Hdr.cbIn, Hdr.cbOut, iCmd));
530 return EINVAL;
531 }
532
533 /*
534 * Allocate buffer and copy in the data.
535 */
536 pHdr = (PSUPREQHDR)RTMemTmpAlloc(cbReq);
537 if (!pHdr)
538 pvPageBuf = pHdr = (PSUPREQHDR)IOMallocAligned(RT_ALIGN_Z(cbReq, PAGE_SIZE), 8);
539 if (RT_UNLIKELY(!pHdr))
540 {
541 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: failed to allocate buffer of %d bytes; iCmd=%#lx\n", cbReq, iCmd));
542 return ENOMEM;
543 }
544 rc = copyin(pUser, pHdr, Hdr.cbIn);
545 if (RT_UNLIKELY(rc))
546 {
547 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyin(%llx,%p,%#x) -> %#x; iCmd=%#lx\n",
548 (unsigned long long)pUser, pHdr, Hdr.cbIn, rc, iCmd));
549 if (pvPageBuf)
550 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
551 else
552 RTMemTmpFree(pHdr);
553 return rc;
554 }
555 }
556 else
557 {
558 dprintf(("VBoxDrvDarwinIOCtlSlow: huh? cbReq=%#x iCmd=%#lx\n", cbReq, iCmd));
559 return EINVAL;
560 }
561
562 /*
563 * Process the IOCtl.
564 */
565 int rc = supdrvIOCtl(iCmd, &g_DevExt, pSession, pHdr);
566 if (RT_LIKELY(!rc))
567 {
568 /*
569 * If not buffered, copy back the buffer before returning.
570 */
571 if (pUser)
572 {
573 uint32_t cbOut = pHdr->cbOut;
574 if (cbOut > cbReq)
575 {
576 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: too much output! %#x > %#x; uCmd=%#lx!\n", cbOut, cbReq, iCmd));
577 cbOut = cbReq;
578 }
579 rc = copyout(pHdr, pUser, cbOut);
580 if (RT_UNLIKELY(rc))
581 OSDBGPRINT(("VBoxDrvDarwinIOCtlSlow: copyout(%p,%llx,%#x) -> %d; uCmd=%#lx!\n",
582 pHdr, (unsigned long long)pUser, cbOut, rc, iCmd));
583
584 /* cleanup */
585 if (pvPageBuf)
586 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
587 else
588 RTMemTmpFree(pHdr);
589 }
590 }
591 else
592 {
593 /*
594 * The request failed, just clean up.
595 */
596 if (pUser)
597 {
598 if (pvPageBuf)
599 IOFreeAligned(pvPageBuf, RT_ALIGN_Z(cbReq, PAGE_SIZE));
600 else
601 RTMemTmpFree(pHdr);
602 }
603
604 dprintf(("VBoxDrvDarwinIOCtlSlow: pid=%d iCmd=%lx pData=%p failed, rc=%d\n", proc_pid(pProcess), iCmd, (void *)pData, rc));
605 rc = EINVAL;
606 }
607
608 dprintf2(("VBoxDrvDarwinIOCtlSlow: returns %d\n", rc));
609 return rc;
610}
611
612
613
614/**
615 * Initializes any OS specific object creator fields.
616 */
617void VBOXCALL supdrvOSObjInitCreator(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession)
618{
619 NOREF(pObj);
620 NOREF(pSession);
621}
622
623
624/**
625 * Checks if the session can access the object.
626 *
627 * @returns true if a decision has been made.
628 * @returns false if the default access policy should be applied.
629 *
630 * @param pObj The object in question.
631 * @param pSession The session wanting to access the object.
632 * @param pszObjName The object name, can be NULL.
633 * @param prc Where to store the result when returning true.
634 */
635bool VBOXCALL supdrvOSObjCanAccess(PSUPDRVOBJ pObj, PSUPDRVSESSION pSession, const char *pszObjName, int *prc)
636{
637 NOREF(pObj);
638 NOREF(pSession);
639 NOREF(pszObjName);
640 NOREF(prc);
641 return false;
642}
643
644
645/**
646 * Converts a supdrv error code to a darwin error code.
647 *
648 * @returns corresponding darwin error code.
649 * @param rc supdrv error code (SUPDRV_ERR_* defines).
650 */
651static int VBoxDrvDarwinErr2DarwinErr(int rc)
652{
653 switch (rc)
654 {
655 case 0: return 0;
656 case SUPDRV_ERR_GENERAL_FAILURE: return EACCES;
657 case SUPDRV_ERR_INVALID_PARAM: return EINVAL;
658 case SUPDRV_ERR_INVALID_MAGIC: return EILSEQ;
659 case SUPDRV_ERR_INVALID_HANDLE: return ENXIO;
660 case SUPDRV_ERR_INVALID_POINTER: return EFAULT;
661 case SUPDRV_ERR_LOCK_FAILED: return ENOLCK;
662 case SUPDRV_ERR_ALREADY_LOADED: return EEXIST;
663 case SUPDRV_ERR_PERMISSION_DENIED: return EPERM;
664 case SUPDRV_ERR_VERSION_MISMATCH: return ENOSYS;
665 }
666
667 return EPERM;
668}
669
670
671/** @todo move this to assembly where a simple "jmp printf" will to the trick. */
672RTDECL(int) SUPR0Printf(const char *pszFormat, ...)
673{
674 va_list args;
675 char szMsg[512];
676
677 va_start(args, pszFormat);
678 vsnprintf(szMsg, sizeof(szMsg) - 1, pszFormat, args);
679 va_end(args);
680
681 szMsg[sizeof(szMsg) - 1] = '\0';
682 printf("%s", szMsg);
683 return 0;
684}
685
686
687/** Runtime assert implementation for Darwin Ring-0. */
688RTDECL(void) AssertMsg1(const char *pszExpr, unsigned uLine, const char *pszFile, const char *pszFunction)
689{
690 printf("!!Assertion Failed!!\n"
691 "Expression: %s\n"
692 "Location : %s(%d) %s\n",
693 pszExpr, pszFile, uLine, pszFunction);
694}
695
696
697/** Runtime assert implementation for the Darwin Ring-0 driver.
698 * @todo this one needs fixing! */
699RTDECL(void) AssertMsg2(const char *pszFormat, ...)
700{ /* forwarder. */
701 va_list ap;
702 char msg[256];
703
704 va_start(ap, pszFormat);
705 vsnprintf(msg, sizeof(msg) - 1, pszFormat, ap);
706 msg[sizeof(msg) - 1] = '\0';
707 printf("%s", msg);
708 va_end(ap);
709}
710
711
712/*
713 *
714 * org_virtualbox_SupDrv
715 *
716 */
717
718
719/**
720 * Initialize the object.
721 */
722bool org_virtualbox_SupDrv::init(OSDictionary *pDictionary)
723{
724 dprintf(("org_virtualbox_SupDrv::init([%p], %p)\n", this, pDictionary));
725 if (IOService::init(pDictionary))
726 {
727 /* init members. */
728 return true;
729 }
730 return false;
731}
732
733
734/**
735 * Free the object.
736 */
737void org_virtualbox_SupDrv::free(void)
738{
739 dprintf(("IOService::free([%p])\n", this));
740 IOService::free();
741}
742
743
744/**
745 * Check if it's ok to start this service.
746 * It's always ok by us, so it's up to IOService to decide really.
747 */
748IOService *org_virtualbox_SupDrv::probe(IOService *pProvider, SInt32 *pi32Score)
749{
750 dprintf(("org_virtualbox_SupDrv::probe([%p])\n", this));
751 return IOService::probe(pProvider, pi32Score);
752}
753
754
755/**
756 * Start this service.
757 */
758bool org_virtualbox_SupDrv::start(IOService *pProvider)
759{
760 dprintf(("org_virtualbox_SupDrv::start([%p])\n", this));
761
762 if (IOService::start(pProvider))
763 {
764 /* register the service. */
765 registerService();
766 return true;
767 }
768 return false;
769}
770
771
772/**
773 * Stop this service.
774 */
775void org_virtualbox_SupDrv::stop(IOService *pProvider)
776{
777 dprintf(("org_virtualbox_SupDrv::stop([%p], %p)\n", this, pProvider));
778 IOService::stop(pProvider);
779}
780
781
782/*
783 *
784 * org_virtualbox_SupDrvClient
785 *
786 */
787
788
789/**
790 * Initializer called when the client opens the service.
791 */
792bool org_virtualbox_SupDrvClient::initWithTask(task_t OwningTask, void *pvSecurityId, UInt32 u32Type)
793{
794 dprintf(("org_virtualbox_SupDrvClient::initWithTask([%p], %#x, %p, %#x)\n", this, OwningTask, pvSecurityId, u32Type));
795
796 if (!OwningTask)
797 return false;
798 if (IOUserClient::initWithTask(OwningTask, pvSecurityId , u32Type))
799 {
800 m_Task = OwningTask;
801 m_pSession = NULL;
802 m_pProvider = NULL;
803 return true;
804 }
805 return false;
806}
807
808
809/**
810 * Start the client service.
811 */
812bool org_virtualbox_SupDrvClient::start(IOService *pProvider)
813{
814 dprintf(("org_virtualbox_SupDrvClient::start([%p], %p)\n", this, pProvider));
815 if (IOUserClient::start(pProvider))
816 {
817 m_pProvider = OSDynamicCast(org_virtualbox_SupDrv, pProvider);
818 if (m_pProvider)
819 {
820 /* this is where we could create the section. */
821 return true;
822 }
823 dprintf(("org_virtualbox_SupDrvClient::start: %p isn't org_virtualbox_SupDrv\n", pProvider));
824 }
825 return false;
826}
827
828
829/**
830 * Client exits normally.
831 */
832IOReturn org_virtualbox_SupDrvClient::clientClose(void)
833{
834 dprintf(("org_virtualbox_SupDrvClient::clientClose([%p])\n", this));
835
836 m_pProvider = NULL;
837 terminate();
838
839 return kIOReturnSuccess;
840}
841
842
843/**
844 * The client exits abnormally / forgets to do cleanups.
845 */
846IOReturn org_virtualbox_SupDrvClient::clientDied(void)
847{
848 dprintf(("org_virtualbox_SupDrvClient::clientDied([%p]) m_Task=%p R0Process=%p Process=%d\n",
849 this, m_Task, RTR0ProcHandleSelf(), RTProcSelf()));
850
851 /*
852 * Do early session cleanup (if there is a session) so
853 * we avoid hanging in vm_map_remove().
854 */
855 const RTR0PROCESS R0Process = (RTR0PROCESS)m_Task;
856 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
857 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
858 for (unsigned i = 0; i < RT_ELEMENTS(g_apSessionHashTab); i++)
859 {
860 for (PSUPDRVSESSION pSession = g_apSessionHashTab[i]; pSession; pSession = pSession->pNextHash)
861 {
862 dprintf2(("pSession=%p R0Process=%p (=? %p)\n", pSession, pSession->R0Process, R0Process));
863 if (pSession->R0Process == R0Process)
864 {
865 /*
866 * It is safe to leave the spinlock here; the session shouldn't be able
867 * to go away while we're cleaning it up, changes to pNextHash will not
868 * harm us, and new sessions can't possibly be added for this process.
869 */
870 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
871 supdrvCleanupSession(&g_DevExt, pSession);
872 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
873 }
874 }
875 }
876 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
877
878 /* IOUserClient::clientDied() calls close... */
879 return IOUserClient::clientDied();
880}
881
882
883/**
884 * Terminate the service (initiate the destruction).
885 */
886bool org_virtualbox_SupDrvClient::terminate(IOOptionBits fOptions)
887{
888 dprintf(("org_virtualbox_SupDrvClient::terminate([%p], %#x)\n", this, fOptions));
889 return IOUserClient::terminate(fOptions);
890}
891
892
893/**
894 * The final stage of the client service destruction.
895 */
896bool org_virtualbox_SupDrvClient::finalize(IOOptionBits fOptions)
897{
898 dprintf(("org_virtualbox_SupDrvClient::finalize([%p], %#x)\n", this, fOptions));
899 return IOUserClient::finalize(fOptions);
900}
901
902
903/**
904 * Stop the client service.
905 */
906void org_virtualbox_SupDrvClient::stop(IOService *pProvider)
907{
908 dprintf(("org_virtualbox_SupDrvClient::stop([%p])\n", this));
909 IOUserClient::stop(pProvider);
910}
911
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