VirtualBox

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

Last change on this file since 41683 was 38827, checked in by vboxsync, 13 years ago

Additions/solaris: Fix panic while mounting shared folders when no previous userland connections to VBoxGuest is alive.

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