Changeset 40311 in vbox
- Timestamp:
- Mar 1, 2012 12:09:56 PM (13 years ago)
- Location:
- trunk/src/VBox/Additions/common/VBoxGuest
- Files:
-
- 3 added
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxGuest/Makefile.kmk
r39358 r40311 208 208 endif 209 209 210 if defined(VBOX_WITH_TESTCASES) && !defined(VBOX_ONLY_ADDITIONS) && !defined(VBOX_ONLY_SDK) 211 PROGRAMS += tstVBoxGuest-solaris 212 tstVBoxGuest-solaris_TEMPLATE = VBOXR3TSTEXE 213 tstVBoxGuest-solaris_SOURCES = \ 214 VBoxGuest-solaris-streams.c \ 215 testcase/tstVBoxGuest-solaris.cpp 216 tstVBoxGuest-solaris_DEFS = TESTCASE 217 tstVBoxGuest-solaris_LIBS = $(LIB_RUNTIME) 218 endif 219 210 220 include $(KBUILD_PATH)/subfooter.kmk 211 221 -
trunk/src/VBox/Additions/common/VBoxGuest/VBoxGuest-solaris-streams.c
r39755 r40311 5 5 6 6 /* 7 * Copyright (C) 20 07Oracle Corporation7 * Copyright (C) 2012 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 17 17 18 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> 19 /****************************************************************************** 20 * Header Files * 21 ******************************************************************************/ 22 23 #ifndef TESTCASE 24 # include <sys/conf.h> 25 # include <sys/modctl.h> 26 # include <sys/mutex.h> 27 # include <sys/pci.h> 28 # include <sys/stat.h> 29 # include <sys/ddi.h> 30 # include <sys/ddi_intr.h> 31 # include <sys/sunddi.h> 32 # include <sys/open.h> 33 # include <sys/sunldi.h> 34 # include <sys/file.h> 33 35 #undef u /* /usr/include/sys/user.h:249:1 is where this is defined to (curproc->p_user). very cool. */ 36 #else /* TESTCASE */ 37 # undef IN_RING3 38 # define IN_RING0 39 #endif /* TESTCASE */ 34 40 35 41 #include "VBoxGuestInternal.h" … … 43 49 #include <iprt/asm.h> 44 50 45 46 /******************************************************************************* 47 * Defined Constants And Macros * 48 *******************************************************************************/ 51 #ifdef TESTCASE /* Include this last as we . */ 52 # include "testcase/solaris.h" 53 # include <iprt/test.h> 54 #endif /* TESTCASE */ 55 56 57 /****************************************************************************** 58 * Defined Constants And Macros * 59 ******************************************************************************/ 60 49 61 /** The module name. */ 50 62 #define DEVICE_NAME "vboxguest" … … 53 65 54 66 55 /******************************************************************************* 56 * Internal Functions * 57 *******************************************************************************/ 58 static int VBoxGuestSolarisOpen(dev_t *pDev, int fFlag, int fType, cred_t *pCred); 59 static int VBoxGuestSolarisClose(dev_t Dev, int fFlag, int fType, cred_t *pCred); 60 static int VBoxGuestSolarisRead(dev_t Dev, struct uio *pUio, cred_t *pCred); 61 static int VBoxGuestSolarisWrite(dev_t Dev, struct uio *pUio, cred_t *pCred); 62 static int VBoxGuestSolarisIOCtl(dev_t Dev, int Cmd, intptr_t pArg, int Mode, cred_t *pCred, int *pVal); 63 static int VBoxGuestSolarisPoll(dev_t Dev, short fEvents, int fAnyYet, short *pReqEvents, struct pollhead **ppPollHead); 64 65 static int VBoxGuestSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult); 66 static int VBoxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd); 67 static int VBoxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd); 68 69 static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip); 70 static void VBoxGuestSolarisRemoveIRQ(dev_info_t *pDip); 71 static 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 67 /****************************************************************************** 68 * Internal functions used in global structures * 69 ******************************************************************************/ 70 71 static int vboxGuestSolarisOpen(queue_t *pReadQueue, dev_t *pDev, int fFlag, 72 int fMode, cred_t *pCred); 73 static int vboxGuestSolarisClose(queue_t *pReadQueue, int fFlag, cred_t *pCred); 74 static int vboxGuestSolarisWPut(queue_t *pWriteQueue, mblk_t *pMBlk); 75 76 static int vboxGuestSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult); 77 static int vboxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd); 78 static int vboxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd); 79 80 81 /****************************************************************************** 82 * Driver global structures * 83 ******************************************************************************/ 84 85 #ifndef TESTCASE /* I see no value in including these. */ 86 87 /* 88 * mod_info: STREAMS module information. 89 */ 90 static struct module_info g_VBoxGuestSolarisModInfo = 91 { 92 0x0ffff, /* module id number */ 93 "vboxguest", 94 0, /* minimum packet size */ 95 INFPSZ, /* maximum packet size accepted */ 96 512, /* high water mark for data flow control */ 97 128 /* low water mark */ 98 }; 99 100 /* 101 * rinit: read queue structure for handling messages coming from below. In 102 * our case this means the host and the virtual hardware, so we do not need 103 * the put and service procedures. 104 */ 105 static struct qinit g_VBoxGuestSolarisRInit = 106 { 107 NULL, /* put */ 108 NULL, /* service thread procedure */ 109 vboxGuestSolarisOpen, 110 vboxGuestSolarisClose, 111 NULL, /* reserved */ 112 &g_VBoxGuestSolarisModInfo, 113 NULL /* module statistics structure */ 114 }; 115 116 /* 117 * winit: write queue structure for handling messages coming from above. Above 118 * means user space applications: either Guest Additions user space tools or 119 * applications reading pointer input. Messages from the last most likely pass 120 * through at least the "consms" console mouse streams module which multiplexes 121 * hardware pointer drivers to a single virtual pointer. 122 */ 123 static struct qinit g_VBoxGuestSolarisWInit = 124 { 125 vboxGuestSolarisWPut, 126 NULL, /* service thread procedure */ 127 NULL, /* open */ 128 NULL, /* close */ 129 NULL, /* reserved */ 130 &g_VBoxGuestSolarisModInfo, 131 NULL /* module statistics structure */ 132 }; 133 134 /** 135 * streamtab: for drivers that support char/block entry points. 136 */ 137 static struct streamtab g_VBoxGuestSolarisStreamTab = 138 { 139 &g_VBoxGuestSolarisRInit, 140 &g_VBoxGuestSolarisWInit, 141 NULL, /* MUX rinit */ 142 NULL /* MUX winit */ 143 }; 144 145 /** 146 * cb_ops: for drivers that support char/block entry points. 79 147 */ 80 148 static struct cb_ops g_VBoxGuestSolarisCbOps = 81 149 { 82 VBoxGuestSolarisOpen,83 VBoxGuestSolarisClose,84 n odev,/* b strategy */85 n odev,/* b dump */86 n odev,/* b print */87 VBoxGuestSolarisRead,88 VBoxGuestSolarisWrite,89 VBoxGuestSolarisIOCtl,90 n odev,/* c devmap */91 n odev,/* c mmap */92 n odev,/* c segmap */93 VBoxGuestSolarisPoll,150 nulldev, /* open */ 151 nulldev, /* close */ 152 nulldev, /* b strategy */ 153 nulldev, /* b dump */ 154 nulldev, /* b print */ 155 nulldev, /* c read */ 156 nulldev, /* c write */ 157 nulldev, /* c ioctl */ 158 nulldev, /* c devmap */ 159 nulldev, /* c mmap */ 160 nulldev, /* c segmap */ 161 nochpoll, /* c poll */ 94 162 ddi_prop_op, /* property ops */ 95 NULL, /* streamtab */163 g_VBoxGuestSolarisStreamTab, 96 164 D_NEW | D_MP, /* compat. flag */ 97 CB_REV /* revision */98 165 }; 99 166 100 167 /** 101 * dev_ops: for driver device operations 168 * dev_ops: for driver device operations. 102 169 */ 103 170 static struct dev_ops g_VBoxGuestSolarisDevOps = … … 105 172 DEVO_REV, /* driver build revision */ 106 173 0, /* ref count */ 107 VBoxGuestSolarisGetInfo,174 vboxGuestSolarisGetInfo, 108 175 nulldev, /* identify */ 109 176 nulldev, /* probe */ 110 VBoxGuestSolarisAttach,111 VBoxGuestSolarisDetach,177 vboxGuestSolarisAttach, 178 vboxGuestSolarisDetach, 112 179 nodev, /* reset */ 113 180 &g_VBoxGuestSolarisCbOps, … … 117 184 118 185 /** 119 * modldrv: export driver specifics to the kernel 186 * modldrv: export driver specifics to the kernel. 120 187 */ 121 188 static struct modldrv g_VBoxGuestSolarisModule = … … 127 194 128 195 /** 129 * modlinkage: export install/remove/info to the kernel 196 * modlinkage: export install/remove/info to the kernel. 130 197 */ 131 198 static struct modlinkage g_VBoxGuestSolarisModLinkage = … … 136 203 }; 137 204 205 #else /* TESTCASE */ 206 static void *g_VBoxGuestSolarisModLinkage; 207 #endif /* TESTCASE */ 208 138 209 /** 139 210 * State info for each open file handle. … … 142 213 { 143 214 /** Pointer to the session handle. */ 144 PVBOXGUESTSESSION pSession; 145 /** The process reference for posting signals */ 146 void *pvProcRef; 215 PVBOXGUESTSESSION pSession; 216 /** The STREAMS write queue which we need for sending messages up to 217 * user-space. */ 218 queue_t *pWriteQueue; 219 /** Our minor number. */ 220 unsigned cMinor; 221 /* The current greatest horizontal pixel offset on the screen, used for 222 * absolute mouse position reporting. 223 */ 224 unsigned cMaxScreenX; 225 /* The current greatest vertical pixel offset on the screen, used for 226 * absolute mouse position reporting. 227 */ 228 unsigned cMaxScreenY; 147 229 } vboxguest_state_t; 148 230 149 231 150 /******************************************************************************* 151 * Global Variables * 152 *******************************************************************************/ 232 /****************************************************************************** 233 * Global Variables * 234 ******************************************************************************/ 235 153 236 /** Device handle (we support only one instance). */ 154 237 static dev_info_t *g_pDip = NULL; … … 164 247 static uint16_t g_uIOPortBase; 165 248 /** Address of the MMIO region.*/ 166 static c addr_t g_pMMIOBase;249 static char *g_pMMIOBase; /* Actually caddr_t. */ 167 250 /** Size of the MMIO region. */ 168 251 static off_t g_cbMMIO; … … 171 254 /** Number of actually allocated interrupt handles */ 172 255 static size_t g_cIntrAllocated; 173 /** The pollhead structure */174 static pollhead_t g_PollHead;175 256 /** The IRQ Mutex */ 176 257 static kmutex_t g_IrqMtx; 177 /** Layered device handle for kernel keep-attached opens */ 178 static ldi_handle_t g_LdiHandle = NULL; 179 /** Ref counting for IDCOpen calls */ 180 static uint64_t g_cLdiOpens = 0; 181 /** The Mutex protecting the LDI handle in IDC opens */ 182 static kmutex_t g_LdiMtx; 183 184 /** 185 * Kernel entry points 186 */ 258 /** Our global state. 259 * @todo Make this into an opaque pointer in the device extension structure. 260 * @todo Can't we make do without all these globals anyway? 261 */ 262 static vboxguest_state_t *g_pState; 263 264 265 /****************************************************************************** 266 * Kernel entry points * 267 ******************************************************************************/ 268 269 /** Driver initialisation. */ 187 270 int _init(void) 188 271 { … … 195 278 PRTLOGGER pRelLogger; 196 279 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES; 280 modctl_t *pModCtl; 281 197 282 rc = RTLogCreate(&pRelLogger, 0 /* fFlags */, "all", 198 283 "VBOX_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups, … … 203 288 cmn_err(CE_NOTE, "failed to initialize driver logging rc=%d!\n", rc); 204 289 205 mutex_init(&g_LdiMtx, NULL, MUTEX_DRIVER, NULL);206 207 290 /* 208 291 * Prevent module autounloading. 209 292 */ 210 modctl_t *pModCtl = mod_getctl(&g_VBoxGuestSolarisModLinkage);293 pModCtl = mod_getctl(&g_VBoxGuestSolarisModLinkage); 211 294 if (pModCtl) 212 295 pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD; … … 232 315 233 316 317 #ifdef TESTCASE 318 /* Nothing in these three really worth testing, plus we would have to stub 319 * around the IPRT log functions. */ 320 #endif 321 322 323 /** Driver cleanup. */ 234 324 int _fini(void) 235 325 { 326 int rc; 327 236 328 LogFlow((DEVICE_NAME ":_fini\n")); 237 intrc = mod_remove(&g_VBoxGuestSolarisModLinkage);329 rc = mod_remove(&g_VBoxGuestSolarisModLinkage); 238 330 if (!rc) 239 331 ddi_soft_state_fini(&g_pVBoxGuestSolarisState); … … 242 334 RTLogDestroy(RTLogSetDefaultInstance(NULL)); 243 335 244 mutex_destroy(&g_LdiMtx);245 246 336 RTR0Term(); 247 337 return rc; … … 249 339 250 340 341 /** Driver identification. */ 251 342 int _info(struct modinfo *pModInfo) 252 343 { … … 255 346 } 256 347 348 349 /****************************************************************************** 350 * Main code * 351 ******************************************************************************/ 352 353 /** 354 * Open callback for the read queue, which we use as a generic device open 355 * handler. 356 */ 357 int vboxGuestSolarisOpen(queue_t *pReadQueue, dev_t *pDev, int fFlag, int fMode, 358 cred_t *pCred) 359 { 360 int rc; 361 PVBOXGUESTSESSION pSession = NULL; 362 vboxguest_state_t *pState = NULL; 363 unsigned cInstance; 364 365 NOREF(fFlag); 366 NOREF(pCred); 367 LogFlow((DEVICE_NAME "::Open\n")); 368 369 /* 370 * Sanity check on the mode parameter. 371 */ 372 if (fMode) 373 return EINVAL; 374 375 for (cInstance = 0; cInstance < 4096; cInstance++) 376 { 377 if ( !ddi_get_soft_state(g_pVBoxGuestSolarisState, cInstance) /* faster */ 378 && ddi_soft_state_zalloc(g_pVBoxGuestSolarisState, cInstance) == DDI_SUCCESS) 379 { 380 pState = ddi_get_soft_state(g_pVBoxGuestSolarisState, cInstance); 381 break; 382 } 383 } 384 if (!pState) 385 { 386 Log((DEVICE_NAME "::Open: too many open instances.")); 387 return ENXIO; 388 } 389 390 /* 391 * Create a new session. 392 */ 393 rc = VBoxGuestCreateUserSession(&g_DevExt, &pSession); 394 if (RT_SUCCESS(rc)) 395 { 396 pState->pSession = pSession; 397 *pDev = makedevice(getmajor(*pDev), cInstance); 398 /* Initialise user data for the queues to our state and vice-versa. */ 399 WR(pReadQueue)->q_ptr = (char *)pState; 400 pReadQueue->q_ptr = (char *)pState; 401 pState->pWriteQueue = WR(pReadQueue); 402 pState->cMinor = cInstance; 403 g_pState = pState; 404 qprocson(pState->pWriteQueue); 405 Log((DEVICE_NAME "::Open: pSession=%p pState=%p pid=%d\n", pSession, pState, (int)RTProcSelf())); 406 return 0; 407 } 408 409 /* Failed, clean up. */ 410 ddi_soft_state_free(g_pVBoxGuestSolarisState, cInstance); 411 412 LogRel((DEVICE_NAME "::Open: VBoxGuestCreateUserSession failed. rc=%d\n", rc)); 413 return EFAULT; 414 } 415 416 417 /** 418 * Close callback for the read queue, which we use as a generic device close 419 * handler. 420 */ 421 int vboxGuestSolarisClose(queue_t *pReadQueue, int fFlag, cred_t *pCred) 422 { 423 PVBOXGUESTSESSION pSession = NULL; 424 vboxguest_state_t *pState = (vboxguest_state_t *)pReadQueue->q_ptr; 425 426 LogFlow((DEVICE_NAME "::Close pid=%d\n", (int)RTProcSelf())); 427 NOREF(fFlag); 428 NOREF(pCred); 429 430 if (!pState) 431 { 432 Log((DEVICE_NAME "::Close: failed to get pState.\n")); 433 return EFAULT; 434 } 435 qprocsoff(pState->pWriteQueue); 436 pState->pWriteQueue = NULL; 437 g_pState = NULL; 438 pReadQueue->q_ptr = NULL; 439 440 pSession = pState->pSession; 441 pState->pSession = NULL; 442 Log((DEVICE_NAME "::Close: pSession=%p pState=%p\n", pSession, pState)); 443 ddi_soft_state_free(g_pVBoxGuestSolarisState, pState->cMinor); 444 if (!pSession) 445 { 446 Log((DEVICE_NAME "::Close: failed to get pSession.\n")); 447 return EFAULT; 448 } 449 450 /* 451 * Close the session. 452 */ 453 VBoxGuestCloseSession(&g_DevExt, pSession); 454 return 0; 455 } 456 457 458 /* Helper for vboxGuestSolarisWPut. */ 459 static int vboxGuestSolarisDispatchIOCtl(queue_t *pWriteQueue, mblk_t *pMBlk); 460 461 /** 462 * Handler for messages sent from above (user-space and upper modules) which 463 * land in our write queue. 464 */ 465 int vboxGuestSolarisWPut(queue_t *pWriteQueue, mblk_t *pMBlk) 466 { 467 vboxguest_state_t *pState = (vboxguest_state_t *)pWriteQueue->q_ptr; 468 469 LogFlowFunc(("\n")); 470 switch (pMBlk->b_datap->db_type) 471 { 472 case M_FLUSH: 473 /* Flush the write queue if so requested. */ 474 if (*pMBlk->b_rptr & FLUSHW) 475 flushq(pWriteQueue, FLUSHDATA); 476 477 /* Flush the read queue if so requested. */ 478 if (*pMBlk->b_rptr & FLUSHR) 479 flushq(RD(pWriteQueue), FLUSHDATA); 480 481 /* We have no one below us to pass the message on to. */ 482 return 0; 483 /* M_IOCDATA is additional data attached to (at least) transparent 484 * IOCtls. We handle the two together here and separate them further 485 * down. */ 486 case M_IOCTL: 487 case M_IOCDATA: 488 { 489 int err = vboxGuestSolarisDispatchIOCtl(pWriteQueue, pMBlk); 490 if (!err) 491 qreply(pWriteQueue, pMBlk); 492 else 493 miocnak(pWriteQueue, pMBlk, 0, err); 494 break; 495 } 496 } 497 return 0; 498 } 499 500 501 /** Data transfer direction of an IOCtl. This is used for describing 502 * transparent IOCtls, and @a UNSPECIFIED is not a valid value for them. */ 503 enum IOCTLDIRECTION 504 { 505 /** This IOCtl transfers no data. */ 506 NONE, 507 /** This IOCtl only transfers data from user to kernel. */ 508 IN, 509 /** This IOCtl only transfers data from kernel to user. */ 510 OUT, 511 /** This IOCtl transfers data from user to kernel and back. */ 512 BOTH, 513 /** We aren't saying anything about how the IOCtl transfers data. */ 514 UNSPECIFIED 515 }; 516 517 /** 518 * IOCtl handler function. 519 * @returns 0 on success, error code on failure. 520 * @param cCmd The IOCtl command number. 521 * @param pvData Buffer for the user data. 522 * @param cbBuffer Size of the buffer in @a pvData or zero. 523 * @param pcbData Where to set the size of the data returned. Required for 524 * handlers which return data. 525 * @param prc Where to store the return code. Default is zero. Only 526 * used for IOCtls without data for convenience of 527 * implemention. 528 */ 529 typedef int FNVBOXGUESTSOLARISIOCTL(vboxguest_state_t *pState, int cCmd, 530 void *pvData, size_t cbBuffer, 531 size_t *pcbData, int *prc); 532 typedef FNVBOXGUESTSOLARISIOCTL *PFNVBOXGUESTSOLARISIOCTL; 533 534 /* Helpers for vboxGuestSolarisDispatchIOCtl. */ 535 static int vboxGuestSolarisHandleIOCtl(queue_t *pWriteQueue, mblk_t *pMBlk, 536 PFNVBOXGUESTSOLARISIOCTL pfnHandler, 537 int cCmd, size_t cbTransparent, 538 enum IOCTLDIRECTION enmDirection); 539 static int vboxGuestSolarisVUIDIOCtl(vboxguest_state_t *pState, int cCmd, 540 void *pvData, size_t cbBuffer, 541 size_t *pcbData, int *prc); 542 static int vboxGuestSolarisGuestIOCtl(vboxguest_state_t *pState, int cCmd, 543 void *pvData, size_t cbBuffer, 544 size_t *pcbData, int *prc); 545 546 /** Table of supported VUID IOCtls. */ 547 struct 548 { 549 /** The IOCtl number. */ 550 int cCmd; 551 /** The size of the buffer which needs to be copied between user and kernel 552 * space, or zero if unknown (must be known for tranparent IOCtls). */ 553 size_t cbBuffer; 554 /** The direction the buffer data needs to be copied. This must be 555 * specified for transparent IOCtls. */ 556 enum IOCTLDIRECTION enmDirection; 557 } s_aVUIDIOCtlDescriptions[] = 558 { 559 { VUIDGFORMAT, sizeof(int), OUT }, 560 { VUIDSFORMAT, 0, NONE }, 561 { VUIDGADDR, 0, UNSPECIFIED }, 562 { MSIOGETPARMS, sizeof(Ms_parms), OUT }, 563 { MSIOSETPARMS, 0, NONE }, 564 { MSIOSRESOLUTION, sizeof(Ms_screen_resolution), IN }, 565 { MSIOBUTTONS, sizeof(int), OUT }, 566 { VUIDGWHEELCOUNT, sizeof(int), OUT }, 567 { VUIDGWHEELINFO, 0, UNSPECIFIED }, 568 { VUIDGWHEELSTATE, 0, UNSPECIFIED }, 569 { VUIDSWHEELSTATE, 0, UNSPECIFIED } 570 }; 571 572 /** 573 * Handle a STREAMS IOCtl message for our driver on the write stream. This 574 * function takes care of the IOCtl logic only and does not call qreply() or 575 * miocnak() at all - the caller must call these on success or failure 576 * respectively. 577 * @returns 0 on success or the IOCtl error code on failure. 578 * @param pWriteQueue pointer to the STREAMS write queue structure. 579 * @param pMBlk pointer to the STREAMS message block structure. 580 */ 581 static int vboxGuestSolarisDispatchIOCtl(queue_t *pWriteQueue, mblk_t *pMBlk) 582 { 583 struct iocblk *pIOCBlk = (struct iocblk *)pMBlk->b_rptr; 584 int cCmd = pIOCBlk->ioc_cmd, cCmdType = (cCmd >> 8) & ~0xff; 585 size_t cbBuffer; 586 enum IOCTLDIRECTION enmDirection; 587 588 LogFlowFunc(("cCmdType=%c, cCmd=%d\n", cCmdType, cCmd)); 589 switch (cCmdType) 590 { 591 case MSIOC: 592 case VUIOC: 593 { 594 unsigned i; 595 596 for (i = 0; i < RT_ELEMENTS(s_aVUIDIOCtlDescriptions); ++i) 597 if (s_aVUIDIOCtlDescriptions[i].cCmd == cCmd) 598 { 599 cbBuffer = s_aVUIDIOCtlDescriptions[i].cbBuffer; 600 enmDirection = s_aVUIDIOCtlDescriptions[i].enmDirection; 601 return vboxGuestSolarisHandleIOCtl(pWriteQueue, pMBlk, 602 vboxGuestSolarisVUIDIOCtl, 603 cCmd, cbBuffer, 604 enmDirection); 605 } 606 return EINVAL; 607 } 608 case 'V': 609 return vboxGuestSolarisHandleIOCtl(pWriteQueue, pMBlk, 610 vboxGuestSolarisGuestIOCtl, 611 cCmd, 0, UNSPECIFIED); 612 default: 613 return ENOTTY; 614 } 615 } 616 617 618 /* Helpers for vboxGuestSolarisHandleIOCtl. */ 619 static int vboxGuestSolarisHandleIOCtlData 620 (queue_t *pWriteQueue, mblk_t *pMBlk, 621 PFNVBOXGUESTSOLARISIOCTL pfnHandler, int cCmd, 622 size_t cbTransparent, enum IOCTLDIRECTION enmDirection); 623 624 static int vboxGuestSolarisHandleTransparentIOCtl 625 (queue_t *pWriteQueue, mblk_t *pMBlk, 626 PFNVBOXGUESTSOLARISIOCTL pfnHandler, int cCmd, 627 size_t cbTransparent, enum IOCTLDIRECTION enmDirection); 628 629 static int vboxGuestSolarisHandleIStrIOCtl 630 (queue_t *pWriteQueue, mblk_t *pMBlk, 631 PFNVBOXGUESTSOLARISIOCTL pfnHandler, int cCmd); 632 633 /** 634 * Generic code for handling STREAMS-specific IOCtl logic and boilerplate. It 635 * calls the IOCtl handler passed to it without the handler having to be aware 636 * of STREAMS structures, or whether this is a transparent (traditional) or an 637 * I_STR (using a STREAMS structure to describe the data) IOCtl. With the 638 * caveat that we only support transparent IOCtls which pass all data in a 639 * single buffer of a fixed size (I_STR IOCtls are restricted to a single 640 * buffer anyway, but the caller can choose the buffer size). 641 * @returns 0 on success or the IOCtl error code on failure. 642 * @param pWriteQueue pointer to the STREAMS write queue structure. 643 * @param pMBlk pointer to the STREAMS message block structure. 644 * @param pfnHandler pointer to the right IOCtl handler function for this 645 * IOCtl number. 646 * @param cCmd IOCtl command number. 647 * @param cbTransparent size of the user space buffer for this IOCtl number, 648 * used for processing transparent IOCtls. Pass zero 649 * for IOCtls with no maximum buffer size (which will 650 * not be able to be handled as transparent) or with 651 * no argument. 652 * @param enmDirection data transfer direction of the IOCtl. 653 */ 654 static int vboxGuestSolarisHandleIOCtl(queue_t *pWriteQueue, mblk_t *pMBlk, 655 PFNVBOXGUESTSOLARISIOCTL pfnHandler, 656 int cCmd, size_t cbTransparent, 657 enum IOCTLDIRECTION enmDirection) 658 { 659 struct iocblk *pIOCBlk = (struct iocblk *)pMBlk->b_rptr; 660 vboxguest_state_t *pState = (vboxguest_state_t *)pWriteQueue->q_ptr; 661 662 if (pMBlk->b_datap->db_type == M_IOCDATA) 663 return vboxGuestSolarisHandleIOCtlData(pWriteQueue, pMBlk, pfnHandler, 664 cCmd, cbTransparent, 665 enmDirection); 666 else if (pIOCBlk->ioc_count == TRANSPARENT) 667 return vboxGuestSolarisHandleTransparentIOCtl(pWriteQueue, pMBlk, 668 pfnHandler, cCmd, 669 cbTransparent, 670 enmDirection); 671 else 672 return vboxGuestSolarisHandleIStrIOCtl(pWriteQueue, pMBlk, pfnHandler, 673 cCmd); 674 } 675 676 677 /** 678 * Helper for vboxGuestSolarisHandleIOCtl. This rather complicated-looking 679 * code is basically the standard boilerplate for handling any streams IOCtl 680 * additional data, which we currently only use for transparent IOCtls. 681 * @copydoc vboxGuestSolarisHandleIOCtl 682 */ 683 static int vboxGuestSolarisHandleIOCtlData(queue_t *pWriteQueue, mblk_t *pMBlk, 684 PFNVBOXGUESTSOLARISIOCTL pfnHandler, 685 int cCmd, size_t cbTransparent, 686 enum IOCTLDIRECTION enmDirection) 687 { 688 struct copyresp *pCopyResp = (struct copyresp *)pMBlk->b_rptr; 689 struct iocblk *pIOCBlk = (struct iocblk *)pMBlk->b_rptr; 690 vboxguest_state_t *pState = (vboxguest_state_t *)pWriteQueue->q_ptr; 691 692 if (pCopyResp->cp_rval) 693 { 694 freemsg(pMBlk); 695 return EAGAIN; /* cp_rval is a pointer but should be the error. */ 696 } 697 if ((pCopyResp->cp_private && enmDirection == BOTH) || enmDirection == IN) 698 { 699 size_t cbBuffer = pIOCBlk->ioc_count, cbData = 0; 700 void *pvData = NULL; 701 int err; 702 703 if (cbData < cbTransparent) 704 return EINVAL; 705 if (!pMBlk->b_cont) 706 return EINVAL; 707 if (enmDirection == BOTH && !pCopyResp->cp_private) 708 return EINVAL; 709 pvData = pMBlk->b_cont->b_rptr; 710 err = pfnHandler(pState, cCmd, pvData, cbBuffer, &cbData, NULL); 711 if (!err && enmDirection == BOTH) 712 mcopyout(pMBlk, NULL, cbData, pCopyResp->cp_private, NULL); 713 else if (!err && enmDirection == IN) 714 miocack(pWriteQueue, pMBlk, 0, 0); 715 return err; 716 } 717 else 718 { 719 AssertReturn(enmDirection == OUT || enmDirection == BOTH, EINVAL); 720 miocack(pWriteQueue, pMBlk, 0, 0); 721 return 0; 722 } 723 } 724 725 /** 726 * Helper for vboxGuestSolarisHandleIOCtl. This rather complicated-looking 727 * code is basically the standard boilerplate for handling transparent IOCtls, 728 * that is, IOCtls which are not re-packed inside STREAMS IOCtls. 729 * @copydoc vboxGuestSolarisHandleIOCtl 730 */ 731 int vboxGuestSolarisHandleTransparentIOCtl 732 (queue_t *pWriteQueue, mblk_t *pMBlk, 733 PFNVBOXGUESTSOLARISIOCTL pfnHandler, int cCmd, 734 size_t cbTransparent, enum IOCTLDIRECTION enmDirection) 735 { 736 int err = 0, rc = 0; 737 size_t cbData = 0; 738 vboxguest_state_t *pState = (vboxguest_state_t *)pWriteQueue->q_ptr; 739 740 if ( (enmDirection != NONE && !pMBlk->b_cont) 741 || enmDirection == UNSPECIFIED) 742 return EINVAL; 743 if (enmDirection == IN || enmDirection == BOTH) 744 { 745 void *pUserAddr = NULL; 746 /* We only need state data if there is something to copy back. */ 747 if (enmDirection == BOTH) 748 pUserAddr = *(void **)pMBlk->b_cont->b_rptr; 749 mcopyin(pMBlk, pUserAddr /* state data */, cbTransparent, NULL); 750 } 751 else if (enmDirection == OUT) 752 { 753 mblk_t *pMBlkOut = allocb(cbOut, BPRI_MED); 754 void *pvData; 755 756 if (!pMBlkOut) 757 return EAGAIN; 758 pvData = pMBlkOut->b_rptr; 759 err = pfnHandler(pState, cCmd, pvData, cbTransparent, &cbData, NULL); 760 if (!err) 761 mcopyout(pMBlk, NULL, cbData, NULL, pMBlkOut); 762 else 763 freemsg(pMBlkOut); 764 } 765 else 766 { 767 AssertReturn(enmDirection == NONE, EINVAL); 768 err = pfnHandler(pState, cCmd, NULL, 0, NULL, &rc); 769 if (!err) 770 miocack(pWriteQueue, pMBlk, 0, rc); 771 } 772 return err; 773 } 774 775 /** 776 * Helper for vboxGuestSolarisHandleIOCtl. This rather complicated-looking 777 * code is basically the standard boilerplate for handling any streams IOCtl. 778 * @copydoc vboxGuestSolarisHandleIOCtl 779 */ 780 static int vboxGuestSolarisHandleIStrIOCtl(queue_t *pWriteQueue, mblk_t *pMBlk, 781 PFNVBOXGUESTSOLARISIOCTL pfnHandler, 782 int cCmd) 783 { 784 struct iocblk *pIOCBlk = (struct iocblk *)pMBlk->b_rptr; 785 vboxguest_state_t *pState = (vboxguest_state_t *)pWriteQueue->q_ptr; 786 uint_t cbBuffer = pIOCBlk->ioc_count; 787 void *pvData = NULL; 788 int err, rc = 0; 789 size_t cbData = 0; 790 791 if (cbBuffer && !pMBlk->b_cont) 792 return EINVAL; 793 /* Repack the whole buffer into a single message block if needed. */ 794 if (cbBuffer) 795 { 796 err = miocpullup(pMBlk, cbBuffer); 797 if (err) 798 return err; 799 pvData = pMBlk->b_cont->b_rptr; 800 } 801 err = pfnHandler(pState, cCmd, pvData, cbBuffer, &cbData, &rc); 802 if (!err) 803 miocack(pWriteQueue, pMBlk, cbData, rc); 804 return err; 805 } 806 807 808 /** 809 * Handle a VUID input device IOCtl. 810 * @copydoc FNVBOXGUESTSOLARISIOCTL 811 */ 812 static int vboxGuestSolarisVUIDIOCtl(vboxguest_state_t *pState, int cCmd, 813 void *pvData, size_t cbBuffer, 814 size_t *pcbData, int *prc) 815 { 816 LogFlowFunc((": " /* no '\n' */)); 817 switch (cCmd) 818 { 819 case VUIDGFORMAT: 820 { 821 LogFlowFunc(("VUIDGFORMAT\n")); 822 AssertReturn(cbBuffer >= sizeof(int), EINVAL); 823 *(int *)pvData = VUID_FIRM_EVENT; 824 *pcbData = sizeof(int); 825 return 0; 826 } 827 case VUIDSFORMAT: 828 LogFlowFunc(("VUIDSFORMAT\n")); 829 /* We define our native format to be VUID_FIRM_EVENT, so there 830 * is nothing more to do and we exit here on success or on 831 * failure. */ 832 return 0; 833 case VUIDGADDR: 834 case VUIDSADDR: 835 LogFlowFunc(("VUIDGADDR/VUIDSADDR\n")); 836 return ENOTTY; 837 case MSIOGETPARMS: 838 { 839 Ms_parms parms = { 0 }; 840 841 LogFlowFunc(("MSIOGETPARMS\n")); 842 AssertReturn(cbBuffer >= sizeof(Ms_parms), EINVAL); 843 *(Ms_parms *)pvData = parms; 844 *pcbData = sizeof(Ms_parms); 845 return 0; 846 } 847 case MSIOSETPARMS: 848 LogFlowFunc(("MSIOSETPARMS\n")); 849 return 0; 850 case MSIOSRESOLUTION: 851 { 852 Ms_screen_resolution *pResolution = (Ms_screen_resolution *)pvData; 853 LogFlowFunc(("MSIOSRESOLUTION\n")); 854 AssertReturn(cbBuffer >= sizeof(Ms_screen_resolution), EINVAL); 855 pState->cMaxScreenX = pResolution->width - 1; 856 pState->cMaxScreenY = pResolution->height - 1; 857 return 0; 858 } 859 case MSIOBUTTONS: 860 { 861 LogFlowFunc(("MSIOBUTTONS\n")); 862 AssertReturn(cbBuffer >= sizeof(int), EINVAL); 863 *(int *)pvData = 0; 864 *pcbData = sizeof(int); 865 return 0; 866 } 867 case VUIDGWHEELCOUNT: 868 { 869 LogFlowFunc(("VUIDGWHEELCOUNT\n")); 870 AssertReturn(cbBuffer >= sizeof(int), EINVAL); 871 *(int *)pvData = 0; 872 *pcbData = sizeof(int); 873 return 0; 874 } 875 case VUIDGWHEELINFO: 876 case VUIDGWHEELSTATE: 877 case VUIDSWHEELSTATE: 878 LogFlowFunc(("VUIDGWHEELINFO/VUIDGWHEELSTATE/VUIDSWHEELSTATE\n")); 879 return EINVAL; 880 default: 881 LogFlowFunc(("Invalid IOCtl command %x\n", cCmd)); 882 return EINVAL; 883 } 884 } 885 886 887 /** 888 * Handle a VBoxGuest IOCtl. 889 * @copydoc FNVBOXGUESTSOLARISIOCTL 890 */ 891 static int vboxGuestSolarisGuestIOCtl(vboxguest_state_t *pState, int cCmd, 892 void *pvData, size_t cbBuffer, 893 size_t *pcbData, int *prc) 894 { 895 int rc = VBoxGuestCommonIOCtl(cCmd, &g_DevExt, pState->pSession, pvData, cbBuffer, pcbData); 896 if (RT_SUCCESS(rc)) 897 { 898 *prc = rc; 899 return 0; 900 } 901 else 902 { 903 /* 904 * We Log() instead of LogRel() here because VBOXGUEST_IOCTL_WAITEVENT can return VERR_TIMEOUT, 905 * VBOXGUEST_IOCTL_CANCEL_ALL_EVENTS can return VERR_INTERRUPTED and possibly more in the future; 906 * which are not really failures that require logging. 907 */ 908 Log((DEVICE_NAME "::IOCtl: VBoxGuestCommonIOCtl failed. Cmd=%#x rc=%d\n", cCmd, rc)); 909 rc = RTErrConvertToErrno(rc); 910 return rc; 911 } 912 } 913 914 915 /** 916 * Info entry point, called by solaris kernel for obtaining driver info. 917 * 918 * @param pDip The module structure instance (do not use). 919 * @param enmCmd Information request type. 920 * @param pvArg Type specific argument. 921 * @param ppvResult Where to store the requested info. 922 * 923 * @return corresponding solaris error code. 924 */ 925 int vboxGuestSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, 926 void *pvArg, void **ppvResult) 927 { 928 int rc = DDI_SUCCESS; 929 930 LogFlow((DEVICE_NAME "::GetInfo\n")); 931 switch (enmCmd) 932 { 933 case DDI_INFO_DEVT2DEVINFO: 934 *ppvResult = (void *)g_pDip; 935 break; 936 937 case DDI_INFO_DEVT2INSTANCE: 938 *ppvResult = (void *)(uintptr_t)ddi_get_instance(g_pDip); 939 break; 940 941 default: 942 rc = DDI_FAILURE; 943 break; 944 } 945 946 NOREF(pvArg); 947 return rc; 948 } 949 950 951 /* Helpers for vboxGuestSolarisAttach and vboxGuestSolarisDetach. */ 952 static int vboxGuestSolarisAddIRQ(dev_info_t *pDip); 953 static void vboxGuestSolarisRemoveIRQ(dev_info_t *pDip); 257 954 258 955 /** … … 264 961 * @return corresponding solaris error code. 265 962 */ 266 static int VBoxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)963 int vboxGuestSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd) 267 964 { 268 965 LogFlow((DEVICE_NAME "::Attach\n")); … … 271 968 case DDI_ATTACH: 272 969 { 970 int instance, rc; 971 ddi_acc_handle_t PciHandle; 972 273 973 if (g_pDip) 274 974 { … … 276 976 return DDI_FAILURE; 277 977 } 278 279 int instance = ddi_get_instance(pDip); 978 instance = ddi_get_instance(pDip); 280 979 281 980 /* 282 981 * Enable resources for PCI access. 283 982 */ 284 ddi_acc_handle_t PciHandle; 285 int rc = pci_config_setup(pDip, &PciHandle); 983 rc = pci_config_setup(pDip, &PciHandle); 286 984 if (rc == DDI_SUCCESS) 287 985 { … … 289 987 * Map the register address space. 290 988 */ 291 c addr_t baseAddr;989 char *baseAddr; /* Actually caddr_t. */ 292 990 ddi_device_acc_attr_t deviceAttr; 293 991 deviceAttr.devacc_attr_version = DDI_DEVICE_ATTR_V0; … … 312 1010 * Add IRQ of VMMDev. 313 1011 */ 314 rc = VBoxGuestSolarisAddIRQ(pDip);1012 rc = vboxGuestSolarisAddIRQ(pDip); 315 1013 if (rc == DDI_SUCCESS) 316 1014 { … … 318 1016 * Call the common device extension initializer. 319 1017 */ 320 rc = VBoxGuestInitDevExt(&g_DevExt, g_uIOPortBase, g_pMMIOBase, g_cbMMIO,321 1018 #if ARCH_BITS == 64 322 VBOXOSTYPE_Solaris_x64, 1019 # define VBOXGUEST_OS_TYPE VBOXOSTYPE_Solaris_x64 323 1020 #else 324 VBOXOSTYPE_Solaris, 1021 # define VBOXGUEST_OS_TYPE VBOXOSTYPE_Solaris 325 1022 #endif 326 VMMDEV_EVENT_MOUSE_POSITION_CHANGED); 1023 rc = VBoxGuestInitDevExt(&g_DevExt, 1024 g_uIOPortBase, 1025 g_pMMIOBase, g_cbMMIO, 1026 VBOXGUEST_OS_TYPE, 1027 VMMDEV_EVENT_MOUSE_POSITION_CHANGED); 1028 #undef VBOXGUEST_OS_TYPE 327 1029 if (RT_SUCCESS(rc)) 328 1030 { … … 340 1042 else 341 1043 LogRel((DEVICE_NAME "::Attach: VBoxGuestInitDevExt failed.\n")); 342 VBoxGuestSolarisRemoveIRQ(pDip);1044 vboxGuestSolarisRemoveIRQ(pDip); 343 1045 } 344 1046 else 345 LogRel((DEVICE_NAME "::Attach: VBoxGuestSolarisAddIRQ failed.\n"));1047 LogRel((DEVICE_NAME "::Attach: vboxGuestSolarisAddIRQ failed.\n")); 346 1048 ddi_regs_map_free(&g_PciMMIOHandle); 347 1049 } … … 382 1084 * @return corresponding solaris error code. 383 1085 */ 384 static int VBoxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)1086 int vboxGuestSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd) 385 1087 { 386 1088 LogFlow((DEVICE_NAME "::Detach\n")); … … 389 1091 case DDI_DETACH: 390 1092 { 391 VBoxGuestSolarisRemoveIRQ(pDip);1093 vboxGuestSolarisRemoveIRQ(pDip); 392 1094 ddi_regs_map_free(&g_PciIOHandle); 393 1095 ddi_regs_map_free(&g_PciMMIOHandle); … … 410 1112 411 1113 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 */ 422 static 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 */ 450 static 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 501 static 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 532 static 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 552 static 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 */ 580 static 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 699 static 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 1114 /* Interrupt service routine installed by vboxGuestSolarisAddIRQ. */ 1115 static uint_t vboxGuestSolarisISR(char *Arg /* Actually caddr_t. */); 729 1116 730 1117 /** … … 734 1121 * @param pDip Pointer to the device info structure. 735 1122 */ 736 static int VBoxGuestSolarisAddIRQ(dev_info_t *pDip) 737 { 1123 static int vboxGuestSolarisAddIRQ(dev_info_t *pDip) 1124 { 1125 int IntrType = 0, rc; 1126 738 1127 LogFlow((DEVICE_NAME "::AddIRQ: pDip=%p\n", pDip)); 739 740 int IntrType = 0; 741 int rc = ddi_intr_get_supported_types(pDip, &IntrType); 1128 rc = ddi_intr_get_supported_types(pDip, &IntrType); 742 1129 if (rc == DDI_SUCCESS) 743 1130 { … … 759 1146 if (g_pIntr) 760 1147 { 761 int IntrAllocated; 1148 size_t IntrAllocated; 1149 unsigned i; 762 1150 rc = ddi_intr_alloc(pDip, g_pIntr, IntrType, 0, IntrCount, &IntrAllocated, DDI_INTR_ALLOC_NORMAL); 763 1151 if ( rc == DDI_SUCCESS 764 1152 && IntrAllocated > 0) 765 1153 { 1154 uint_t uIntrPriority; 766 1155 g_cIntrAllocated = IntrAllocated; 767 uint_t uIntrPriority;768 1156 rc = ddi_intr_get_pri(g_pIntr[0], &uIntrPriority); 769 1157 if (rc == DDI_SUCCESS) … … 773 1161 774 1162 /* Assign interrupt handler functions and enable interrupts. */ 775 for (i nt i= 0; i < IntrAllocated; i++)1163 for (i = 0; i < IntrAllocated; i++) 776 1164 { 777 rc = ddi_intr_add_handler(g_pIntr[i], (ddi_intr_handler_t *) VBoxGuestSolarisISR,1165 rc = ddi_intr_add_handler(g_pIntr[i], (ddi_intr_handler_t *)vboxGuestSolarisISR, 778 1166 NULL /* No Private Data */, NULL); 779 1167 if (rc == DDI_SUCCESS) … … 791 1179 /* Remove any assigned handlers */ 792 1180 LogRel((DEVICE_NAME ":failed to assign IRQs allocated=%d\n", IntrAllocated)); 793 for (i nt x = 0; x < IntrAllocated; x++)794 ddi_intr_remove_handler(g_pIntr[ x]);1181 for (i = 0; i < IntrAllocated; i++) 1182 ddi_intr_remove_handler(g_pIntr[i]); 795 1183 } 796 1184 else … … 798 1186 799 1187 /* Remove allocated IRQs, too bad we can free only one handle at a time. */ 800 for (i nt k = 0; k < g_cIntrAllocated; k++)801 ddi_intr_free(g_pIntr[ k]);1188 for (i = 0; i < g_cIntrAllocated; i++) 1189 ddi_intr_free(g_pIntr[i]); 802 1190 } 803 1191 else … … 828 1216 * @param pDip Pointer to the device info structure. 829 1217 */ 830 static void VBoxGuestSolarisRemoveIRQ(dev_info_t *pDip) 831 { 1218 static void vboxGuestSolarisRemoveIRQ(dev_info_t *pDip) 1219 { 1220 unsigned i; 1221 832 1222 LogFlow((DEVICE_NAME "::RemoveIRQ:\n")); 833 834 for (int i = 0; i < g_cIntrAllocated; i++) 1223 for (i = 0; i < g_cIntrAllocated; i++) 835 1224 { 836 1225 int rc = ddi_intr_disable(g_pIntr[i]); … … 853 1242 * @returns DDI_INTR_CLAIMED if it's our interrupt, DDI_INTR_UNCLAIMED if it isn't. 854 1243 */ 855 static uint_t VBoxGuestSolarisISR(caddr_t Arg) 856 { 1244 static uint_t vboxGuestSolarisISR(char *Arg /* Actually caddr_t. */) 1245 { 1246 bool fOurIRQ; 1247 857 1248 LogFlow((DEVICE_NAME "::ISR:\n")); 858 859 1249 mutex_enter(&g_IrqMtx); 860 boolfOurIRQ = VBoxGuestCommonISR(&g_DevExt);1250 fOurIRQ = VBoxGuestCommonISR(&g_DevExt); 861 1251 mutex_exit(&g_IrqMtx); 862 863 1252 return fOurIRQ ? DDI_INTR_CLAIMED : DDI_INTR_UNCLAIMED; 864 1253 } 865 1254 866 1255 1256 /* Helper for VBoxGuestNativeISRMousePollEvent. */ 1257 static void VBoxGuestVUIDPutAbsEvent(ushort_t cEvent, int cValue); 1258 1259 /** 1260 * Native part of the IRQ service routine, called when the VBoxGuest mouse 1261 * pointer is moved. We send a VUID event up to user space. 1262 */ 867 1263 void VBoxGuestNativeISRMousePollEvent(PVBOXGUESTDEVEXT pDevExt) 868 1264 { 1265 VMMDevReqMouseStatus *pReq; 1266 int rc; 869 1267 LogFlow((DEVICE_NAME "::NativeISRMousePollEvent:\n")); 870 1268 871 /* 872 * Wake up poll waiters. 873 */ 874 pollwakeup(&g_PollHead, POLLIN | POLLRDNORM); 875 } 876 877 878 /* Common code that depend on g_DevExt. */ 1269 rc = VbglGRAlloc((VMMDevRequestHeader **)&pReq, sizeof(*pReq), 1270 VMMDevReq_GetMouseStatus); 1271 if (RT_FAILURE(rc)) 1272 return; /* If kernel memory is short a missed event is acceptable! */ 1273 pReq->mouseFeatures = 0; 1274 pReq->pointerXPos = 0; 1275 pReq->pointerYPos = 0; 1276 rc = VbglGRPerform(&pReq->header); 1277 if (RT_SUCCESS(rc)) 1278 { 1279 int cMaxScreenX = g_pState->cMaxScreenX; 1280 int cMaxScreenY = g_pState->cMaxScreenY; 1281 1282 VBoxGuestVUIDPutAbsEvent(LOC_X_ABSOLUTE, 1283 pReq->pointerXPos * cMaxScreenX 1284 / VMMDEV_MOUSE_RANGE_MAX); 1285 VBoxGuestVUIDPutAbsEvent(LOC_Y_ABSOLUTE, 1286 pReq->pointerYPos * cMaxScreenY 1287 / VMMDEV_MOUSE_RANGE_MAX); 1288 } 1289 VbglGRFree(&pReq->header); 1290 } 1291 1292 1293 void VBoxGuestVUIDPutAbsEvent(ushort_t cEvent, int cValue) 1294 { 1295 queue_t *pReadQueue = RD(g_pState->pWriteQueue); 1296 mblk_t *pMBlk = allocb(sizeof(Firm_event, BPRI_HI)); 1297 Firm_event *pEvent; 1298 AssertReturnVoid(cEvent == LOC_X_ABSOLUTE || cEvent == LOC_Y_ABSOLUTE); 1299 if (!pMBlk) 1300 return; /* If kernel memory is short a missed event is acceptable! */ 1301 pEvent = (Firm_event *)pMBlk->b_wptr; 1302 pEvent->id = cEvent; 1303 pEvent->pair_type = FE_PAIR_DELTA; 1304 pEvent->pair = cEvent == LOC_X_ABSOLUTE ? LOC_X_DELTA : LOC_Y_DELTA; 1305 pEvent->value = cValue; 1306 uniqtime32(&pEvent->time); 1307 pMBlk->b_wptr += sizeof(Firm_event); 1308 /* Put the message on the queue immediately if it is not blocked. */ 1309 if (canput(pReadQueue->q_next)) 1310 putnext(pReadQueue, pMBlk); 1311 else 1312 putbq(pReadQueue, pMBlk); 1313 } 1314 1315 1316 /* Common code that depends on g_DevExt. */ 879 1317 #include "VBoxGuestIDC-unix.c.h" 880 1318
Note:
See TracChangeset
for help on using the changeset viewer.