VirtualBox

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

Last change on this file since 45221 was 41722, checked in by vboxsync, 13 years ago

Additions/common/VBoxGuest: fixed copyright dates and licence headers and removed a copyright text that is not relevant to this code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.9 KB
Line 
1/* $Id: VBoxGuest-solaris.c 41722 2012-06-14 19:49:31Z vboxsync $ */
2/** @file
3 * VirtualBox Guest Additions Driver for Solaris.
4 */
5
6/*
7 * Copyright (C) 2007-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <sys/conf.h>
32#include <sys/modctl.h>
33#include <sys/mutex.h>
34#include <sys/pci.h>
35#include <sys/stat.h>
36#include <sys/ddi.h>
37#include <sys/ddi_intr.h>
38#include <sys/sunddi.h>
39#include <sys/open.h>
40#include <sys/sunldi.h>
41#include <sys/file.h>
42#undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */
43
44#include "VBoxGuestInternal.h"
45#include <VBox/log.h>
46#include <VBox/version.h>
47#include <iprt/assert.h>
48#include <iprt/initterm.h>
49#include <iprt/process.h>
50#include <iprt/mem.h>
51#include <iprt/cdefs.h>
52#include <iprt/asm.h>
53
54
55/*******************************************************************************
56* Defined Constants And Macros *
57*******************************************************************************/
58/** The module name. */
59#define DEVICE_NAME "vboxguest"
60/** The module description as seen in 'modinfo'. */
61#define DEVICE_DESC "VirtualBox GstDrv"
62
63
64/*******************************************************************************
65* Internal Functions *
66*******************************************************************************/
67static int VBoxGuestSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred);
68static int VBoxGuestSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred);
69static int VBoxGuestSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred);
70static int VBoxGuestSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred);
71static int VBoxGuestSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal);
72static int VBoxGuestSolarisPoll(dev_t Dev, short fEvents, int fAnyYet, short *pReqEvents, struct pollhead **ppPollHead);
73
74static int VBoxGuestSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
75static int VBoxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
76static int VBoxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
77
78static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip);
79static void VBoxGuestSolarisRemoveIRQ(dev_info_t *pDip);
80static uint_t VBoxGuestSolarisISR(caddr_t Arg);
81
82
83/*******************************************************************************
84* Structures and Typedefs *
85*******************************************************************************/
86/**
87 * cb_ops: for drivers that support char/block entry points
88 */
89static struct cb_ops g_VBoxGuestSolarisCbOps =
90{
91 VBoxGuestSolarisOpen,
92 VBoxGuestSolarisClose,
93 nodev, /* b strategy */
94 nodev, /* b dump */
95 nodev, /* b print */
96 VBoxGuestSolarisRead,
97 VBoxGuestSolarisWrite,
98 VBoxGuestSolarisIOCtl,
99 nodev, /* c devmap */
100 nodev, /* c mmap */
101 nodev, /* c segmap */
102 VBoxGuestSolarisPoll,
103 ddi_prop_op, /* property ops */
104 NULL, /* streamtab */
105 D_NEW | D_MP, /* compat. flag */
106 CB_REV /* revision */
107};
108
109/**
110 * dev_ops: for driver device operations
111 */
112static struct dev_ops g_VBoxGuestSolarisDevOps =
113{
114 DEVO_REV, /* driver build revision */
115 0, /* ref count */
116 VBoxGuestSolarisGetInfo,
117 nulldev, /* identify */
118 nulldev, /* probe */
119 VBoxGuestSolarisAttach,
120 VBoxGuestSolarisDetach,
121 nodev, /* reset */
122 &g_VBoxGuestSolarisCbOps,
123 (struct bus_ops *)0,
124 nodev /* power */
125};
126
127/**
128 * modldrv: export driver specifics to the kernel
129 */
130static struct modldrv g_VBoxGuestSolarisModule =
131{
132 &mod_driverops, /* extern from kernel */
133 DEVICE_DESC " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV),
134 &g_VBoxGuestSolarisDevOps
135};
136
137/**
138 * modlinkage: export install/remove/info to the kernel
139 */
140static struct modlinkage g_VBoxGuestSolarisModLinkage =
141{
142 MODREV_1, /* loadable module system revision */
143 &g_VBoxGuestSolarisModule,
144 NULL /* terminate array of linkage structures */
145};
146
147/**
148 * State info for each open file handle.
149 */
150typedef struct
151{
152 /** Pointer to the session handle. */
153 PVBOXGUESTSESSION pSession;
154 /** The process reference for posting signals */
155 void *pvProcRef;
156} vboxguest_state_t;
157
158
159/*******************************************************************************
160* Global Variables *
161*******************************************************************************/
162/** Device handle (we support only one instance). */
163static dev_info_t *g_pDip = NULL;
164/** Opaque pointer to file-descriptor states */
165static void *g_pVBoxGuestSolarisState = NULL;
166/** Device extention & session data association structure. */
167static VBOXGUESTDEVEXT g_DevExt;
168/** IO port handle. */
169static ddi_acc_handle_t g_PciIOHandle;
170/** MMIO handle. */
171static ddi_acc_handle_t g_PciMMIOHandle;
172/** IO Port. */
173static uint16_t g_uIOPortBase;
174/** Address of the MMIO region.*/
175static caddr_t g_pMMIOBase;
176/** Size of the MMIO region. */
177static off_t g_cbMMIO;
178/** Pointer to the interrupt handle vector */
179static ddi_intr_handle_t *g_pIntr;
180/** Number of actually allocated interrupt handles */
181static size_t g_cIntrAllocated;
182/** The pollhead structure */
183static pollhead_t g_PollHead;
184/** The IRQ Mutex */
185static kmutex_t g_IrqMtx;
186/** Layered device handle for kernel keep-attached opens */
187static ldi_handle_t g_LdiHandle = NULL;
188/** Ref counting for IDCOpen calls */
189static uint64_t g_cLdiOpens = 0;
190/** The Mutex protecting the LDI handle in IDC opens */
191static kmutex_t g_LdiMtx;
192
193/**
194 * Kernel entry points
195 */
196int _init(void)
197{
198 /*
199 * Initialize IPRT R0 driver, which internally calls OS-specific r0 init.
200 */
201 int rc = RTR0Init(0);
202 if (RT_SUCCESS(rc))
203 {
204 PRTLOGGER pRelLogger;
205 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
206 rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all",
207 "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
208 RTLOGDEST_STDOUT | RTLOGDEST_DEBUGGER, NULL);
209 if (RT_SUCCESS(rc))
210 RTLogRelSetDefaultInstance(pRelLogger);
211 else
212 cmn_err(CE_NOTE, "failed to initialize driver logging rc=%d!\n", rc);
213
214 mutex_init(&g_LdiMtx, NULL, MUTEX_DRIVER, NULL);
215
216 /*
217 * Prevent module autounloading.
218 */
219 modctl_t *pModCtl = mod_getctl(&g_VBoxGuestSolarisModLinkage);
220 if (pModCtl)
221 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
222 else
223 LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
224
225 rc = ddi_soft_state_init(&g_pVBoxGuestSolarisState, sizeof(vboxguest_state_t), 1);
226 if (!rc)
227 {
228 rc = mod_install(&g_VBoxGuestSolarisModLinkage);
229 if (rc)
230 ddi_soft_state_fini(&g_pVBoxGuestSolarisState);
231 }
232 }
233 else
234 {
235 cmn_err(CE_NOTE, "_init: RTR0Init failed. rc=%d\n", rc);
236 return EINVAL;
237 }
238
239 return rc;
240}
241
242
243int _fini(void)
244{
245 LogFlow((DEVICE_NAME ":_fini\n"));
246 int rc = mod_remove(&g_VBoxGuestSolarisModLinkage);
247 if (!rc)
248 ddi_soft_state_fini(&g_pVBoxGuestSolarisState);
249
250 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
251 RTLogDestroy(RTLogSetDefaultInstance(NULL));
252
253 mutex_destroy(&g_LdiMtx);
254
255 RTR0Term();
256 return rc;
257}
258
259
260int _info(struct modinfo *pModInfo)
261{
262 LogFlow((DEVICE_NAME ":_info\n"));
263 return mod_info(&g_VBoxGuestSolarisModLinkage, pModInfo);
264}
265
266
267/**
268 * Attach entry point, to attach a device to the system or resume it.
269 *
270 * @param pDip The module structure instance.
271 * @param enmCmd Attach type (ddi_attach_cmd_t)
272 *
273 * @return corresponding solaris error code.
274 */
275static int VBoxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
276{
277 LogFlow((DEVICE_NAME "::Attach\n"));
278 switch (enmCmd)
279 {
280 case DDI_ATTACH:
281 {
282 if (g_pDip)
283 {
284 LogRel((DEVICE_NAME "::Attach: Only one instance supported.\n"));
285 return DDI_FAILURE;
286 }
287
288 int instance = ddi_get_instance(pDip);
289
290 /*
291 * Enable resources for PCI access.
292 */
293 ddi_acc_handle_t PciHandle;
294 int 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, &g_PciIOHandle);
307 if (rc == DDI_SUCCESS)
308 {
309 /*
310 * Read size of the MMIO region.
311 */
312 g_uIOPortBase = (uintptr_t)baseAddr;
313 rc = ddi_dev_regsize(pDip, 2, &g_cbMMIO);
314 if (rc == DDI_SUCCESS)
315 {
316 rc = ddi_regs_map_setup(pDip, 2, &g_pMMIOBase, 0, g_cbMMIO, &deviceAttr,
317 &g_PciMMIOHandle);
318 if (rc == DDI_SUCCESS)
319 {
320 /*
321 * Add IRQ of VMMDev.
322 */
323 rc = VBoxGuestSolarisAddIRQ(pDip);
324 if (rc == DDI_SUCCESS)
325 {
326 /*
327 * Call the common device extension initializer.
328 */
329 rc = VBoxGuestInitDevExt(&g_DevExt, g_uIOPortBase, g_pMMIOBase, g_cbMMIO,
330#if ARCH_BITS == 64
331 VBOXOSTYPE_Solaris_x64,
332#else
333 VBOXOSTYPE_Solaris,
334#endif
335 VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
336 if (RT_SUCCESS(rc))
337 {
338 rc = ddi_create_minor_node(pDip, DEVICE_NAME, S_IFCHR, instance, DDI_PSEUDO, 0);
339 if (rc == DDI_SUCCESS)
340 {
341 g_pDip = pDip;
342 pci_config_teardown(&PciHandle);
343 return DDI_SUCCESS;
344 }
345
346 LogRel((DEVICE_NAME "::Attach: ddi_create_minor_node failed.\n"));
347 VBoxGuestDeleteDevExt(&g_DevExt);
348 }
349 else
350 LogRel((DEVICE_NAME "::Attach: VBoxGuestInitDevExt failed.\n"));
351 VBoxGuestSolarisRemoveIRQ(pDip);
352 }
353 else
354 LogRel((DEVICE_NAME "::Attach: VBoxGuestSolarisAddIRQ failed.\n"));
355 ddi_regs_map_free(&g_PciMMIOHandle);
356 }
357 else
358 LogRel((DEVICE_NAME "::Attach: ddi_regs_map_setup for MMIO region failed.\n"));
359 }
360 else
361 LogRel((DEVICE_NAME "::Attach: ddi_dev_regsize for MMIO region failed.\n"));
362 ddi_regs_map_free(&g_PciIOHandle);
363 }
364 else
365 LogRel((DEVICE_NAME "::Attach: ddi_regs_map_setup for IOport failed.\n"));
366 pci_config_teardown(&PciHandle);
367 }
368 else
369 LogRel((DEVICE_NAME "::Attach: pci_config_setup failed rc=%d.\n", rc));
370 return DDI_FAILURE;
371 }
372
373 case DDI_RESUME:
374 {
375 /** @todo implement resume for guest driver. */
376 return DDI_SUCCESS;
377 }
378
379 default:
380 return DDI_FAILURE;
381 }
382}
383
384
385/**
386 * Detach entry point, to detach a device to the system or suspend it.
387 *
388 * @param pDip The module structure instance.
389 * @param enmCmd Attach type (ddi_attach_cmd_t)
390 *
391 * @return corresponding solaris error code.
392 */
393static int VBoxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
394{
395 LogFlow((DEVICE_NAME "::Detach\n"));
396 switch (enmCmd)
397 {
398 case DDI_DETACH:
399 {
400 VBoxGuestSolarisRemoveIRQ(pDip);
401 ddi_regs_map_free(&g_PciIOHandle);
402 ddi_regs_map_free(&g_PciMMIOHandle);
403 ddi_remove_minor_node(pDip, NULL);
404 VBoxGuestDeleteDevExt(&g_DevExt);
405 g_pDip = NULL;
406 return DDI_SUCCESS;
407 }
408
409 case DDI_SUSPEND:
410 {
411 /** @todo implement suspend for guest driver. */
412 return DDI_SUCCESS;
413 }
414
415 default:
416 return DDI_FAILURE;
417 }
418}
419
420
421/**
422 * Info entry point, called by solaris kernel for obtaining driver info.
423 *
424 * @param pDip The module structure instance (do not use).
425 * @param enmCmd Information request type.
426 * @param pvArg Type specific argument.
427 * @param ppvResult Where to store the requested info.
428 *
429 * @return corresponding solaris error code.
430 */
431static int VBoxGuestSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppvResult)
432{
433 LogFlow((DEVICE_NAME "::GetInfo\n"));
434
435 int rc = DDI_SUCCESS;
436 switch (enmCmd)
437 {
438 case DDI_INFO_DEVT2DEVINFO:
439 *ppvResult = (void *)g_pDip;
440 break;
441
442 case DDI_INFO_DEVT2INSTANCE:
443 *ppvResult = (void *)(uintptr_t)ddi_get_instance(g_pDip);
444 break;
445
446 default:
447 rc = DDI_FAILURE;
448 break;
449 }
450
451 NOREF(pvArg);
452 return rc;
453}
454
455
456/**
457 * User context entry points
458 */
459static int VBoxGuestSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred)
460{
461 int rc;
462 PVBOXGUESTSESSION pSession = NULL;
463
464 LogFlow((DEVICE_NAME "::Open\n"));
465
466 /*
467 * Verify we are being opened as a character device.
468 */
469 if (fType != OTYP_CHR)
470 return EINVAL;
471
472 vboxguest_state_t *pState = NULL;
473 unsigned iOpenInstance;
474 for (iOpenInstance = 0; iOpenInstance < 4096; iOpenInstance++)
475 {
476 if ( !ddi_get_soft_state(g_pVBoxGuestSolarisState, iOpenInstance) /* faster */
477 && ddi_soft_state_zalloc(g_pVBoxGuestSolarisState, iOpenInstance) == DDI_SUCCESS)
478 {
479 pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, iOpenInstance);
480 break;
481 }
482 }
483 if (!pState)
484 {
485 Log((DEVICE_NAME "::Open: too many open instances."));
486 return ENXIO;
487 }
488
489 /*
490 * Create a new session.
491 */
492 rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession);
493 if (RT_SUCCESS(rc))
494 {
495 pState->pvProcRef = proc_ref();
496 pState->pSession = pSession;
497 *pDev = makedevice(getmajor(*pDev), iOpenInstance);
498 Log((DEVICE_NAME "::Open: pSession=%p pState=%p pid=%d\n", pSession, pState, (int)RTProcSelf()));
499 return 0;
500 }
501
502 /* Failed, clean up. */
503 ddi_soft_state_free(g_pVBoxGuestSolarisState, iOpenInstance);
504
505 LogRel((DEVICE_NAME "::Open: VBoxGuestCreateUserSession failed. rc=%d\n", rc));
506 return EFAULT;
507}
508
509
510static int VBoxGuestSolarisClose(dev_t Dev, int flag, int fType, cred_t *pCred)
511{
512 LogFlow((DEVICE_NAME "::Close pid=%d\n", (int)RTProcSelf()));
513
514 PVBOXGUESTSESSION pSession = NULL;
515 vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, getminor(Dev));
516 if (!pState)
517 {
518 Log((DEVICE_NAME "::Close: failed to get pState.\n"));
519 return EFAULT;
520 }
521
522 proc_unref(pState->pvProcRef);
523 pSession = pState->pSession;
524 pState->pSession = NULL;
525 Log((DEVICE_NAME "::Close: pSession=%p pState=%p\n", pSession, pState));
526 ddi_soft_state_free(g_pVBoxGuestSolarisState, getminor(Dev));
527 if (!pSession)
528 {
529 Log((DEVICE_NAME "::Close: failed to get pSession.\n"));
530 return EFAULT;
531 }
532
533 /*
534 * Close the session.
535 */
536 VBoxGuestCloseSession(&g_DevExt, pSession);
537 return 0;
538}
539
540
541static int VBoxGuestSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred)
542{
543 LogFlow((DEVICE_NAME "::Read\n"));
544
545 vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, getminor(Dev));
546 if (!pState)
547 {
548 Log((DEVICE_NAME "::Close: failed to get pState.\n"));
549 return EFAULT;
550 }
551
552 PVBOXGUESTSESSION pSession = pState->pSession;
553 uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
554 if (pSession->u32MousePosChangedSeq != u32CurSeq)
555 pSession->u32MousePosChangedSeq = u32CurSeq;
556
557 return 0;
558}
559
560
561static int VBoxGuestSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred)
562{
563 LogFlow((DEVICE_NAME "::Write\n"));
564 return 0;
565}
566
567
568/** @def IOCPARM_LEN
569 * Gets the length from the ioctl number.
570 * This is normally defined by sys/ioccom.h on BSD systems...
571 */
572#ifndef IOCPARM_LEN
573# define IOCPARM_LEN(Code) (((Code) >> 16) & IOCPARM_MASK)
574#endif
575
576
577/**
578 * Driver ioctl, an alternate entry point for this character driver.
579 *
580 * @param Dev Device number
581 * @param Cmd Operation identifier
582 * @param pArg Arguments from user to driver
583 * @param Mode Information bitfield (read/write, address space etc.)
584 * @param pCred User credentials
585 * @param pVal Return value for calling process.
586 *
587 * @return corresponding solaris error code.
588 */
589static int VBoxGuestSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal)
590{
591 LogFlow((DEVICE_NAME ":VBoxGuestSolarisIOCtl\n"));
592
593 /*
594 * Get the session from the soft state item.
595 */
596 vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, getminor(Dev));
597 if (!pState)
598 {
599 LogRel((DEVICE_NAME "::IOCtl: no state data for %d\n", getminor(Dev)));
600 return EINVAL;
601 }
602
603 PVBOXGUESTSESSION pSession = pState->pSession;
604 if (!pSession)
605 {
606 LogRel((DEVICE_NAME "::IOCtl: no session data for %d\n", getminor(Dev)));
607 return EINVAL;
608 }
609
610 /*
611 * Read and validate the request wrapper.
612 */
613 VBGLBIGREQ ReqWrap;
614 if (IOCPARM_LEN(Cmd) != sizeof(ReqWrap))
615 {
616 LogRel((DEVICE_NAME "::IOCtl: bad request %#x size=%d expected=%d\n", Cmd, IOCPARM_LEN(Cmd), sizeof(ReqWrap)));
617 return ENOTTY;
618 }
619
620 int rc = ddi_copyin((void *)pArg, &ReqWrap, sizeof(ReqWrap), Mode);
621 if (RT_UNLIKELY(rc))
622 {
623 LogRel((DEVICE_NAME "::IOCtl: ddi_copyin failed to read header pArg=%p Cmd=%d. rc=%#x.\n", pArg, Cmd, rc));
624 return EINVAL;
625 }
626
627 if (ReqWrap.u32Magic != VBGLBIGREQ_MAGIC)
628 {
629 LogRel((DEVICE_NAME "::IOCtl: bad magic %#x; pArg=%p Cmd=%#x.\n", ReqWrap.u32Magic, pArg, Cmd));
630 return EINVAL;
631 }
632 if (RT_UNLIKELY(ReqWrap.cbData > _1M*16))
633 {
634 LogRel((DEVICE_NAME "::IOCtl: bad size %#x; pArg=%p Cmd=%#x.\n", ReqWrap.cbData, pArg, Cmd));
635 return EINVAL;
636 }
637
638 /*
639 * Read the request payload if any; requests like VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS have no data payload.
640 */
641 void *pvBuf = NULL;
642 if (RT_LIKELY(ReqWrap.cbData > 0))
643 {
644 pvBuf = RTMemTmpAlloc(ReqWrap.cbData);
645 if (RT_UNLIKELY(!pvBuf))
646 {
647 LogRel((DEVICE_NAME "::IOCtl: RTMemTmpAlloc failed to alloc %d bytes.\n", ReqWrap.cbData));
648 return ENOMEM;
649 }
650
651 rc = ddi_copyin((void *)(uintptr_t)ReqWrap.pvDataR3, pvBuf, ReqWrap.cbData, Mode);
652 if (RT_UNLIKELY(rc))
653 {
654 RTMemTmpFree(pvBuf);
655 LogRel((DEVICE_NAME "::IOCtl: ddi_copyin failed; pvBuf=%p pArg=%p Cmd=%d. rc=%d\n", pvBuf, pArg, Cmd, rc));
656 return EFAULT;
657 }
658 if (RT_UNLIKELY(!VALID_PTR(pvBuf)))
659 {
660 RTMemTmpFree(pvBuf);
661 LogRel((DEVICE_NAME "::IOCtl: pvBuf invalid pointer %p\n", pvBuf));
662 return EINVAL;
663 }
664 }
665 Log((DEVICE_NAME "::IOCtl: pSession=%p pid=%d.\n", pSession, (int)RTProcSelf()));
666
667 /*
668 * Process the IOCtl.
669 */
670 size_t cbDataReturned = 0;
671 rc = VBoxGuestCommonIOCtl(Cmd, &g_DevExt, pSession, pvBuf, ReqWrap.cbData, &cbDataReturned);
672 if (RT_SUCCESS(rc))
673 {
674 rc = 0;
675 if (RT_UNLIKELY(cbDataReturned > ReqWrap.cbData))
676 {
677 LogRel((DEVICE_NAME "::IOCtl: too much output data %d expected %d\n", cbDataReturned, ReqWrap.cbData));
678 cbDataReturned = ReqWrap.cbData;
679 }
680 if (cbDataReturned > 0)
681 {
682 rc = ddi_copyout(pvBuf, (void *)(uintptr_t)ReqWrap.pvDataR3, cbDataReturned, Mode);
683 if (RT_UNLIKELY(rc))
684 {
685 LogRel((DEVICE_NAME "::IOCtl: ddi_copyout failed; pvBuf=%p pArg=%p cbDataReturned=%u Cmd=%d. rc=%d\n",
686 pvBuf, pArg, cbDataReturned, Cmd, rc));
687 rc = EFAULT;
688 }
689 }
690 }
691 else
692 {
693 /*
694 * We Log() instead of LogRel() here because VBOXGUEST_IOCTL_WAITEVENT can return VERR_TIMEOUT,
695 * VBOXGUEST_IOCTL_CANCEL_ALL_EVENTS can return VERR_INTERRUPTED and possibly more in the future;
696 * which are not really failures that require logging.
697 */
698 Log((DEVICE_NAME "::IOCtl: VBoxGuestCommonIOCtl failed. Cmd=%#x rc=%d\n", Cmd, rc));
699 rc = RTErrConvertToErrno(rc);
700 }
701 *pVal = rc;
702 if (pvBuf)
703 RTMemTmpFree(pvBuf);
704 return rc;
705}
706
707
708static int VBoxGuestSolarisPoll(dev_t Dev, short fEvents, int fAnyYet, short *pReqEvents, struct pollhead **ppPollHead)
709{
710 LogFlow((DEVICE_NAME "::Poll: fEvents=%d fAnyYet=%d\n", fEvents, fAnyYet));
711
712 vboxguest_state_t *pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, getminor(Dev));
713 if (RT_LIKELY(pState))
714 {
715 PVBOXGUESTSESSION pSession = (PVBOXGUESTSESSION)pState->pSession;
716 uint32_t u32CurSeq = ASMAtomicUoReadU32(&g_DevExt.u32MousePosChangedSeq);
717 if (pSession->u32MousePosChangedSeq != u32CurSeq)
718 {
719 *pReqEvents |= (POLLIN | POLLRDNORM);
720 pSession->u32MousePosChangedSeq = u32CurSeq;
721 }
722 else
723 {
724 *pReqEvents = 0;
725 if (!fAnyYet)
726 *ppPollHead = &g_PollHead;
727 }
728
729 return 0;
730 }
731 else
732 {
733 Log((DEVICE_NAME "::Poll: no state data for %d\n", getminor(Dev)));
734 return EINVAL;
735 }
736}
737
738
739/**
740 * Sets IRQ for VMMDev.
741 *
742 * @returns Solaris error code.
743 * @param pDip Pointer to the device info structure.
744 */
745static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip)
746{
747 LogFlow((DEVICE_NAME "::AddIRQ: pDip=%p\n", pDip));
748
749 int IntrType = 0;
750 int rc = ddi_intr_get_supported_types(pDip, &IntrType);
751 if (rc == DDI_SUCCESS)
752 {
753 /* We won't need to bother about MSIs. */
754 if (IntrType & DDI_INTR_TYPE_FIXED)
755 {
756 int IntrCount = 0;
757 rc = ddi_intr_get_nintrs(pDip, IntrType, &IntrCount);
758 if ( rc == DDI_SUCCESS
759 && IntrCount > 0)
760 {
761 int IntrAvail = 0;
762 rc = ddi_intr_get_navail(pDip, IntrType, &IntrAvail);
763 if ( rc == DDI_SUCCESS
764 && IntrAvail > 0)
765 {
766 /* Allocated kernel memory for the interrupt handles. The allocation size is stored internally. */
767 g_pIntr = RTMemAlloc(IntrCount * sizeof(ddi_intr_handle_t));
768 if (g_pIntr)
769 {
770 int IntrAllocated;
771 rc = ddi_intr_alloc(pDip, g_pIntr, IntrType, 0, IntrCount, &IntrAllocated, DDI_INTR_ALLOC_NORMAL);
772 if ( rc == DDI_SUCCESS
773 && IntrAllocated > 0)
774 {
775 g_cIntrAllocated = IntrAllocated;
776 uint_t uIntrPriority;
777 rc = ddi_intr_get_pri(g_pIntr[0], &uIntrPriority);
778 if (rc == DDI_SUCCESS)
779 {
780 /* Initialize the mutex. */
781 mutex_init(&g_IrqMtx, NULL, MUTEX_DRIVER, DDI_INTR_PRI(uIntrPriority));
782
783 /* Assign interrupt handler functions and enable interrupts. */
784 for (int i = 0; i < IntrAllocated; i++)
785 {
786 rc = ddi_intr_add_handler(g_pIntr[i], (ddi_intr_handler_t *)VBoxGuestSolarisISR,
787 NULL /* No Private Data */, NULL);
788 if (rc == DDI_SUCCESS)
789 rc = ddi_intr_enable(g_pIntr[i]);
790 if (rc != DDI_SUCCESS)
791 {
792 /* Changing local IntrAllocated to hold so-far allocated handles for freeing. */
793 IntrAllocated = i;
794 break;
795 }
796 }
797 if (rc == DDI_SUCCESS)
798 return rc;
799
800 /* Remove any assigned handlers */
801 LogRel((DEVICE_NAME ":failed to assign IRQs allocated=%d\n", IntrAllocated));
802 for (int x = 0; x < IntrAllocated; x++)
803 ddi_intr_remove_handler(g_pIntr[x]);
804 }
805 else
806 LogRel((DEVICE_NAME "::AddIRQ: failed to get priority of interrupt. rc=%d\n", rc));
807
808 /* Remove allocated IRQs, too bad we can free only one handle at a time. */
809 for (int k = 0; k < g_cIntrAllocated; k++)
810 ddi_intr_free(g_pIntr[k]);
811 }
812 else
813 LogRel((DEVICE_NAME "::AddIRQ: failed to allocated IRQs. count=%d\n", IntrCount));
814 RTMemFree(g_pIntr);
815 }
816 else
817 LogRel((DEVICE_NAME "::AddIRQ: failed to allocated IRQs. count=%d\n", IntrCount));
818 }
819 else
820 LogRel((DEVICE_NAME "::AddIRQ: failed to get or insufficient available IRQs. rc=%d IntrAvail=%d\n", rc, IntrAvail));
821 }
822 else
823 LogRel((DEVICE_NAME "::AddIRQ: failed to get or insufficient number of IRQs. rc=%d IntrCount=%d\n", rc, IntrCount));
824 }
825 else
826 LogRel((DEVICE_NAME "::AddIRQ: invalid irq type. IntrType=%#x\n", IntrType));
827 }
828 else
829 LogRel((DEVICE_NAME "::AddIRQ: failed to get supported interrupt types\n"));
830 return rc;
831}
832
833
834/**
835 * Removes IRQ for VMMDev.
836 *
837 * @param pDip Pointer to the device info structure.
838 */
839static void VBoxGuestSolarisRemoveIRQ(dev_info_t *pDip)
840{
841 LogFlow((DEVICE_NAME "::RemoveIRQ:\n"));
842
843 for (int i = 0; i < g_cIntrAllocated; i++)
844 {
845 int rc = ddi_intr_disable(g_pIntr[i]);
846 if (rc == DDI_SUCCESS)
847 {
848 rc = ddi_intr_remove_handler(g_pIntr[i]);
849 if (rc == DDI_SUCCESS)
850 ddi_intr_free(g_pIntr[i]);
851 }
852 }
853 RTMemFree(g_pIntr);
854 mutex_destroy(&g_IrqMtx);
855}
856
857
858/**
859 * Interrupt Service Routine for VMMDev.
860 *
861 * @param Arg Private data (unused, will be NULL).
862 * @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't.
863 */
864static uint_t VBoxGuestSolarisISR(caddr_t Arg)
865{
866 LogFlow((DEVICE_NAME "::ISR:\n"));
867
868 mutex_enter(&g_IrqMtx);
869 bool fOurIRQ = VBoxGuestCommonISR(&g_DevExt);
870 mutex_exit(&g_IrqMtx);
871
872 return fOurIRQ ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED;
873}
874
875
876void VBoxGuestNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt)
877{
878 LogFlow((DEVICE_NAME "::NativeISRMousePollEvent:\n"));
879
880 /*
881 * Wake up poll waiters.
882 */
883 pollwakeup(&g_PollHead, POLLIN | POLLRDNORM);
884}
885
886
887/* Common code that depend on g_DevExt. */
888#include "VBoxGuestIDC-unix.c.h"
889
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