VirtualBox

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

Last change on this file since 16684 was 14203, checked in by vboxsync, 16 years ago

Solaris/Additions: Return errno rather than IPRT in vboxguest solaris ioctl.

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