VirtualBox

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

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

vboxadd now works on solaris guest.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 28.2 KB
Line 
1/* $Id: VBoxGuest-solaris.c 6063 2007-12-14 08:50:36Z 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#include "VBoxGuestInternal.h"
33#include <VBox/log.h>
34#include <VBox/VBoxGuest.h>
35#include <iprt/asm.h>
36#include <iprt/assert.h>
37#include <iprt/initterm.h>
38#include <iprt/process.h>
39#include <iprt/mem.h>
40
41
42/*******************************************************************************
43* Defined Constants And Macros *
44*******************************************************************************/
45/** The module name. */
46#define DEVICE_NAME "vboxadd"
47/** The module description as seen in 'modinfo'. */
48#define DEVICE_DESC "VirtualBox Guest Additions Driver"
49/** @name R0 Log helpers.
50 * @{ */
51#define VBA_LOGCONT(...) cmn_err(CE_CONT, "vboxadd: " __VA_ARGS__);
52#define VBA_LOGNOTE(...) cmn_err(CE_NOTE, "vboxadd: " __VA_ARGS__);
53/** @} */
54
55
56/*******************************************************************************
57* Internal Functions *
58*******************************************************************************/
59static int VBoxAddSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
60static int VBoxAddSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
61static int VBoxAddSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
62static int VBoxAddSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
63static int VBoxAddSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int mode, cred_t *pCred, int *pVal);
64
65static int VBoxAddSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
66static int VBoxAddSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
67static int VBoxAddSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
68
69static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip, void *pvState);
70static void VBoxGuestSolarisRemoveIRQ(dev_info_t *pDip, void *pvState);
71static uint_t VBoxGuestSolarisISR(caddr_t Arg);
72
73DECLVBGL(int) VBoxGuestSolarisServiceCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned);
74DECLVBGL(void *) VBoxGuestSolarisServiceOpen(uint32_t *pu32Version);
75DECLVBGL(int) VBoxGuestSolarisServiceClose(void *pvSession);
76
77
78/*******************************************************************************
79* Global Variables *
80*******************************************************************************/
81/**
82 * cb_ops: for drivers that support char/block entry points
83 */
84static struct cb_ops g_VBoxAddSolarisCbOps =
85{
86 VBoxAddSolarisOpen,
87 VBoxAddSolarisClose,
88 nodev, /* b strategy */
89 nodev, /* b dump */
90 nodev, /* b print */
91 VBoxAddSolarisRead,
92 VBoxAddSolarisWrite,
93 VBoxAddSolarisIOCtl,
94 nodev, /* c devmap */
95 nodev, /* c mmap */
96 nodev, /* c segmap */
97 nochpoll, /* c poll */
98 ddi_prop_op, /* property ops */
99 NULL, /* streamtab */
100 D_NEW | D_MP, /* compat. flag */
101 CB_REV /* revision */
102};
103
104/**
105 * dev_ops: for driver device operations
106 */
107static struct dev_ops g_VBoxAddSolarisDevOps =
108{
109 DEVO_REV, /* driver build revision */
110 0, /* ref count */
111 VBoxAddSolarisGetInfo,
112 nulldev, /* identify */
113 nulldev, /* probe */
114 VBoxAddSolarisAttach,
115 VBoxAddSolarisDetach,
116 nodev, /* reset */
117 &g_VBoxAddSolarisCbOps,
118 (struct bus_ops *)0,
119 nodev /* power */
120};
121
122/**
123 * modldrv: export driver specifics to the kernel
124 */
125static struct modldrv g_VBoxAddSolarisModule =
126{
127 &mod_driverops, /* extern from kernel */
128 DEVICE_DESC,
129 &g_VBoxAddSolarisDevOps
130};
131
132/**
133 * modlinkage: export install/remove/info to the kernel
134 */
135static struct modlinkage g_VBoxAddSolarisModLinkage =
136{
137 MODREV_1, /* loadable module system revision */
138 &g_VBoxAddSolarisModule,
139 NULL /* terminate array of linkage structures */
140};
141
142/**
143 * State info for each open file handle.
144 */
145typedef struct
146{
147 /** PCI handle of VMMDev. */
148 ddi_acc_handle_t PciHandle;
149 /** IO port handle. */
150 ddi_acc_handle_t PciIOHandle;
151 /** MMIO handle. */
152 ddi_acc_handle_t PciMMIOHandle;
153 /** Interrupt block cookie. */
154 ddi_iblock_cookie_t BlockCookie;
155 /** Driver Mutex. */
156 kmutex_t Mtx;
157 /** IO Port. */
158 uint16_t uIOPortBase;
159 /** Address of the MMIO region.*/
160 caddr_t pMMIOBase;
161 /** Size of the MMIO region. */
162 off_t cbMMIO;
163 /** VMMDev Version. */
164 uint32_t u32Version;
165} VBoxAddDevState;
166
167/** Device handle (we support only one instance). */
168static dev_info_t *g_pDip;
169
170/** Opaque pointer to state */
171static void *g_pVBoxAddSolarisState;
172
173/** Device extention & session data association structure. */
174static VBOXGUESTDEVEXT g_DevExt;
175/** Spinlock protecting g_apSessionHashTab. */
176static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
177/** Hash table */
178static PVBOXGUESTSESSION g_apSessionHashTab[19];
179/** Calculates the index into g_apSessionHashTab.*/
180#define SESSION_HASH(sfn) ((sfn) % RT_ELEMENTS(g_apSessionHashTab))
181
182/** GCC C++ hack. */
183unsigned __gxx_personality_v0 = 0xdecea5ed;
184
185/**
186 * Kernel entry points
187 */
188int _init(void)
189{
190 VBA_LOGCONT("_init\n");
191
192 int rc = ddi_soft_state_init(&g_pVBoxAddSolarisState, sizeof(VBoxAddDevState), 1);
193 if (!rc)
194 {
195 rc = mod_install(&g_VBoxAddSolarisModLinkage);
196 if (rc)
197 ddi_soft_state_fini(&g_pVBoxAddSolarisState);
198 }
199 return rc;
200}
201
202
203int _fini(void)
204{
205 VBA_LOGCONT("_fini\n");
206
207 int rc = mod_remove(&g_VBoxAddSolarisModLinkage);
208 if (!rc)
209 ddi_soft_state_fini(&g_pVBoxAddSolarisState);
210 return rc;
211}
212
213
214int _info(struct modinfo *pModInfo)
215{
216 VBA_LOGCONT("_info\n");
217 return mod_info(&g_VBoxAddSolarisModLinkage, pModInfo);
218}
219
220
221/**
222 * Attach entry point, to attach a device to the system or resume it.
223 *
224 * @param pDip The module structure instance.
225 * @param enmCmd Attach type (ddi_attach_cmd_t)
226 *
227 * @return corresponding solaris error code.
228 */
229static int VBoxAddSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
230{
231 VBA_LOGCONT("VBoxAddSolarisAttach\n");
232 switch (enmCmd)
233 {
234 case DDI_ATTACH:
235 {
236 int rc;
237 int instance;
238 VBoxAddDevState *pState;
239
240 instance = ddi_get_instance(pDip);
241 rc = ddi_soft_state_zalloc(g_pVBoxAddSolarisState, instance);
242 if (rc != DDI_SUCCESS)
243 {
244 VBA_LOGNOTE("ddi_soft_state_zalloc failed.\n");
245 return DDI_FAILURE;
246 }
247
248 pState = ddi_get_soft_state(g_pVBoxAddSolarisState, instance);
249 if (!pState)
250 {
251 ddi_soft_state_free(g_pVBoxAddSolarisState, instance);
252 VBA_LOGNOTE("ddi_get_soft_state for instance %d failed\n", instance);
253 return DDI_FAILURE;
254 }
255
256 /*
257 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
258 */
259 rc = RTR0Init(0);
260 if (RT_FAILURE(rc))
261 {
262 VBA_LOGNOTE("RTR0Init failed.\n");
263 return DDI_FAILURE;
264 }
265
266 /*
267 * Initialize the session hash table.
268 */
269 rc = RTSpinlockCreate(&g_Spinlock);
270 if (RT_SUCCESS(rc))
271 {
272 /*
273 * Enable resources for PCI access.
274 */
275 rc = pci_config_setup(pDip, &pState->PciHandle);
276 if (rc == DDI_SUCCESS)
277 {
278 /*
279 * Check vendor and device ID.
280 */
281 uint16_t uVendorID = pci_config_get16(pState->PciHandle, PCI_CONF_VENID);
282 uint16_t uDeviceID = pci_config_get16(pState->PciHandle, PCI_CONF_DEVID);
283 if ( uVendorID == VMMDEV_VENDORID
284 && uDeviceID == VMMDEV_DEVICEID)
285 {
286 /*
287 * Verify PCI class of the device (a bit paranoid).
288 */
289 uint8_t uClass = pci_config_get8(pState->PciHandle, PCI_CONF_BASCLASS);
290 uint8_t uSubClass = pci_config_get8(pState->PciHandle, PCI_CONF_SUBCLASS);
291 if ( uClass == PCI_CLASS_PERIPH
292 && uSubClass == PCI_PERIPH_OTHER)
293 {
294 /*
295 * Map the register address space.
296 */
297 caddr_t baseAddr;
298 ddi_device_acc_attr_t deviceAttr;
299 deviceAttr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
300 deviceAttr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
301 deviceAttr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
302 deviceAttr.devacc_attr_access = DDI_DEFAULT_ACC;
303 rc = ddi_regs_map_setup(pDip, 1, &baseAddr, 0, 0, &deviceAttr, &pState->PciIOHandle);
304 if (rc == DDI_SUCCESS)
305 {
306 /*
307 * Read size of the MMIO region.
308 */
309 pState->uIOPortBase = (uintptr_t)baseAddr;
310 rc = ddi_dev_regsize(pDip, 2, &pState->cbMMIO);
311 if (rc == DDI_SUCCESS)
312 {
313 rc = ddi_regs_map_setup(pDip, 2, &pState->pMMIOBase, 0, pState->cbMMIO, &deviceAttr,
314 &pState->PciMMIOHandle);
315 if (rc == DDI_SUCCESS)
316 {
317 /*
318 * Add IRQ of VMMDev.
319 */
320 rc = VBoxGuestSolarisAddIRQ(pDip, pState);
321 if (rc == DDI_SUCCESS)
322 {
323 /*
324 * Call the common device extension initializer.
325 */
326 rc = VBoxGuestInitDevExt(&g_DevExt, pState->uIOPortBase, pState->pMMIOBase,
327 pState->cbMMIO, OSTypeSolaris);
328 if (RT_SUCCESS(rc))
329 {
330 rc = ddi_create_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, 0);
331 if (rc == DDI_SUCCESS)
332 {
333 g_pDip = pDip;
334 ddi_set_driver_private(pDip, pState);
335 pci_config_teardown(&pState->PciHandle);
336 ddi_report_dev(pDip);
337 return DDI_SUCCESS;
338 }
339
340 VBA_LOGNOTE("ddi_create_minor_node failed.\n");
341 }
342 else
343 VBA_LOGNOTE("VBoxGuestInitDevExt failed.\n");
344 VBoxGuestSolarisRemoveIRQ(pDip, pState);
345 }
346 else
347 VBA_LOGNOTE("VBoxGuestSolarisAddIRQ failed.\n");
348 ddi_regs_map_free(&pState->PciMMIOHandle);
349 }
350 else
351 VBA_LOGNOTE("ddi_regs_map_setup for MMIO region failed.\n");
352 }
353 else
354 VBA_LOGNOTE("ddi_dev_regsize for MMIO region failed.\n");
355 ddi_regs_map_free(&pState->PciIOHandle);
356 }
357 else
358 VBA_LOGNOTE("ddi_regs_map_setup for IOport failed.\n");
359 }
360 else
361 VBA_LOGNOTE("PCI class/sub-class does not match.\n");
362 }
363 else
364 VBA_LOGNOTE("PCI vendorID, deviceID does not match.\n");
365 pci_config_teardown(&pState->PciHandle);
366 }
367 else
368 VBA_LOGNOTE("pci_config_setup failed rc=%d.\n", rc);
369 RTSpinlockDestroy(g_Spinlock);
370 g_Spinlock = NIL_RTSPINLOCK;
371 }
372 else
373 VBA_LOGNOTE("RTSpinlockCreate failed.\n");
374
375 RTR0Term();
376 return DDI_FAILURE;
377 }
378
379 case DDI_RESUME:
380 {
381 /** @todo implement resume for guest driver. */
382 return DDI_SUCCESS;
383 }
384
385 default:
386 return DDI_FAILURE;
387 }
388}
389
390
391/**
392 * Detach entry point, to detach a device to the system or suspend it.
393 *
394 * @param pDip The module structure instance.
395 * @param enmCmd Attach type (ddi_attach_cmd_t)
396 *
397 * @return corresponding solaris error code.
398 */
399static int VBoxAddSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
400{
401 VBA_LOGCONT("VBoxAddSolarisDetach\n");
402 switch (enmCmd)
403 {
404 case DDI_DETACH:
405 {
406 int rc;
407 int instance = ddi_get_instance(pDip);
408 VBoxAddDevState *pState = ddi_get_soft_state(g_pVBoxAddSolarisState, instance);
409 if (pState)
410 {
411 VBoxGuestSolarisRemoveIRQ(pDip, pState);
412 ddi_regs_map_free(&pState->PciIOHandle);
413 ddi_regs_map_free(&pState->PciMMIOHandle);
414 ddi_remove_minor_node(pDip, NULL);
415 ddi_soft_state_free(g_pVBoxAddSolarisState, instance);
416
417 rc = RTSpinlockDestroy(g_Spinlock);
418 AssertRC(rc);
419 g_Spinlock = NIL_RTSPINLOCK;
420
421 RTR0Term();
422 return DDI_SUCCESS;
423 }
424 VBA_LOGNOTE("ddi_get_soft_state failed. Cannot detach instance %d\n", instance);
425 return DDI_FAILURE;
426 }
427
428 case DDI_SUSPEND:
429 {
430 /** @todo implement suspend for guest driver. */
431 return DDI_SUCCESS;
432 }
433
434 default:
435 return DDI_FAILURE;
436 }
437}
438
439
440/**
441 * Info entry point, called by solaris kernel for obtaining driver info.
442 *
443 * @param pDip The module structure instance (do not use).
444 * @param enmCmd Information request type.
445 * @param pArg Type specific argument.
446 * @param ppResult Where to store the requested info.
447 *
448 * @return corresponding solaris error code.
449 */
450static int VBoxAddSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult)
451{
452 VBA_LOGCONT("VBoxAddSolarisGetInfo\n");
453
454 int rc = DDI_SUCCESS;
455 switch (enmCmd)
456 {
457 case DDI_INFO_DEVT2DEVINFO:
458 *ppResult = (void *)g_pDip;
459 break;
460
461 case DDI_INFO_DEVT2INSTANCE:
462 *ppResult = (void *)ddi_get_instance(g_pDip);
463 break;
464
465 default:
466 rc = DDI_FAILURE;
467 break;
468 }
469 return rc;
470}
471
472
473/**
474 * User context entry points
475 */
476static int VBoxAddSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
477{
478 int rc;
479 PVBOXGUESTSESSION pSession;
480
481 VBA_LOGCONT("VBoxAddSolarisOpen\n");
482
483 /*
484 * Create a new session.
485 */
486 rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession);
487 if (RT_SUCCESS(rc))
488 {
489 /*
490 * Insert it into the hash table.
491 */
492 unsigned iHash = SESSION_HASH(pSession->Process);
493 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
494 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
495 pSession->pNextHash = g_apSessionHashTab[iHash];
496 g_apSessionHashTab[iHash] = pSession;
497 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
498
499 Log(("VBoxAddSolarisOpen: g_DevExt=%p pSession=%p rc=%d pid=%d\n", &g_DevExt, pSession, rc, (int)RTProcSelf()));
500 return 0;
501 }
502 LogRel(("VBoxAddSolarisOpen: VBoxGuestCreateUserSession failed. rc=%d\n", rc));
503 return rc;
504}
505
506
507static int VBoxAddSolarisClose(dev_t Dev, int flag, int fType, cred_t *pCred)
508{
509 VBA_LOGCONT("VBoxAddSolarisClose pid=%d=%d\n", (int)RTProcSelf());
510
511 /*
512 * Remove from the hash table.
513 */
514 PVBOXGUESTSESSION pSession;
515 const RTPROCESS Process = RTProcSelf();
516 const unsigned iHash = SESSION_HASH(Process);
517 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
518 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
519
520 pSession = g_apSessionHashTab[iHash];
521 if (pSession)
522 {
523 if (pSession->Process == Process)
524 {
525 g_apSessionHashTab[iHash] = pSession->pNextHash;
526 pSession->pNextHash = NULL;
527 }
528 else
529 {
530 PVBOXGUESTSESSION pPrev = pSession;
531 pSession = pSession->pNextHash;
532 while (pSession)
533 {
534 if (pSession->Process == Process)
535 {
536 pPrev->pNextHash = pSession->pNextHash;
537 pSession->pNextHash = NULL;
538 break;
539 }
540
541 /* next */
542 pPrev = pSession;
543 pSession = pSession->pNextHash;
544 }
545 }
546 }
547 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
548 if (!pSession)
549 {
550 Log(("VBoxGuestIoctl: WHUT?!? pSession == NULL! This must be a mistake... pid=%d", (int)Process));
551 return VERR_INVALID_PARAMETER;
552 }
553
554 /*
555 * Close the session.
556 */
557 VBoxGuestCloseSession(&g_DevExt, pSession);
558 return 0;
559}
560
561
562static int VBoxAddSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
563{
564 VBA_LOGCONT("VBoxAddSolarisRead\n");
565 return DDI_SUCCESS;
566}
567
568
569static int VBoxAddSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
570{
571 VBA_LOGCONT("VBoxAddSolarisWrite\n");
572 return DDI_SUCCESS;
573}
574
575/** @def IOCPARM_LEN
576 * Gets the length from the ioctl number.
577 * This is normally defined by sys/ioccom.h on BSD systems...
578 */
579#ifndef IOCPARM_LEN
580# define IOCPARM_LEN(x) ( ((x) >> 16) & IOCPARM_MASK )
581#endif
582
583/**
584 * Driver ioctl, an alternate entry point for this character driver.
585 *
586 * @param Dev Device number
587 * @param Cmd Operation identifier
588 * @param pArg Arguments from user to driver
589 * @param Mode Information bitfield (read/write, address space etc.)
590 * @param pCred User credentials
591 * @param pVal Return value for calling process.
592 *
593 * @return corresponding solaris error code.
594 */
595static int VBoxAddSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal)
596{
597 VBA_LOGCONT("VBoxAddSolarisIOCtl\n");
598
599 /** @todo use the faster way to find pSession (using the soft state) */
600 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
601 const RTPROCESS Process = RTProcSelf();
602 const unsigned iHash = SESSION_HASH(Process);
603 PVBOXGUESTSESSION pSession;
604
605 /*
606 * Find the session.
607 */
608 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
609 pSession = g_apSessionHashTab[iHash];
610 if (pSession && pSession->Process != Process)
611 {
612 do pSession = pSession->pNextHash;
613 while (pSession && pSession->Process != Process);
614 }
615 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
616 if (!pSession)
617 {
618 VBA_LOGNOTE("VBoxAddSolarisIOCtl: WHAT?!? pSession == NULL! This must be a mistake... pid=%d iCmd=%#x\n",
619 (int)Process, Cmd);
620 return EINVAL;
621 }
622
623 /** @todo I'll remove this size check after testing. */
624 uint32_t cbBuf = 0;
625 if ( Cmd >= VBOXGUEST_IOCTL_VMMREQUEST(0)
626 && Cmd <= VBOXGUEST_IOCTL_VMMREQUEST(0xfff))
627 cbBuf = sizeof(VMMDevRequestHeader);
628#ifdef VBOX_HGCM
629 else if ( Cmd >= VBOXGUEST_IOCTL_HGCM_CALL(0)
630 && Cmd <= VBOXGUEST_IOCTL_HGCM_CALL(0xfff))
631 cbBuf = sizeof(VBoxGuestHGCMCallInfo);
632#endif /* VBOX_HGCM */
633 else
634 {
635 switch (Cmd)
636 {
637 case VBOXGUEST_IOCTL_GETVMMDEVPORT:
638 cbBuf = sizeof(VBoxGuestPortInfo);
639 break;
640
641 case VBOXGUEST_IOCTL_WAITEVENT:
642 cbBuf = sizeof(VBoxGuestWaitEventInfo);
643 break;
644
645 case VBOXGUEST_IOCTL_CTL_FILTER_MASK:
646 cbBuf = sizeof(VBoxGuestFilterMaskInfo);
647 break;
648
649#ifdef VBOX_HGCM
650 case VBOXGUEST_IOCTL_HGCM_CONNECT:
651 cbBuf = sizeof(VBoxGuestHGCMConnectInfo);
652 break;
653
654 case VBOXGUEST_IOCTL_HGCM_DISCONNECT:
655 cbBuf = sizeof(VBoxGuestHGCMDisconnectInfo);
656 break;
657
658 case VBOXGUEST_IOCTL_CLIPBOARD_CONNECT:
659 cbBuf = sizeof(uint32_t);
660 break;
661#endif /* VBOX_HGCM */
662
663 default:
664 {
665 VBA_LOGNOTE("VBoxAddSolarisIOCtl: Unkown request %d\n", Cmd);
666 return VERR_NOT_SUPPORTED;
667 }
668 }
669 }
670
671 if (RT_UNLIKELY(cbBuf != IOCPARM_LEN(Cmd)))
672 {
673 VBA_LOGNOTE("VBoxAddSolarisIOCtl: buffer size mismatch. size=%d expected=%d.\n", IOCPARM_LEN(Cmd), cbBuf);
674 return EINVAL;
675 }
676
677 void *pvBuf = RTMemTmpAlloc(cbBuf);
678 if (RT_UNLIKELY(!pvBuf))
679 {
680 VBA_LOGNOTE("VBoxAddSolarisIOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", cbBuf);
681 return ENOMEM;
682 }
683
684 int rc = ddi_copyin((void *)pArg, pvBuf, cbBuf, Mode);
685 if (RT_UNLIKELY(rc))
686 {
687 RTMemTmpFree(pvBuf);
688 VBA_LOGNOTE("VBoxAddSolarisIOCtl: ddi_copyin failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc);
689 return EFAULT;
690 }
691
692 size_t cbDataReturned;
693 rc = VBoxGuestCommonIOCtl(Cmd, &g_DevExt, pSession, pvBuf, cbBuf, &cbDataReturned);
694 if (RT_LIKELY(!rc))
695 {
696 if (RT_UNLIKELY(cbDataReturned > cbBuf))
697 {
698 VBA_LOGNOTE("VBoxAddSolarisIOCtl: too much output data %d expected %d\n", cbDataReturned, cbBuf);
699 cbDataReturned = cbBuf;
700 }
701 rc = ddi_copyout(pvBuf, (void *)pArg, cbDataReturned, Mode);
702 if (RT_UNLIKELY(rc))
703 {
704 VBA_LOGNOTE("VBoxAddSolarisIOCtl: ddi_copyout failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc);
705 rc = EFAULT;
706 }
707 }
708 else
709 {
710 VBA_LOGNOTE("VBoxAddSolarisIOCtl: VBoxGuestCommonIOCtl failed. rc=%d\n", rc);
711 rc = EFAULT;
712 }
713 *pVal = rc;
714 RTMemTmpFree(pvBuf);
715 return rc;
716}
717
718
719/**
720 * Sets IRQ for VMMDev.
721 *
722 * @returns Solaris error code.
723 * @param pDip Pointer to the device info structure.
724 * @param pvState Pointer to the state info structure.
725 */
726static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip, void *pvState)
727{
728 int rc;
729 VBoxAddDevState *pState = (VBoxAddDevState *)pvState;
730 VBA_LOGCONT("VBoxGuestSolarisAddIRQ\n");
731
732 /*
733 * These calls are supposedly deprecated. But Sun seems to use them all over
734 * the place. Anyway, once this works we will switch to the highly elaborate
735 * and non-obsolete way of setting up IRQs.
736 */
737 rc = ddi_get_iblock_cookie(pDip, 0, &pState->BlockCookie);
738 if (rc == DDI_SUCCESS)
739 {
740 mutex_init(&pState->Mtx, "VBoxGuest Driver Mutex", MUTEX_DRIVER, (void *)pState->BlockCookie);
741 rc = ddi_add_intr(pDip, 0, &pState->BlockCookie, NULL, VBoxGuestSolarisISR, (caddr_t)pState);
742 if (rc != DDI_SUCCESS)
743 VBA_LOGNOTE("ddi_add_intr failed. Cannot set IRQ for VMMDev.\n");
744 }
745 else
746 VBA_LOGNOTE("ddi_get_iblock_cookie failed. Cannot set IRQ for VMMDev.\n");
747 return rc;
748}
749
750
751/**
752 * Removes IRQ for VMMDev.
753 *
754 * @param pDip Pointer to the device info structure.
755 * @param pvState Opaque pointer to the state info structure.
756 */
757static void VBoxGuestSolarisRemoveIRQ(dev_info_t *pDip, void *pvState)
758{
759 VBA_LOGCONT("VBoxGuestSolarisRemoveIRQ\n");
760
761 VBoxAddDevState *pState = (VBoxAddDevState *)pvState;
762 ddi_remove_intr(pDip, 0, pState->BlockCookie);
763 mutex_destroy(&pState->Mtx);
764}
765
766
767/**
768 * Interrupt Service Routine for VMMDev.
769 *
770 * @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't.
771 */
772static uint_t VBoxGuestSolarisISR(caddr_t Arg)
773{
774 VBA_LOGCONT("VBoxGuestSolarisISR\n");
775
776 VBoxAddDevState *pState = (VBoxAddDevState *)Arg;
777 mutex_enter(&pState->Mtx);
778 bool fOurIRQ = VBoxGuestCommonISR(&g_DevExt);
779 mutex_exit(&pState->Mtx);
780
781 return fOurIRQ ? DDI_INTR_CLAIMED : DDI_INTR_CLAIMED;
782}
783
784
785/**
786 * VBoxGuest Common ioctl wrapper from VBoxGuestLib.
787 *
788 * @returns VBox error code.
789 * @param pvSession Opaque pointer to the session.
790 * @param iCmd Requested function.
791 * @param pvData IO data buffer.
792 * @param cbData Size of the data buffer.
793 * @param pcbDataReturned Where to store the amount of returned data.
794 */
795DECLVBGL(int) VBoxGuestSolarisServiceCall(void *pvSession, unsigned iCmd, void *pvData, size_t cbData, size_t *pcbDataReturned)
796{
797 VBA_LOGCONT("VBoxGuestSolarisServiceCall\n");
798
799 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
800 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
801 AssertMsgReturn(pSession->pDevExt == &g_DevExt,
802 ("SC: %p != %p\n", pSession->pDevExt, &g_DevExt), VERR_INVALID_HANDLE);
803
804 return VBoxGuestCommonIOCtl(iCmd, &g_DevExt, pSession, pvData, cbData, pcbDataReturned);
805}
806
807
808/**
809 * Solaris Guest service open.
810 *
811 * @returns Opaque pointer to session object.
812 * @param pu32Version Where to store VMMDev version.
813 */
814DECLVBGL(void *) VBoxGuestSolarisServiceOpen(uint32_t *pu32Version)
815{
816 VBA_LOGCONT("VBoxGuestSolarisServiceOpen\n");
817
818 AssertPtrReturn(pu32Version, NULL);
819 PVBOXGUESTSESSION pSession;
820 int rc = VBoxGuestCreateKernelSession(&g_DevExt, &pSession);
821 if (RT_SUCCESS(rc))
822 {
823 *pu32Version = VMMDEV_VERSION;
824 return pSession;
825 }
826 VBA_LOGNOTE("VBoxGuestCreateKernelSession failed. rc=%d\n", rc);
827 return NULL;
828}
829
830
831/**
832 * Solaris Guest service close.
833 *
834 * @returns VBox error code.
835 * @param pvState Opaque pointer to the session object.
836 */
837DECLVBGL(int) VBoxGuestSolarisServiceClose(void *pvSession)
838{
839 VBA_LOGCONT("VBoxGuestSolarisServiceClose\n");
840
841 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pvSession;
842 AssertPtrReturn(pSession, VERR_INVALID_POINTER);
843 if (pSession)
844 {
845 VBoxGuestCloseSession(&g_DevExt, pSession);
846 return VINF_SUCCESS;
847 }
848 VBA_LOGNOTE("Invalid pSession.\n");
849 return VERR_INVALID_HANDLE;
850}
851
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