VirtualBox

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

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

Remove done todo.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 32.4 KB
Line 
1/* $Id: VBoxGuest-solaris.c 6151 2007-12-19 11:20:48Z vboxsync $ */
2/** @file
3 * VirtualBox Guest Additions Driver for Solaris.
4 */
5
6/*
7 * Copyright (C) 2007 innotek GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include <sys/conf.h>
23#include <sys/cmn_err.h>
24#include <sys/modctl.h>
25#include <sys/mutex.h>
26#include <sys/pci.h>
27#include <sys/stat.h>
28#include <sys/ddi.h>
29#include <sys/sunddi.h>
30#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
31
32#if defined(DEBUG_ramshankar) && !defined(LOG_ENABLED)
33#define LOG_ENABLED
34#endif
35#include "VBoxGuestInternal.h"
36#include <VBox/log.h>
37#include <iprt/asm.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 "vboxadd"
49/** The module description as seen in 'modinfo'. */
50#define DEVICE_DESC "VirtualBox Guest Additions Driver"
51
52
53/*******************************************************************************
54* Internal Functions *
55*******************************************************************************/
56static int VBoxAddSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
57static int VBoxAddSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
58static int VBoxAddSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
59static int VBoxAddSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
60static int VBoxAddSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int mode, cred_t *pCred, int *pVal);
61
62static int VBoxAddSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
63static int VBoxAddSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
64static int VBoxAddSolarisDetach(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* Global Variables *
77*******************************************************************************/
78/**
79 * cb_ops: for drivers that support char/block entry points
80 */
81static struct cb_ops g_VBoxAddSolarisCbOps =
82{
83 VBoxAddSolarisOpen,
84 VBoxAddSolarisClose,
85 nodev, /* b strategy */
86 nodev, /* b dump */
87 nodev, /* b print */
88 VBoxAddSolarisRead,
89 VBoxAddSolarisWrite,
90 VBoxAddSolarisIOCtl,
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_VBoxAddSolarisDevOps =
105{
106 DEVO_REV, /* driver build revision */
107 0, /* ref count */
108 VBoxAddSolarisGetInfo,
109 nulldev, /* identify */
110 nulldev, /* probe */
111 VBoxAddSolarisAttach,
112 VBoxAddSolarisDetach,
113 nodev, /* reset */
114 &g_VBoxAddSolarisCbOps,
115 (struct bus_ops *)0,
116 nodev /* power */
117};
118
119/**
120 * modldrv: export driver specifics to the kernel
121 */
122static struct modldrv g_VBoxAddSolarisModule =
123{
124 &mod_driverops, /* extern from kernel */
125 DEVICE_DESC,
126 &g_VBoxAddSolarisDevOps
127};
128
129/**
130 * modlinkage: export install/remove/info to the kernel
131 */
132static struct modlinkage g_VBoxAddSolarisModLinkage =
133{
134 MODREV_1, /* loadable module system revision */
135 &g_VBoxAddSolarisModule,
136 NULL /* terminate array of linkage structures */
137};
138
139/**
140 * State info for each open file handle.
141 */
142typedef struct
143{
144 /** PCI handle of VMMDev. */
145 ddi_acc_handle_t PciHandle;
146 /** IO port handle. */
147 ddi_acc_handle_t PciIOHandle;
148 /** MMIO handle. */
149 ddi_acc_handle_t PciMMIOHandle;
150 /** Interrupt block cookie. */
151 ddi_iblock_cookie_t BlockCookie;
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#ifndef USE_SESSION_HASH
163 /** Pointer to the session handle. */
164 PVBOXGUESTSESSION pSession;
165#endif
166} VBoxAddDevState;
167
168/** Device handle (we support only one instance). */
169static dev_info_t *g_pDip;
170
171/** Opaque pointer to state */
172static void *g_pVBoxAddSolarisState;
173
174/** Device extention & session data association structure. */
175static VBOXGUESTDEVEXT g_DevExt;
176/** Spinlock protecting g_apSessionHashTab. */
177static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
178#ifdef USE_SESSION_HASH
179/** Hash table */
180static PVBOXGUESTSESSION g_apSessionHashTab[19];
181/** Calculates the index into g_apSessionHashTab.*/
182#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
183#endif /* USE_SESSION_HASH */
184
185/** GCC C++ hack. */
186unsigned __gxx_personality_v0 = 0xdecea5ed;
187
188/**
189 * Kernel entry points
190 */
191int _init(void)
192{
193 LogFlow((DEVICE_NAME ":_init\n"));
194 int rc = ddi_soft_state_init(&g_pVBoxAddSolarisState, sizeof(VBoxAddDevState), 1);
195 if (!rc)
196 {
197 rc = mod_install(&g_VBoxAddSolarisModLinkage);
198 if (rc)
199 ddi_soft_state_fini(&g_pVBoxAddSolarisState);
200 }
201 return rc;
202}
203
204
205int _fini(void)
206{
207 LogFlow((DEVICE_NAME ":_fini\n"));
208 int rc = mod_remove(&g_VBoxAddSolarisModLinkage);
209 if (!rc)
210 ddi_soft_state_fini(&g_pVBoxAddSolarisState);
211 return rc;
212}
213
214
215int _info(struct modinfo *pModInfo)
216{
217 LogFlow((DEVICE_NAME ":_info\n"));
218 return mod_info(&g_VBoxAddSolarisModLinkage, pModInfo);
219}
220
221
222/**
223 * Attach entry point, to attach a device to the system or resume it.
224 *
225 * @param pDip The module structure instance.
226 * @param enmCmd Attach type (ddi_attach_cmd_t)
227 *
228 * @return corresponding solaris error code.
229 */
230static int VBoxAddSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
231{
232 LogFlow((DEVICE_NAME ":VBoxAddSolarisAttach\n"));
233 switch (enmCmd)
234 {
235 case DDI_ATTACH:
236 {
237 int rc;
238 int instance;
239 VBoxAddDevState *pState;
240
241 instance = ddi_get_instance(pDip);
242#ifdef USE_SESSION_HASH
243 rc = ddi_soft_state_zalloc(g_pVBoxAddSolarisState, instance);
244 if (rc != DDI_SUCCESS)
245 {
246 Log((DEVICE_NAME ":ddi_soft_state_zalloc failed.\n"));
247 return DDI_FAILURE;
248 }
249
250 pState = ddi_get_soft_state(g_pVBoxAddSolarisState, instance);
251 if (!pState)
252 {
253 ddi_soft_state_free(g_pVBoxAddSolarisState, instance);
254 Log((DEVICE_NAME ":ddi_get_soft_state for instance %d failed\n", instance));
255 return DDI_FAILURE;
256 }
257#else
258 pState = RTMemAllocZ(sizeof(VBoxAddDevState));
259 if (!pState)
260 {
261 Log((DEVICE_NAME ":RTMemAllocZ failed to allocate %d bytes\n", sizeof(VBoxAddDevState)));
262 return DDI_FAILURE;
263 }
264#endif
265
266 /*
267 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
268 */
269 rc = RTR0Init(0);
270 if (RT_FAILURE(rc))
271 {
272 Log((DEVICE_NAME ":RTR0Init failed.\n"));
273 return DDI_FAILURE;
274 }
275
276 /*
277 * Initialize the session hash table.
278 */
279 rc = RTSpinlockCreate(&g_Spinlock);
280 if (RT_SUCCESS(rc))
281 {
282 /*
283 * Enable resources for PCI access.
284 */
285 rc = pci_config_setup(pDip, &pState->PciHandle);
286 if (rc == DDI_SUCCESS)
287 {
288 /*
289 * Check vendor and device ID.
290 */
291 uint16_t uVendorID = pci_config_get16(pState->PciHandle, PCI_CONF_VENID);
292 uint16_t uDeviceID = pci_config_get16(pState->PciHandle, PCI_CONF_DEVID);
293 if ( uVendorID == VMMDEV_VENDORID
294 && uDeviceID == VMMDEV_DEVICEID)
295 {
296 /*
297 * Verify PCI class of the device (a bit paranoid).
298 */
299 uint8_t uClass = pci_config_get8(pState->PciHandle, PCI_CONF_BASCLASS);
300 uint8_t uSubClass = pci_config_get8(pState->PciHandle, PCI_CONF_SUBCLASS);
301 if ( uClass == PCI_CLASS_PERIPH
302 && uSubClass == PCI_PERIPH_OTHER)
303 {
304 /*
305 * Map the register address space.
306 */
307 caddr_t baseAddr;
308 ddi_device_acc_attr_t deviceAttr;
309 deviceAttr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
310 deviceAttr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
311 deviceAttr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
312 deviceAttr.devacc_attr_access = DDI_DEFAULT_ACC;
313 rc = ddi_regs_map_setup(pDip, 1, &baseAddr, 0, 0, &deviceAttr, &pState->PciIOHandle);
314 if (rc == DDI_SUCCESS)
315 {
316 /*
317 * Read size of the MMIO region.
318 */
319 pState->uIOPortBase = (uintptr_t)baseAddr;
320 rc = ddi_dev_regsize(pDip, 2, &pState->cbMMIO);
321 if (rc == DDI_SUCCESS)
322 {
323 rc = ddi_regs_map_setup(pDip, 2, &pState->pMMIOBase, 0, pState->cbMMIO, &deviceAttr,
324 &pState->PciMMIOHandle);
325 if (rc == DDI_SUCCESS)
326 {
327 /*
328 * Add IRQ of VMMDev.
329 */
330 rc = VBoxGuestSolarisAddIRQ(pDip, pState);
331 if (rc == DDI_SUCCESS)
332 {
333 /*
334 * Call the common device extension initializer.
335 */
336 rc = VBoxGuestInitDevExt(&g_DevExt, pState->uIOPortBase, pState->pMMIOBase,
337 pState->cbMMIO, OSTypeSolaris);
338 if (RT_SUCCESS(rc))
339 {
340 rc = ddi_create_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, 0);
341 if (rc == DDI_SUCCESS)
342 {
343 g_pDip = pDip;
344 ddi_set_driver_private(pDip, pState);
345 pci_config_teardown(&pState->PciHandle);
346 ddi_report_dev(pDip);
347 return DDI_SUCCESS;
348 }
349
350 LogRel((DEVICE_NAME ":ddi_create_minor_node failed.\n"));
351 }
352 else
353 Log((DEVICE_NAME ":VBoxGuestInitDevExt failed.\n"));
354 VBoxGuestSolarisRemoveIRQ(pDip, pState);
355 }
356 else
357 LogRel((DEVICE_NAME ":VBoxGuestSolarisAddIRQ failed.\n"));
358 ddi_regs_map_free(&pState->PciMMIOHandle);
359 }
360 else
361 Log((DEVICE_NAME ":ddi_regs_map_setup for MMIO region failed.\n"));
362 }
363 else
364 Log((DEVICE_NAME ":ddi_dev_regsize for MMIO region failed.\n"));
365 ddi_regs_map_free(&pState->PciIOHandle);
366 }
367 else
368 Log((DEVICE_NAME ":ddi_regs_map_setup for IOport failed.\n"));
369 }
370 else
371 Log((DEVICE_NAME ":PCI class/sub-class does not match.\n"));
372 }
373 else
374 Log((DEVICE_NAME ":PCI vendorID, deviceID does not match.\n"));
375 pci_config_teardown(&pState->PciHandle);
376 }
377 else
378 LogRel((DEVICE_NAME ":pci_config_setup failed rc=%d.\n", rc));
379 RTSpinlockDestroy(g_Spinlock);
380 g_Spinlock = NIL_RTSPINLOCK;
381 }
382 else
383 Log((DEVICE_NAME ":RTSpinlockCreate failed.\n"));
384
385 RTR0Term();
386 return DDI_FAILURE;
387 }
388
389 case DDI_RESUME:
390 {
391 /** @todo implement resume for guest driver. */
392 return DDI_SUCCESS;
393 }
394
395 default:
396 return DDI_FAILURE;
397 }
398}
399
400
401/**
402 * Detach entry point, to detach a device to the system or suspend it.
403 *
404 * @param pDip The module structure instance.
405 * @param enmCmd Attach type (ddi_attach_cmd_t)
406 *
407 * @return corresponding solaris error code.
408 */
409static int VBoxAddSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
410{
411 LogFlow((DEVICE_NAME ":VBoxAddSolarisDetach\n"));
412 switch (enmCmd)
413 {
414 case DDI_DETACH:
415 {
416 int rc;
417 int instance = ddi_get_instance(pDip);
418#ifdef USE_SESSION_HASH
419 VBoxAddDevState *pState = ddi_get_soft_state(g_pVBoxAddSolarisState, instance);
420#else
421 VBoxAddDevState *pState = ddi_get_driver_private(g_pDip);
422#endif
423 if (pState)
424 {
425 VBoxGuestSolarisRemoveIRQ(pDip, pState);
426 ddi_regs_map_free(&pState->PciIOHandle);
427 ddi_regs_map_free(&pState->PciMMIOHandle);
428 ddi_remove_minor_node(pDip, NULL);
429#ifdef USE_SESSION_HASH
430 ddi_soft_state_free(g_pVBoxAddSolarisState, instance);
431#else
432 RTMemFree(pState);
433#endif
434
435 rc = RTSpinlockDestroy(g_Spinlock);
436 AssertRC(rc);
437 g_Spinlock = NIL_RTSPINLOCK;
438
439 RTR0Term();
440 return DDI_SUCCESS;
441 }
442 Log((DEVICE_NAME ":ddi_get_soft_state failed. Cannot detach instance %d\n", instance));
443 return DDI_FAILURE;
444 }
445
446 case DDI_SUSPEND:
447 {
448 /** @todo implement suspend for guest driver. */
449 return DDI_SUCCESS;
450 }
451
452 default:
453 return DDI_FAILURE;
454 }
455}
456
457
458/**
459 * Info entry point, called by solaris kernel for obtaining driver info.
460 *
461 * @param pDip The module structure instance (do not use).
462 * @param enmCmd Information request type.
463 * @param pArg Type specific argument.
464 * @param ppResult Where to store the requested info.
465 *
466 * @return corresponding solaris error code.
467 */
468static int VBoxAddSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult)
469{
470 LogFlow((DEVICE_NAME ":VBoxAddSolarisGetInfo\n"));
471
472 int rc = DDI_SUCCESS;
473 switch (enmCmd)
474 {
475 case DDI_INFO_DEVT2DEVINFO:
476 *ppResult = (void *)g_pDip;
477 break;
478
479 case DDI_INFO_DEVT2INSTANCE:
480 *ppResult = (void *)(uintptr_t)ddi_get_instance(g_pDip);
481 break;
482
483 default:
484 rc = DDI_FAILURE;
485 break;
486 }
487 return rc;
488}
489
490
491/**
492 * User context entry points
493 */
494static int VBoxAddSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
495{
496 int rc;
497 PVBOXGUESTSESSION pSession;
498
499 LogFlow((DEVICE_NAME ":VBoxAddSolarisOpen\n"));
500
501#ifndef USE_SESSION_HASH
502 VBoxAddDevState *pState = NULL;
503 unsigned iOpenInstance;
504 for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
505 {
506 if ( !ddi_get_soft_state(g_pVBoxAddSolarisState, iOpenInstance) /* faster */
507 && ddi_soft_state_zalloc(g_pVBoxAddSolarisState, iOpenInstance) == DDI_SUCCESS)
508 {
509 pState = ddi_get_soft_state(g_pVBoxAddSolarisState, iOpenInstance);
510 break;
511 }
512 }
513 if (!pState)
514 {
515 Log((DEVICE_NAME ":VBoxAddSolarisOpen: too many open instances."));
516 return ENXIO;
517 }
518
519 /*
520 * Create a new session.
521 */
522 rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession);
523 if (RT_SUCCESS(rc))
524 {
525 pState->pSession = pSession;
526 *pDev = makedevice(getmajor(*pDev), iOpenInstance);
527 Log((DEVICE_NAME "VBoxAddSolarisOpen: pSession=%p pState=%p\n", pSession, pState));
528 return 0;
529 }
530
531 /* Failed, clean up. */
532 ddi_soft_state_free(g_pVBoxAddSolarisState, iOpenInstance);
533#else
534 /*
535 * Create a new session.
536 */
537 rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession);
538 if (RT_SUCCESS(rc))
539 {
540 /*
541 * Insert it into the hash table.
542 */
543 unsigned iHash = SESSION_HASH(pSession->Process);
544 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
545 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
546 pSession->pNextHash = g_apSessionHashTab[iHash];
547 g_apSessionHashTab[iHash] = pSession;
548 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
549
550 int instance;
551 for (instance = 0; instance < 4096; instance++)
552 {
553 VBoxAddDevState *pState = ddi_get_soft_state(g_pVBoxAddSolarisState, instance);
554 if (pState)
555 break;
556 }
557 if (instance >= 4096)
558 {
559 Log((DEVICE_NAME ":VBoxAddSolarisOpen: All instances exhausted\n"));
560 return ENXIO;
561 }
562 *pDev = makedevice(getmajor(*pDev), instance);
563 Log((DEVICE_NAME "VBoxAddSolarisOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, (int)RTProcSelf()));
564 return 0;
565 }
566#endif
567 LogRel((DEVICE_NAME "VBoxAddSolarisOpen: VBoxGuestCreateUserSession failed. rc=%d\n", rc));
568 return rc;
569}
570
571
572static int VBoxAddSolarisClose(dev_t Dev, int flag, int fType, cred_t *pCred)
573{
574 LogFlow((DEVICE_NAME ":VBoxAddSolarisClose pid=%d\n", (int)RTProcSelf()));
575
576#ifdef USE_SESSION_HASH
577 /*
578 * Remove from the hash table.
579 */
580 PVBOXGUESTSESSION pSession;
581 const RTPROCESS Process = RTProcSelf();
582 const unsigned iHash = SESSION_HASH(Process);
583 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
584 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
585
586 pSession = g_apSessionHashTab[iHash];
587 if (pSession)
588 {
589 if (pSession->Process == Process)
590 {
591 g_apSessionHashTab[iHash] = pSession->pNextHash;
592 pSession->pNextHash = NULL;
593 }
594 else
595 {
596 PVBOXGUESTSESSION pPrev = pSession;
597 pSession = pSession->pNextHash;
598 while (pSession)
599 {
600 if (pSession->Process == Process)
601 {
602 pPrev->pNextHash = pSession->pNextHash;
603 pSession->pNextHash = NULL;
604 break;
605 }
606
607 /* next */
608 pPrev = pSession;
609 pSession = pSession->pNextHash;
610 }
611 }
612 }
613 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
614 if (!pSession)
615 {
616 Log((DEVICE_NAME ":VBoxGuestIoctl: WHUT?!? pSession == NULL! This must be a mistake... pid=%d", (int)Process));
617 return EFAULT;
618 }
619#else
620 PVBOXGUESTSESSION pSession;
621 VBoxAddDevState *pState = ddi_get_soft_state(g_pVBoxAddSolarisState, getminor(Dev));
622 if (!pState)
623 {
624 Log((DEVICE_NAME ":VBoxAddSolarisClose: failed to get pState.\n"));
625 return EFAULT;
626 }
627
628 pSession = pState->pSession;
629 pState->pSession = NULL;
630 ddi_soft_state_free(g_pVBoxAddSolarisState, getminor(Dev));
631 if (!pSession)
632 {
633 Log((DEVICE_NAME ":VBoxAddSolarisClose: failed to get pSession.\n"));
634 return EFAULT;
635 }
636#endif
637
638 /*
639 * Close the session.
640 */
641 VBoxGuestCloseSession(&g_DevExt, pSession);
642 return 0;
643}
644
645
646static int VBoxAddSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
647{
648 LogFlow((DEVICE_NAME ":VBoxAddSolarisRead\n"));
649 return 0;
650}
651
652
653static int VBoxAddSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
654{
655 LogFlow((DEVICE_NAME ":VBoxAddSolarisWrite\n"));
656 return 0;
657}
658
659/** @def IOCPARM_LEN
660 * Gets the length from the ioctl number.
661 * This is normally defined by sys/ioccom.h on BSD systems...
662 */
663#ifndef IOCPARM_LEN
664# define IOCPARM_LEN(x) ( ((x) >> 16) & IOCPARM_MASK )
665#endif
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 VBoxAddSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal)
680{
681 LogFlow((DEVICE_NAME ":VBoxAddSolarisIOCtl\n"));
682
683#ifdef USE_SESSION_HASH
684 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
685 const RTPROCESS Process = RTProcSelf();
686 const unsigned iHash = SESSION_HASH(Process);
687 PVBOXGUESTSESSION pSession;
688
689 /*
690 * Find the session.
691 */
692 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
693 pSession = g_apSessionHashTab[iHash];
694 if (pSession && pSession->Process != Process)
695 {
696 do pSession = pSession->pNextHash;
697 while (pSession && pSession->Process != Process);
698 }
699 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
700 if (!pSession)
701 {
702 Log((DEVICE_NAME ":VBoxAddSolarisIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n", (int)Process, Cmd));
703 return EINVAL;
704 }
705#else
706 /*
707 * Get the session from the soft state item.
708 */
709 VBoxAddDevState *pState = ddi_get_soft_state(g_pVBoxAddSolarisState, getminor(Dev));
710 if (!pState)
711 {
712 Log((DEVICE_NAME ":VBoxAddSolarisIOCtl: no state data for %d\n", getminor(Dev)));
713 return EINVAL;
714 }
715
716 PVBOXGUESTSESSION pSession = pState->pSession;
717 if (!pSession)
718 {
719 Log((DEVICE_NAME ":VBoxAddSolarisIOCtl: no session data for %d\n", getminor(Dev)));
720 return EINVAL;
721 }
722#endif
723
724 /** @todo I'll remove this size check after testing. */
725 uint32_t cbBuf = 0;
726 if ( Cmd >= VBOXGUEST_IOCTL_VMMREQUEST(0)
727 && Cmd <= VBOXGUEST_IOCTL_VMMREQUEST(0xfff))
728 {
729 cbBuf = sizeof(VMMDevRequestHeader);
730 LogFlow((DEVICE_NAME ":VBOXGUEST_IOCTL_VMMREQUEST"));
731 }
732#ifdef VBOX_HGCM
733 else if ( Cmd >= VBOXGUEST_IOCTL_HGCM_CALL(0)
734 && Cmd <= VBOXGUEST_IOCTL_HGCM_CALL(0xfff))
735 {
736 cbBuf = sizeof(VBoxGuestHGCMCallInfo);
737 LogFlow((DEVICE_NAME ":VBOXGUEST_IOCTL_HGCM_CALL"));
738 }
739#endif /* VBOX_HGCM */
740 else
741 {
742 switch (Cmd)
743 {
744 case VBOXGUEST_IOCTL_GETVMMDEVPORT:
745 cbBuf = sizeof(VBoxGuestPortInfo);
746 LogFlow((DEVICE_NAME ":VBOXGUEST_IOCTL_GETVMMDEVPORT"));
747 break;
748
749 case VBOXGUEST_IOCTL_WAITEVENT:
750 cbBuf = sizeof(VBoxGuestWaitEventInfo);
751 LogFlow((DEVICE_NAME ":VBOXGUEST_IOCTL_WAITEVENT"));
752 break;
753
754 case VBOXGUEST_IOCTL_CTL_FILTER_MASK:
755 cbBuf = sizeof(VBoxGuestFilterMaskInfo);
756 LogFlow((DEVICE_NAME ":VBOXGUEST_IOCTL_CTL_FILTER_MASK"));
757 break;
758
759#ifdef VBOX_HGCM
760 case VBOXGUEST_IOCTL_HGCM_CONNECT:
761 cbBuf = sizeof(VBoxGuestHGCMConnectInfo);
762 LogFlow((DEVICE_NAME ":VBOXGUEST_IOCTL_HGCM_CONNECT"));
763 break;
764
765 case VBOXGUEST_IOCTL_HGCM_DISCONNECT:
766 cbBuf = sizeof(VBoxGuestHGCMDisconnectInfo);
767 LogFlow((DEVICE_NAME ":VBOXGUEST_IOCTL_HGCM_DISCONNECT"));
768 break;
769
770 case VBOXGUEST_IOCTL_CLIPBOARD_CONNECT:
771 cbBuf = sizeof(uint32_t);
772 LogFlow((DEVICE_NAME ":VBOXGUEST_IOCTL_CLIPBOARD_CONNECT"));
773 break;
774#endif /* VBOX_HGCM */
775
776 default:
777 {
778 LogRel((DEVICE_NAME ":VBoxAddSolarisIOCtl: Unkown request %d\n", Cmd));
779 return VERR_NOT_SUPPORTED;
780 }
781 }
782 }
783#if 0
784 /* cbBuf must actually get the size based on the VMM request type.
785 * Anyway, this obtaining cbBuf businesss will be removed eventually.
786 */
787 if (RT_UNLIKELY(cbBuf != IOCPARM_LEN(Cmd)))
788 {
789 LogRel((DEVICE_NAME ":VBoxAddSolarisIOCtl: buffer size mismatch. size=%d expected=%d.\n", IOCPARM_LEN(Cmd), cbBuf));
790 return EINVAL;
791 }
792#endif
793
794 cbBuf = IOCPARM_LEN(Cmd);
795 void *pvBuf = RTMemTmpAlloc(cbBuf);
796 if (RT_UNLIKELY(!pvBuf))
797 {
798 Log((DEVICE_NAME ":VBoxAddSolarisIOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", cbBuf));
799 return ENOMEM;
800 }
801
802 int rc = ddi_copyin((void *)pArg, pvBuf, cbBuf, Mode);
803 if (RT_UNLIKELY(rc))
804 {
805 RTMemTmpFree(pvBuf);
806 Log((DEVICE_NAME ":VBoxAddSolarisIOCtl: ddi_copyin failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
807 return EFAULT;
808 }
809 if (RT_UNLIKELY(cbBuf != 0 && !VALID_PTR(pvBuf)))
810 {
811 RTMemTmpFree(pvBuf);
812 Log((DEVICE_NAME ":VBoxAddSolarisIOCtl: pvBuf invalid pointer %p\n", pvBuf));
813 }
814
815 size_t cbDataReturned;
816 rc = VBoxGuestCommonIOCtl(Cmd, &g_DevExt, pSession, pvBuf, cbBuf, &cbDataReturned);
817 if (RT_SUCCESS(rc))
818 {
819 if (RT_UNLIKELY(cbDataReturned > cbBuf))
820 {
821 Log((DEVICE_NAME ":VBoxAddSolarisIOCtl: too much output data %d expected %d\n", cbDataReturned, cbBuf));
822 cbDataReturned = cbBuf;
823 }
824 rc = ddi_copyout(pvBuf, (void *)pArg, cbDataReturned, Mode);
825 if (RT_UNLIKELY(rc))
826 {
827 Log((DEVICE_NAME ":VBoxAddSolarisIOCtl: ddi_copyout failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
828 rc = EFAULT;
829 }
830 }
831 else
832 {
833 LogRel((DEVICE_NAME ":VBoxAddSolarisIOCtl: VBoxGuestCommonIOCtl failed. rc=%d\n", rc));
834 rc = EFAULT;
835 }
836 *pVal = rc;
837 RTMemTmpFree(pvBuf);
838 return rc;
839}
840
841
842/**
843 * Sets IRQ for VMMDev.
844 *
845 * @returns Solaris error code.
846 * @param pDip Pointer to the device info structure.
847 * @param pvState Pointer to the state info structure.
848 */
849static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip, void *pvState)
850{
851 int rc;
852 VBoxAddDevState *pState = (VBoxAddDevState *)pvState;
853 LogFlow((DEVICE_NAME "VBoxGuestSolarisAddIRQ\n"));
854
855 /*
856 * These calls are supposedly deprecated. But Sun seems to use them all over
857 * the place. Anyway, once this works we will switch to the highly elaborate
858 * and non-obsolete way of setting up IRQs.
859 */
860 rc = ddi_get_iblock_cookie(pDip, 0, &pState->BlockCookie);
861 if (rc == DDI_SUCCESS)
862 {
863 mutex_init(&pState->Mtx, "VBoxGuest Driver Mutex", MUTEX_DRIVER, (void *)pState->BlockCookie);
864 rc = ddi_add_intr(pDip, 0, &pState->BlockCookie, NULL, VBoxGuestSolarisISR, (caddr_t)pState);
865 if (rc != DDI_SUCCESS)
866 Log((DEVICE_NAME ":ddi_add_intr failed. Cannot set IRQ for VMMDev.\n"));
867 }
868 else
869 Log((DEVICE_NAME ":ddi_get_iblock_cookie failed. Cannot set IRQ for VMMDev.\n"));
870 return rc;
871}
872
873
874/**
875 * Removes IRQ for VMMDev.
876 *
877 * @param pDip Pointer to the device info structure.
878 * @param pvState Opaque pointer to the state info structure.
879 */
880static void VBoxGuestSolarisRemoveIRQ(dev_info_t *pDip, void *pvState)
881{
882 LogFlow((DEVICE_NAME ":VBoxGuestSolarisRemoveIRQ\n"));
883
884 VBoxAddDevState *pState = (VBoxAddDevState *)pvState;
885 ddi_remove_intr(pDip, 0, pState->BlockCookie);
886 mutex_destroy(&pState->Mtx);
887}
888
889
890/**
891 * Interrupt Service Routine for VMMDev.
892 *
893 * @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't.
894 */
895static uint_t VBoxGuestSolarisISR(caddr_t Arg)
896{
897 LogFlow((DEVICE_NAME ":VBoxGuestSolarisISR\n"));
898
899 VBoxAddDevState *pState = (VBoxAddDevState *)Arg;
900 mutex_enter(&pState->Mtx);
901 bool fOurIRQ = VBoxGuestCommonISR(&g_DevExt);
902 mutex_exit(&pState->Mtx);
903
904 return fOurIRQ ? DDI_INTR_CLAIMED : DDI_INTR_CLAIMED;
905}
906
907
908/**
909 * VBoxGuest Common ioctl wrapper from VBoxGuestLib.
910 *
911 * @returns VBox error code.
912 * @param pvSession Opaque pointer to the session.
913 * @param iCmd Requested function.
914 * @param pvData IO data buffer.
915 * @param cbData Size of the data buffer.
916 * @param pcbDataReturned Where to store the amount of returned data.
917 */
918DECLVBGL(int) VBoxGuestSolarisServiceCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned)
919{
920 LogFlow((DEVICE_NAME ":VBoxGuestSolarisServiceCall\n"));
921
922 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
923 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
924 AssertMsgReturn(pSession->pDevExt == &g_DevExt,
925 ("SC: %p != %p\n", pSession->pDevExt, &g_DevExt), VERR_INVALID_HANDLE);
926
927 return VBoxGuestCommonIOCtl(iCmd, &g_DevExt, pSession, pvData, cbData, pcbDataReturned);
928}
929
930
931/**
932 * Solaris Guest service open.
933 *
934 * @returns Opaque pointer to session object.
935 * @param pu32Version Where to store VMMDev version.
936 */
937DECLVBGL(void *) VBoxGuestSolarisServiceOpen(uint32_t *pu32Version)
938{
939 LogFlow((DEVICE_NAME ":VBoxGuestSolarisServiceOpen\n"));
940
941 AssertPtrReturn(pu32Version, NULL);
942 PVBOXGUESTSESSION pSession;
943 int rc = VBoxGuestCreateKernelSession(&g_DevExt, &pSession);
944 if (RT_SUCCESS(rc))
945 {
946 *pu32Version = VMMDEV_VERSION;
947 return pSession;
948 }
949 LogRel((DEVICE_NAME ":VBoxGuestCreateKernelSession failed. rc=%d\n", rc));
950 return NULL;
951}
952
953
954/**
955 * Solaris Guest service close.
956 *
957 * @returns VBox error code.
958 * @param pvState Opaque pointer to the session object.
959 */
960DECLVBGL(int) VBoxGuestSolarisServiceClose(void *pvSession)
961{
962 LogFlow((DEVICE_NAME ":VBoxGuestSolarisServiceClose\n"));
963
964 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
965 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
966 if (pSession)
967 {
968 VBoxGuestCloseSession(&g_DevExt, pSession);
969 return VINF_SUCCESS;
970 }
971 LogRel((DEVICE_NAME ":Invalid pSession.\n"));
972 return VERR_INVALID_HANDLE;
973}
974
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