VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris.c@ 10639

Last change on this file since 10639 was 8351, checked in by vboxsync, 17 years ago

Additions/common: moved guest cap disabling into common VBoxGuest.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 35.8 KB
Line 
1/* $Id: VBoxGuest-solaris.c 8351 2008-04-24 09:32:22Z vboxsync $ */
2/** @file
3 * VirtualBox Guest Additions Driver for Solaris.
4 */
5
6/*
7 * Copyright (C) 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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include <sys/conf.h>
27#include <sys/modctl.h>
28#include <sys/mutex.h>
29#include <sys/pci.h>
30#include <sys/stat.h>
31#include <sys/ddi.h>
32#include <sys/ddi_intr.h>
33#include <sys/sunddi.h>
34#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
35
36#include "VBoxGuestInternal.h"
37#include <VBox/log.h>
38#include <iprt/assert.h>
39#include <iprt/initterm.h>
40#include <iprt/process.h>
41#include <iprt/mem.h>
42
43
44/*******************************************************************************
45* Defined Constants And Macros *
46*******************************************************************************/
47/** The module name. */
48#define DEVICE_NAME "vboxguest"
49/** The module description as seen in 'modinfo'. */
50#define DEVICE_DESC "VirtualBox Guest Driver"
51
52
53/*******************************************************************************
54* Internal Functions *
55*******************************************************************************/
56static int VBoxGuestSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
57static int VBoxGuestSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
58static int VBoxGuestSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
59static int VBoxGuestSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
60static int VBoxGuestSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal);
61
62static int VBoxGuestSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
63static int VBoxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
64static int VBoxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
65
66static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip, void *pvState);
67static void VBoxGuestSolarisRemoveIRQ(dev_info_t *pDip, void *pvState);
68static uint_t VBoxGuestSolarisISR(caddr_t Arg);
69
70DECLVBGL(int) VBoxGuestSolarisServiceCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned);
71DECLVBGL(void *) VBoxGuestSolarisServiceOpen(uint32_t *pu32Version);
72DECLVBGL(int) VBoxGuestSolarisServiceClose(void *pvSession);
73
74
75/*******************************************************************************
76* Structures and Typedefs *
77*******************************************************************************/
78/**
79 * cb_ops: for drivers that support char/block entry points
80 */
81static struct cb_ops g_VBoxGuestSolarisCbOps =
82{
83 VBoxGuestSolarisOpen,
84 VBoxGuestSolarisClose,
85 nodev, /* b strategy */
86 nodev, /* b dump */
87 nodev, /* b print */
88 VBoxGuestSolarisRead,
89 VBoxGuestSolarisWrite,
90 VBoxGuestSolarisIOCtl,
91 nodev, /* c devmap */
92 nodev, /* c mmap */
93 nodev, /* c segmap */
94 nochpoll, /* c poll */
95 ddi_prop_op, /* property ops */
96 NULL, /* streamtab */
97 D_NEW | D_MP, /* compat. flag */
98 CB_REV /* revision */
99};
100
101/**
102 * dev_ops: for driver device operations
103 */
104static struct dev_ops g_VBoxGuestSolarisDevOps =
105{
106 DEVO_REV, /* driver build revision */
107 0, /* ref count */
108 VBoxGuestSolarisGetInfo,
109 nulldev, /* identify */
110 nulldev, /* probe */
111 VBoxGuestSolarisAttach,
112 VBoxGuestSolarisDetach,
113 nodev, /* reset */
114 &g_VBoxGuestSolarisCbOps,
115 (struct bus_ops *)0,
116 nodev /* power */
117};
118
119/**
120 * modldrv: export driver specifics to the kernel
121 */
122static struct modldrv g_VBoxGuestSolarisModule =
123{
124 &mod_driverops, /* extern from kernel */
125 DEVICE_DESC,
126 &g_VBoxGuestSolarisDevOps
127};
128
129/**
130 * modlinkage: export install/remove/info to the kernel
131 */
132static struct modlinkage g_VBoxGuestSolarisModLinkage =
133{
134 MODREV_1, /* loadable module system revision */
135 &g_VBoxGuestSolarisModule,
136 NULL /* terminate array of linkage structures */
137};
138
139/**
140 * State info for each open file handle.
141 */
142typedef struct
143{
144 /** IO port handle. */
145 ddi_acc_handle_t PciIOHandle;
146 /** MMIO handle. */
147 ddi_acc_handle_t PciMMIOHandle;
148#if 0
149 /** Interrupt block cookie. */
150 ddi_iblock_cookie_t BlockCookie;
151#endif
152 /** Driver Mutex. */
153 kmutex_t Mtx;
154 /** IO Port. */
155 uint16_t uIOPortBase;
156 /** Address of the MMIO region.*/
157 caddr_t pMMIOBase;
158 /** Size of the MMIO region. */
159 off_t cbMMIO;
160 /** VMMDev Version. */
161 uint32_t u32Version;
162 /** Pointer to the interrupt handle vector */
163 ddi_intr_handle_t *pIntr;
164 /** Number of actually allocated interrupt handles */
165 size_t cIntrAllocated;
166#ifndef USE_SESSION_HASH
167 /** Pointer to the session handle. */
168 PVBOXGUESTSESSION pSession;
169#endif
170} vboxguest_state_t;
171
172
173/*******************************************************************************
174* Global Variables *
175*******************************************************************************/
176/** Device handle (we support only one instance). */
177static dev_info_t *g_pDip;
178
179/** Opaque pointer to state */
180static void *g_pVBoxGuestSolarisState;
181
182/** Device extention & session data association structure. */
183static VBOXGUESTDEVEXT g_DevExt;
184/** Spinlock protecting g_apSessionHashTab. */
185static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
186#ifdef USE_SESSION_HASH
187/** Hash table */
188static PVBOXGUESTSESSION g_apSessionHashTab[19];
189/** Calculates the index into g_apSessionHashTab.*/
190#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
191#endif /* USE_SESSION_HASH */
192
193/** GCC C++ hack. */
194unsigned __gxx_personality_v0 = 0xdecea5ed;
195
196/**
197 * Kernel entry points
198 */
199int _init(void)
200{
201 LogFlow((DEVICE_NAME ":_init\n"));
202 int rc = ddi_soft_state_init(&g_pVBoxGuestSolarisState, sizeof(vboxguest_state_t), 1);
203 if (!rc)
204 {
205 rc = mod_install(&g_VBoxGuestSolarisModLinkage);
206 if (rc)
207 ddi_soft_state_fini(&g_pVBoxGuestSolarisState);
208 }
209 return rc;
210}
211
212
213int _fini(void)
214{
215 LogFlow((DEVICE_NAME ":_fini\n"));
216 int rc = mod_remove(&g_VBoxGuestSolarisModLinkage);
217 if (!rc)
218 ddi_soft_state_fini(&g_pVBoxGuestSolarisState);
219 return rc;
220}
221
222
223int _info(struct modinfo *pModInfo)
224{
225 LogFlow((DEVICE_NAME ":_info\n"));
226 return mod_info(&g_VBoxGuestSolarisModLinkage, pModInfo);
227}
228
229
230/**
231 * Attach entry point, to attach a device to the system or resume it.
232 *
233 * @param pDip The module structure instance.
234 * @param enmCmd Attach type (ddi_attach_cmd_t)
235 *
236 * @return corresponding solaris error code.
237 */
238static int VBoxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
239{
240 LogFlow((DEVICE_NAME ":VBoxGuestSolarisAttach\n"));
241 switch (enmCmd)
242 {
243 case DDI_ATTACH:
244 {
245 int rc;
246 int instance;
247 vboxguest_state_t *pState;
248
249 instance = ddi_get_instance(pDip);
250#ifdef USE_SESSION_HASH
251 rc = ddi_soft_state_zalloc(g_pVBoxGuestSolarisState, instance);
252 if (rc != DDI_SUCCESS)
253 {
254 Log((DEVICE_NAME ":ddi_soft_state_zalloc failed.\n"));
255 return DDI_FAILURE;
256 }
257
258 pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, instance);
259 if (!pState)
260 {
261 ddi_soft_state_free(g_pVBoxGuestSolarisState, instance);
262 Log((DEVICE_NAME ":ddi_get_soft_state for instance %d failed\n", instance));
263 return DDI_FAILURE;
264 }
265#else
266 pState = RTMemAllocZ(sizeof(vboxguest_state_t));
267 if (!pState)
268 {
269 Log((DEVICE_NAME ":RTMemAllocZ failed to allocate %d bytes\n", sizeof(vboxguest_state_t)));
270 return DDI_FAILURE;
271 }
272#endif
273
274 /*
275 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
276 */
277 rc = RTR0Init(0);
278 if (RT_FAILURE(rc))
279 {
280 Log((DEVICE_NAME ":RTR0Init failed.\n"));
281 return DDI_FAILURE;
282 }
283
284 /*
285 * Initialize the session hash table.
286 */
287 rc = RTSpinlockCreate(&g_Spinlock);
288 if (RT_SUCCESS(rc))
289 {
290 /*
291 * Enable resources for PCI access.
292 */
293 ddi_acc_handle_t PciHandle;
294 rc = pci_config_setup(pDip, &PciHandle);
295 if (rc == DDI_SUCCESS)
296 {
297 /*
298 * Map the register address space.
299 */
300 caddr_t baseAddr;
301 ddi_device_acc_attr_t deviceAttr;
302 deviceAttr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
303 deviceAttr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
304 deviceAttr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
305 deviceAttr.devacc_attr_access = DDI_DEFAULT_ACC;
306 rc = ddi_regs_map_setup(pDip, 1, &baseAddr, 0, 0, &deviceAttr, &pState->PciIOHandle);
307 if (rc == DDI_SUCCESS)
308 {
309 /*
310 * Read size of the MMIO region.
311 */
312 pState->uIOPortBase = (uintptr_t)baseAddr;
313 rc = ddi_dev_regsize(pDip, 2, &pState->cbMMIO);
314 if (rc == DDI_SUCCESS)
315 {
316 rc = ddi_regs_map_setup(pDip, 2, &pState->pMMIOBase, 0, pState->cbMMIO, &deviceAttr,
317 &pState->PciMMIOHandle);
318 if (rc == DDI_SUCCESS)
319 {
320 /*
321 * Add IRQ of VMMDev.
322 */
323 rc = VBoxGuestSolarisAddIRQ(pDip, pState);
324 if (rc == DDI_SUCCESS)
325 {
326 /*
327 * Call the common device extension initializer.
328 */
329 rc = VBoxGuestInitDevExt(&g_DevExt, pState->uIOPortBase, pState->pMMIOBase,
330 pState->cbMMIO, VBOXOSTYPE_Solaris);
331 if (RT_SUCCESS(rc))
332 {
333 rc = ddi_create_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, 0);
334 if (rc == DDI_SUCCESS)
335 {
336 g_pDip = pDip;
337 ddi_set_driver_private(pDip, pState);
338 pci_config_teardown(&PciHandle);
339 ddi_report_dev(pDip);
340 return DDI_SUCCESS;
341 }
342
343 LogRel((DEVICE_NAME ":ddi_create_minor_node failed.\n"));
344 }
345 else
346 LogRel((DEVICE_NAME ":VBoxGuestInitDevExt failed.\n"));
347 VBoxGuestSolarisRemoveIRQ(pDip, pState);
348 }
349 else
350 LogRel((DEVICE_NAME ":VBoxGuestSolarisAddIRQ failed.\n"));
351 ddi_regs_map_free(&pState->PciMMIOHandle);
352 }
353 else
354 LogRel((DEVICE_NAME ":ddi_regs_map_setup for MMIO region failed.\n"));
355 }
356 else
357 LogRel((DEVICE_NAME ":ddi_dev_regsize for MMIO region failed.\n"));
358 ddi_regs_map_free(&pState->PciIOHandle);
359 }
360 else
361 LogRel((DEVICE_NAME ":ddi_regs_map_setup for IOport failed.\n"));
362 pci_config_teardown(&PciHandle);
363 }
364 else
365 LogRel((DEVICE_NAME ":pci_config_setup failed rc=%d.\n", rc));
366 RTSpinlockDestroy(g_Spinlock);
367 g_Spinlock = NIL_RTSPINLOCK;
368 }
369 else
370 LogRel((DEVICE_NAME ":RTSpinlockCreate failed.\n"));
371
372 RTR0Term();
373 return DDI_FAILURE;
374 }
375
376 case DDI_RESUME:
377 {
378 /** @todo implement resume for guest driver. */
379 return DDI_SUCCESS;
380 }
381
382 default:
383 return DDI_FAILURE;
384 }
385}
386
387
388/**
389 * Detach entry point, to detach a device to the system or suspend it.
390 *
391 * @param pDip The module structure instance.
392 * @param enmCmd Attach type (ddi_attach_cmd_t)
393 *
394 * @return corresponding solaris error code.
395 */
396static int VBoxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
397{
398 LogFlow((DEVICE_NAME ":VBoxGuestSolarisDetach\n"));
399 switch (enmCmd)
400 {
401 case DDI_DETACH:
402 {
403 int rc;
404 int instance = ddi_get_instance(pDip);
405#ifdef USE_SESSION_HASH
406 vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, instance);
407#else
408 vboxguest_state_t *pState = ddi_get_driver_private(g_pDip);
409#endif
410 if (pState)
411 {
412 VBoxGuestSolarisRemoveIRQ(pDip, pState);
413 ddi_regs_map_free(&pState->PciIOHandle);
414 ddi_regs_map_free(&pState->PciMMIOHandle);
415 ddi_remove_minor_node(pDip, NULL);
416#ifdef USE_SESSION_HASH
417 ddi_soft_state_free(g_pVBoxGuestSolarisState, instance);
418#else
419 RTMemFree(pState);
420#endif
421
422 rc = RTSpinlockDestroy(g_Spinlock);
423 AssertRC(rc);
424 g_Spinlock = NIL_RTSPINLOCK;
425
426 RTR0Term();
427 return DDI_SUCCESS;
428 }
429 Log((DEVICE_NAME ":ddi_get_soft_state failed. Cannot detach instance %d\n", instance));
430 return DDI_FAILURE;
431 }
432
433 case DDI_SUSPEND:
434 {
435 /** @todo implement suspend for guest driver. */
436 return DDI_SUCCESS;
437 }
438
439 default:
440 return DDI_FAILURE;
441 }
442}
443
444
445/**
446 * Info entry point, called by solaris kernel for obtaining driver info.
447 *
448 * @param pDip The module structure instance (do not use).
449 * @param enmCmd Information request type.
450 * @param pvArg Type specific argument.
451 * @param ppvResult Where to store the requested info.
452 *
453 * @return corresponding solaris error code.
454 */
455static int VBoxGuestSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppvResult)
456{
457 LogFlow((DEVICE_NAME ":VBoxGuestSolarisGetInfo\n"));
458
459 int rc = DDI_SUCCESS;
460 switch (enmCmd)
461 {
462 case DDI_INFO_DEVT2DEVINFO:
463 *ppvResult = (void *)g_pDip;
464 break;
465
466 case DDI_INFO_DEVT2INSTANCE:
467 *ppvResult = (void *)(uintptr_t)ddi_get_instance(g_pDip);
468 break;
469
470 default:
471 rc = DDI_FAILURE;
472 break;
473 }
474
475 NOREF(pvArg);
476 return rc;
477}
478
479
480/**
481 * User context entry points
482 */
483static int VBoxGuestSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
484{
485 int rc;
486 PVBOXGUESTSESSION pSession;
487
488 LogFlow((DEVICE_NAME ":VBoxGuestSolarisOpen\n"));
489
490 /*
491 * Verify we are being opened as a character device.
492 */
493 if (fType != OTYP_CHR)
494 return EINVAL;
495
496#ifndef USE_SESSION_HASH
497 vboxguest_state_t *pState = NULL;
498 unsigned iOpenInstance;
499 for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
500 {
501 if ( !ddi_get_soft_state(g_pVBoxGuestSolarisState, iOpenInstance) /* faster */
502 && ddi_soft_state_zalloc(g_pVBoxGuestSolarisState, iOpenInstance) == DDI_SUCCESS)
503 {
504 pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, iOpenInstance);
505 break;
506 }
507 }
508 if (!pState)
509 {
510 Log((DEVICE_NAME ":VBoxGuestSolarisOpen: too many open instances."));
511 return ENXIO;
512 }
513
514 /*
515 * Create a new session.
516 */
517 rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession);
518 if (RT_SUCCESS(rc))
519 {
520 pState->pSession = pSession;
521 *pDev = makedevice(getmajor(*pDev), iOpenInstance);
522 Log((DEVICE_NAME "VBoxGuestSolarisOpen: pSession=%p pState=%p pid=%d\n", pSession, pState, (int)RTProcSelf()));
523 return 0;
524 }
525
526 /* Failed, clean up. */
527 ddi_soft_state_free(g_pVBoxGuestSolarisState, iOpenInstance);
528#else
529 /*
530 * Create a new session.
531 */
532 rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession);
533 if (RT_SUCCESS(rc))
534 {
535 /*
536 * Insert it into the hash table.
537 */
538 unsigned iHash = SESSION_HASH(pSession->Process);
539 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
540 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
541 pSession->pNextHash = g_apSessionHashTab[iHash];
542 g_apSessionHashTab[iHash] = pSession;
543 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
544
545 int instance;
546 for (instance = 0; instance < 4096; instance++)
547 {
548 vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, instance);
549 if (pState)
550 break;
551 }
552 if (instance >= 4096)
553 {
554 Log((DEVICE_NAME ":VBoxGuestSolarisOpen: All instances exhausted\n"));
555 return ENXIO;
556 }
557 *pDev = makedevice(getmajor(*pDev), instance);
558 Log((DEVICE_NAME ":VBoxGuestSolarisOpen success: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, (int)RTProcSelf()));
559 return 0;
560 }
561#endif
562 LogRel((DEVICE_NAME ":VBoxGuestSolarisOpen: VBoxGuestCreateUserSession failed. rc=%d\n", rc));
563 return EFAULT;
564}
565
566
567static int VBoxGuestSolarisClose(dev_t Dev, int flag, int fType, cred_t *pCred)
568{
569 LogFlow((DEVICE_NAME ":VBoxGuestSolarisClose pid=%d\n", (int)RTProcSelf()));
570
571#ifndef USE_SESSION_HASH
572 PVBOXGUESTSESSION pSession;
573 vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, getminor(Dev));
574 if (!pState)
575 {
576 Log((DEVICE_NAME ":VBoxGuestSolarisClose: failed to get pState.\n"));
577 return EFAULT;
578 }
579
580 pSession = pState->pSession;
581 pState->pSession = NULL;
582 Log((DEVICE_NAME ":VBoxGuestSolarisClose: pSession=%p pState=%p\n", pSession, pState));
583 ddi_soft_state_free(g_pVBoxGuestSolarisState, getminor(Dev));
584 if (!pSession)
585 {
586 Log((DEVICE_NAME ":VBoxGuestSolarisClose: failed to get pSession.\n"));
587 return EFAULT;
588 }
589
590#else /* USE_SESSION_HASH */
591 /*
592 * Remove from the hash table.
593 */
594 PVBOXGUESTSESSION pSession;
595 const RTPROCESS Process = RTProcSelf();
596 const unsigned iHash = SESSION_HASH(Process);
597 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
598 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
599
600 pSession = g_apSessionHashTab[iHash];
601 if (pSession)
602 {
603 if (pSession->Process == Process)
604 {
605 g_apSessionHashTab[iHash] = pSession->pNextHash;
606 pSession->pNextHash = NULL;
607 }
608 else
609 {
610 PVBOXGUESTSESSION pPrev = pSession;
611 pSession = pSession->pNextHash;
612 while (pSession)
613 {
614 if (pSession->Process == Process)
615 {
616 pPrev->pNextHash = pSession->pNextHash;
617 pSession->pNextHash = NULL;
618 break;
619 }
620
621 /* next */
622 pPrev = pSession;
623 pSession = pSession->pNextHash;
624 }
625 }
626 }
627 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
628 if (!pSession)
629 {
630 Log((DEVICE_NAME ":VBoxGuestSolarisClose: WHUT?!? pSession == NULL! This must be a mistake... pid=%d", (int)Process));
631 return EFAULT;
632 }
633 Log((DEVICE_NAME ":VBoxGuestSolarisClose: pid=%d\n", (int)Process));
634#endif /* USE_SESSION_HASH */
635
636 /*
637 * Close the session.
638 */
639 VBoxGuestCloseSession(&g_DevExt, pSession);
640 return 0;
641}
642
643
644static int VBoxGuestSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
645{
646 LogFlow((DEVICE_NAME ":VBoxGuestSolarisRead\n"));
647 return 0;
648}
649
650
651static int VBoxGuestSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
652{
653 LogFlow((DEVICE_NAME ":VBoxGuestSolarisWrite\n"));
654 return 0;
655}
656
657
658/** @def IOCPARM_LEN
659 * Gets the length from the ioctl number.
660 * This is normally defined by sys/ioccom.h on BSD systems...
661 */
662#ifndef IOCPARM_LEN
663# define IOCPARM_LEN(Code) (((Code) >> 16) & IOCPARM_MASK)
664#endif
665
666
667/**
668 * Driver ioctl, an alternate entry point for this character driver.
669 *
670 * @param Dev Device number
671 * @param Cmd Operation identifier
672 * @param pArg Arguments from user to driver
673 * @param Mode Information bitfield (read/write, address space etc.)
674 * @param pCred User credentials
675 * @param pVal Return value for calling process.
676 *
677 * @return corresponding solaris error code.
678 */
679static int VBoxGuestSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal)
680{
681 LogFlow((DEVICE_NAME ":VBoxGuestSolarisIOCtl\n"));
682
683#ifndef USE_SESSION_HASH
684 /*
685 * Get the session from the soft state item.
686 */
687 vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, getminor(Dev));
688 if (!pState)
689 {
690 Log((DEVICE_NAME ":VBoxGuestSolarisIOCtl: no state data for %d\n", getminor(Dev)));
691 return EINVAL;
692 }
693
694 PVBOXGUESTSESSION pSession = pState->pSession;
695 if (!pSession)
696 {
697 Log((DEVICE_NAME ":VBoxGuestSolarisIOCtl: no session data for %d\n", getminor(Dev)));
698 return EINVAL;
699 }
700
701#else /* USE_SESSION_HASH */
702 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
703 const RTPROCESS Process = RTProcSelf();
704 const unsigned iHash = SESSION_HASH(Process);
705 PVBOXGUESTSESSION pSession;
706
707 /*
708 * Find the session.
709 */
710 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
711 pSession = g_apSessionHashTab[iHash];
712 if (pSession && pSession->Process != Process)
713 {
714 do pSession = pSession->pNextHash;
715 while (pSession && pSession->Process != Process);
716 }
717 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
718 if (!pSession)
719 {
720 Log((DEVICE_NAME ":VBoxGuestSolarisIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n", (int)Process, Cmd));
721 return EINVAL;
722 }
723#endif /* USE_SESSION_HASH */
724
725 /*
726 * Read and validate the request wrapper.
727 */
728 VBGLBIGREQ ReqWrap;
729 if (IOCPARM_LEN(Cmd) != sizeof(ReqWrap))
730 {
731 LogRel((DEVICE_NAME ": VBoxGuestSolarisIOCtl: bad request %#x size=%d expected=%d\n", Cmd, IOCPARM_LEN(Cmd), sizeof(ReqWrap)));
732 return ENOTTY;
733 }
734
735 int rc = ddi_copyin((void *)pArg, &ReqWrap, sizeof(ReqWrap), Mode);
736 if (RT_UNLIKELY(rc))
737 {
738 LogRel((DEVICE_NAME ": VBoxGuestSolarisIOCtl: ddi_copyin failed to read header pArg=%p Cmd=%d. rc=%d.\n", pArg, Cmd, rc));
739 return EINVAL;
740 }
741
742 if (ReqWrap.u32Magic != VBGLBIGREQ_MAGIC)
743 {
744 LogRel((DEVICE_NAME ": VBoxGuestSolarisIOCtl: bad magic %#x; pArg=%p Cmd=%d.\n", ReqWrap.u32Magic, pArg, Cmd));
745 return EINVAL;
746 }
747 if (RT_UNLIKELY( ReqWrap.cbData == 0
748 || ReqWrap.cbData > _1M*16))
749 {
750 Log((DEVICE_NAME ": VBoxGuestSolarisIOCtl: bad size %#x; pArg=%p Cmd=%d.\n", ReqWrap.cbData, pArg, Cmd));
751 return EINVAL;
752 }
753
754 /*
755 * Read the request.
756 */
757 void *pvBuf = RTMemTmpAlloc(ReqWrap.cbData);
758 if (RT_UNLIKELY(!pvBuf))
759 {
760 LogRel((DEVICE_NAME ":VBoxGuestSolarisIOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", ReqWrap.cbData));
761 return ENOMEM;
762 }
763
764 rc = ddi_copyin((void *)(uintptr_t)ReqWrap.pvDataR3, pvBuf, ReqWrap.cbData, Mode);
765 if (RT_UNLIKELY(rc))
766 {
767 RTMemTmpFree(pvBuf);
768 LogRel((DEVICE_NAME ":VBoxGuestSolarisIOCtl: ddi_copyin failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
769 return EFAULT;
770 }
771 if (RT_UNLIKELY( ReqWrap.cbData != 0
772 && !VALID_PTR(pvBuf)))
773 {
774 RTMemTmpFree(pvBuf);
775 LogRel((DEVICE_NAME ":VBoxGuestSolarisIOCtl: pvBuf invalid pointer %p\n", pvBuf));
776 return EINVAL;
777 }
778 Log((DEVICE_NAME ":VBoxGuestSolarisIOCtl: pSession=%p pid=%d.\n", pSession, (int)RTProcSelf()));
779
780 /*
781 * Process the IOCtl.
782 */
783 size_t cbDataReturned;
784 rc = VBoxGuestCommonIOCtl(Cmd, &g_DevExt, pSession, pvBuf, ReqWrap.cbData, &cbDataReturned);
785 if (RT_SUCCESS(rc))
786 {
787 rc = 0;
788 if (RT_UNLIKELY(cbDataReturned > ReqWrap.cbData))
789 {
790 LogRel((DEVICE_NAME ":VBoxGuestSolarisIOCtl: too much output data %d expected %d\n", cbDataReturned, ReqWrap.cbData));
791 cbDataReturned = ReqWrap.cbData;
792 }
793 if (cbDataReturned > 0)
794 {
795 rc = ddi_copyout(pvBuf, (void *)(uintptr_t)ReqWrap.pvDataR3, cbDataReturned, Mode);
796 if (RT_UNLIKELY(rc))
797 {
798 LogRel((DEVICE_NAME ":VBoxGuestSolarisIOCtl: ddi_copyout failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
799 rc = EFAULT;
800 }
801 }
802 }
803 else
804 {
805 LogRel((DEVICE_NAME ":VBoxGuestSolarisIOCtl: VBoxGuestCommonIOCtl failed. rc=%d\n", rc));
806 rc = EFAULT;
807 }
808 *pVal = rc;
809 RTMemTmpFree(pvBuf);
810 return rc;
811}
812
813
814/**
815 * Sets IRQ for VMMDev.
816 *
817 * @returns Solaris error code.
818 * @param pDip Pointer to the device info structure.
819 * @param pvState Pointer to the state info structure.
820 */
821static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip, void *pvState)
822{
823 LogFlow((DEVICE_NAME ":VBoxGuestSolarisAddIRQ %p\n", pvState));
824
825 vboxguest_state_t *pState = (vboxguest_state_t *)pvState;
826#if 0
827 /*
828 * These calls are supposedly deprecated. But Sun seems to use them all over
829 * the place. Anyway, once this works we will switch to the highly elaborate
830 * and non-obsolete way of setting up IRQs.
831 */
832 int rc = ddi_get_iblock_cookie(pDip, 0, &pState->BlockCookie);
833 if (rc == DDI_SUCCESS)
834 {
835 mutex_init(&pState->Mtx, "VBoxGuest Driver Mutex", MUTEX_DRIVER, (void *)pState->BlockCookie);
836 rc = ddi_add_intr(pDip, 0, &pState->BlockCookie, NULL, VBoxGuestSolarisISR, (caddr_t)pState);
837 if (rc != DDI_SUCCESS)
838 Log((DEVICE_NAME ":ddi_add_intr failed. Cannot set IRQ for VMMDev.\n"));
839 }
840 else
841 Log((DEVICE_NAME ":ddi_get_iblock_cookie failed. Cannot set IRQ for VMMDev.\n"));
842 return rc;
843#else
844 int IntrType = 0;
845 int rc = ddi_intr_get_supported_types(pDip, &IntrType);
846 if (rc == DDI_SUCCESS)
847 {
848 /* We won't need to bother about MSIs. */
849 if (IntrType & DDI_INTR_TYPE_FIXED)
850 {
851 int IntrCount = 0;
852 rc = ddi_intr_get_nintrs(pDip, IntrType, &IntrCount);
853 if ( rc == DDI_SUCCESS
854 && IntrCount > 0)
855 {
856 int IntrAvail = 0;
857 rc = ddi_intr_get_navail(pDip, IntrType, &IntrAvail);
858 if ( rc == DDI_SUCCESS
859 && IntrAvail > 0)
860 {
861 /* Allocated kernel memory for the interrupt handles. The allocation size is stored internally. */
862 pState->pIntr = RTMemAlloc(IntrCount * sizeof(ddi_intr_handle_t));
863 if (pState->pIntr)
864 {
865 int IntrAllocated;
866 rc = ddi_intr_alloc(pDip, pState->pIntr, IntrType, 0, IntrCount, &IntrAllocated, DDI_INTR_ALLOC_NORMAL);
867 if ( rc == DDI_SUCCESS
868 && IntrAllocated > 0)
869 {
870 pState->cIntrAllocated = IntrAllocated;
871 uint_t uIntrPriority;
872 rc = ddi_intr_get_pri(pState->pIntr[0], &uIntrPriority);
873 if (rc == DDI_SUCCESS)
874 {
875 /* Initialize the mutex. */
876 mutex_init(&pState->Mtx, "VBoxGuestMtx", MUTEX_DRIVER, DDI_INTR_PRI(uIntrPriority));
877
878 /* Assign interrupt handler functions and enable interrupts. */
879 for (int i = 0; i < IntrAllocated; i++)
880 {
881 rc = ddi_intr_add_handler(pState->pIntr[i], (ddi_intr_handler_t *)VBoxGuestSolarisISR,
882 (caddr_t)pState, NULL);
883 if (rc == DDI_SUCCESS)
884 rc = ddi_intr_enable(pState->pIntr[i]);
885 if (rc != DDI_SUCCESS)
886 {
887 /* Changing local IntrAllocated to hold so-far allocated handles for freeing. */
888 IntrAllocated = i;
889 break;
890 }
891 }
892 if (rc == DDI_SUCCESS)
893 return rc;
894
895 /* Remove any assigned handlers */
896 LogRel((DEVICE_NAME ":failed to assign IRQs allocated=%d\n", IntrAllocated));
897 for (int x = 0; x < IntrAllocated; x++)
898 ddi_intr_remove_handler(pState->pIntr[x]);
899 }
900 else
901 LogRel((DEVICE_NAME ":VBoxGuestSolarisAddIRQ: failed to get priority of interrupt. rc=%d\n", rc));
902
903 /* Remove allocated IRQs, too bad we can free only one handle at a time. */
904 for (int k = 0; k < pState->cIntrAllocated; k++)
905 ddi_intr_free(pState->pIntr[k]);
906 }
907 else
908 LogRel((DEVICE_NAME ":VBoxGuestSolarisAddIRQ: failed to allocated IRQs. count=%d\n", IntrCount));
909 RTMemFree(pState->pIntr);
910 }
911 else
912 LogRel((DEVICE_NAME ":VBoxGuestSolarisAddIRQ: failed to allocated IRQs. count=%d\n", IntrCount));
913 }
914 else
915 LogRel((DEVICE_NAME ":VBoxGuestSolarisAddIRQ: failed to get or insufficient available IRQs. rc=%d IntrAvail=%d\n", rc, IntrAvail));
916 }
917 else
918 LogRel((DEVICE_NAME ":VBoxGuestSolarisAddIRQ: failed to get or insufficient number of IRQs. rc=%d IntrCount=%d\n", rc, IntrCount));
919 }
920 else
921 LogRel((DEVICE_NAME ":VBoxGuestSolarisAddIRQ: invalid irq type. IntrType=%#x\n", IntrType));
922 }
923 else
924 LogRel((DEVICE_NAME ":VBoxGuestSolarisAddIRQ: failed to get supported interrupt types\n"));
925 return rc;
926#endif
927}
928
929
930/**
931 * Removes IRQ for VMMDev.
932 *
933 * @param pDip Pointer to the device info structure.
934 * @param pvState Opaque pointer to the state info structure.
935 */
936static void VBoxGuestSolarisRemoveIRQ(dev_info_t *pDip, void *pvState)
937{
938 vboxguest_state_t *pState = (vboxguest_state_t *)pvState;
939 LogFlow((DEVICE_NAME ":VBoxGuestSolarisRemoveIRQ pvState=%p\n"));
940
941#if 0
942 ddi_remove_intr(pDip, 0, pState->BlockCookie);
943 mutex_destroy(&pState->Mtx);
944#else
945 for (int i = 0; i < pState->cIntrAllocated; i++)
946 {
947 int rc = ddi_intr_disable(pState->pIntr[i]);
948 if (rc == DDI_SUCCESS)
949 {
950 rc = ddi_intr_remove_handler(pState->pIntr[i]);
951 if (rc == DDI_SUCCESS)
952 ddi_intr_free(pState->pIntr[i]);
953 }
954 }
955 RTMemFree(pState->pIntr);
956 mutex_destroy(&pState->Mtx);
957#endif
958}
959
960
961/**
962 * Interrupt Service Routine for VMMDev.
963 *
964 * @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't.
965 */
966static uint_t VBoxGuestSolarisISR(caddr_t Arg)
967{
968 LogFlow((DEVICE_NAME ":VBoxGuestSolarisISR Arg=%p\n", Arg));
969
970 vboxguest_state_t *pState = (vboxguest_state_t *)Arg;
971 mutex_enter(&pState->Mtx);
972 bool fOurIRQ = VBoxGuestCommonISR(&g_DevExt);
973 mutex_exit(&pState->Mtx);
974
975 return fOurIRQ ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED;
976}
977
978
979/**
980 * VBoxGuest Common ioctl wrapper from VBoxGuestLib.
981 *
982 * @returns VBox error code.
983 * @param pvSession Opaque pointer to the session.
984 * @param iCmd Requested function.
985 * @param pvData IO data buffer.
986 * @param cbData Size of the data buffer.
987 * @param pcbDataReturned Where to store the amount of returned data.
988 */
989DECLVBGL(int) VBoxGuestSolarisServiceCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned)
990{
991 LogFlow((DEVICE_NAME ":VBoxGuestSolarisServiceCall %pvSesssion=%p Cmd=%u pvData=%p cbData=%d\n", pvSession, iCmd, pvData, cbData));
992
993 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
994 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
995 AssertMsgReturn(pSession->pDevExt == &g_DevExt,
996 ("SC: %p != %p\n", pSession->pDevExt, &g_DevExt), VERR_INVALID_HANDLE);
997
998 return VBoxGuestCommonIOCtl(iCmd, &g_DevExt, pSession, pvData, cbData, pcbDataReturned);
999}
1000
1001
1002/**
1003 * Solaris Guest service open.
1004 *
1005 * @returns Opaque pointer to session object.
1006 * @param pu32Version Where to store VMMDev version.
1007 */
1008DECLVBGL(void *) VBoxGuestSolarisServiceOpen(uint32_t *pu32Version)
1009{
1010 LogFlow((DEVICE_NAME ":VBoxGuestSolarisServiceOpen\n"));
1011
1012 AssertPtrReturn(pu32Version, NULL);
1013 PVBOXGUESTSESSION pSession;
1014 int rc = VBoxGuestCreateKernelSession(&g_DevExt, &pSession);
1015 if (RT_SUCCESS(rc))
1016 {
1017 *pu32Version = VMMDEV_VERSION;
1018 return pSession;
1019 }
1020 LogRel((DEVICE_NAME ":VBoxGuestCreateKernelSession failed. rc=%d\n", rc));
1021 return NULL;
1022}
1023
1024
1025/**
1026 * Solaris Guest service close.
1027 *
1028 * @returns VBox error code.
1029 * @param pvState Opaque pointer to the session object.
1030 */
1031DECLVBGL(int) VBoxGuestSolarisServiceClose(void *pvSession)
1032{
1033 LogFlow((DEVICE_NAME ":VBoxGuestSolarisServiceClose\n"));
1034
1035 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
1036 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
1037 if (pSession)
1038 {
1039 VBoxGuestCloseSession(&g_DevExt, pSession);
1040 return VINF_SUCCESS;
1041 }
1042 LogRel((DEVICE_NAME ":Invalid pSession.\n"));
1043 return VERR_INVALID_HANDLE;
1044}
1045
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