VirtualBox

source: vbox/trunk/src/VBox/Devices/VMMDev/VBoxDev.cpp@ 3237

Last change on this file since 3237 was 3237, checked in by vboxsync, 18 years ago

Set size and version after memsetting the VMMDev RAM on reset. Patched up the error handling in the constructor.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 69.0 KB
Line 
1/** @file
2 *
3 * VBox Guest/VMM/host communication:
4 * Virtual communication device
5 */
6
7/*
8 * Copyright (C) 2006-2007 innotek GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23/* #define LOG_ENABLED */
24
25#include <stdio.h>
26#include <string.h>
27
28#include <VBox/VBoxDev.h>
29#include <VBox/VBoxGuest.h>
30#include <VBox/param.h>
31#include <VBox/mm.h>
32#include <VBox/pgm.h>
33#include <VBox/err.h>
34
35#define LOG_GROUP LOG_GROUP_DEV_VMM
36#include <VBox/log.h>
37#include <iprt/assert.h>
38#include <iprt/time.h>
39
40#include "VMMDevState.h"
41
42#ifdef VBOX_HGCM
43#include "VMMDevHGCM.h"
44#endif
45
46#define PCIDEV_2_VMMDEVSTATE(pPciDev) ( (VMMDevState *)(pPciDev) )
47#define VMMDEVSTATE_2_DEVINS(pVMMDevState) ( (pVMMDevState)->pDevIns )
48
49#define VBOX_GUEST_ADDITIONS_VERSION_1_03(s) \
50 ((RT_HIWORD ((s)->guestInfo.additionsVersion) == 1) && \
51 (RT_LOWORD ((s)->guestInfo.additionsVersion) == 3))
52
53#define VBOX_GUEST_ADDITIONS_VERSION_OK(additionsVersion) \
54 (RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
55 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION))
56
57#define VBOX_GUEST_ADDITIONS_VERSION_OLD(additionsVersion) \
58 ((RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) \
59 || ((RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
60 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION))
61
62#define VBOX_GUEST_ADDITIONS_VERSION_TOO_OLD(additionsVersion) \
63 (RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION))
64
65#define VBOX_GUEST_ADDITIONS_VERSION_NEW(additionsVersion) \
66 ((RT_HIWORD(additionsVersion) > RT_HIWORD(VMMDEV_VERSION) \
67 || ((RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
68 && RT_LOWORD(additionsVersion) > RT_LOWORD(VMMDEV_VERSION))
69
70#ifndef VBOX_DEVICE_STRUCT_TESTCASE
71
72/* Whenever host wants to inform guest about something
73 * an IRQ notification will be raised.
74 *
75 * VMMDev PDM interface will contain the guest notification method.
76 *
77 * There is a 32 bit event mask which will be read
78 * by guest on an interrupt. A non zero bit in the mask
79 * means that the specific event occured and requires
80 * processing on guest side.
81 *
82 * After reading the event mask guest must issue a
83 * generic request AcknowlegdeEvents.
84 *
85 * IRQ line is set to 1 (request) if there are unprocessed
86 * events, that is the event mask is not zero.
87 *
88 * After receiving an interrupt and checking event mask,
89 * the guest must process events using the event specific
90 * mechanism.
91 *
92 * That is if mouse capabilities were changed,
93 * guest will use VMMDev_GetMouseStatus generic request.
94 *
95 * Event mask is only a set of flags indicating that guest
96 * must proceed with a procedure.
97 *
98 * Unsupported events are therefore ignored.
99 * The guest additions must inform host which events they
100 * want to receive, to avoid unnecessary IRQ processing.
101 * By default no events are signalled to guest.
102 *
103 * This seems to be fast method. It requires
104 * only one context switch for an event processing.
105 *
106 */
107
108static void vmmdevSetIRQ_Legacy_EMT (VMMDevState *pVMMDevState)
109{
110 if (!pVMMDevState->fu32AdditionsOk)
111 {
112 Log(("vmmdevSetIRQ: IRQ is not generated, guest has not yet reported to us.\n"));
113 return;
114 }
115
116 uint32_t u32IRQLevel = 0;
117
118 /* Filter unsupported events */
119 uint32_t u32EventFlags =
120 pVMMDevState->u32HostEventFlags
121 & pVMMDevState->pVMMDevRAMHC->V.V1_03.u32GuestEventMask;
122
123 Log(("vmmdevSetIRQ: u32EventFlags = 0x%08X, "
124 "pVMMDevState->u32HostEventFlags = 0x%08X, "
125 "pVMMDevState->pVMMDevRAMHC->u32GuestEventMask = 0x%08X\n",
126 u32EventFlags,
127 pVMMDevState->u32HostEventFlags,
128 pVMMDevState->pVMMDevRAMHC->V.V1_03.u32GuestEventMask));
129
130 /* Move event flags to VMMDev RAM */
131 pVMMDevState->pVMMDevRAMHC->V.V1_03.u32HostEvents = u32EventFlags;
132
133 if (u32EventFlags)
134 {
135 /* Clear host flags which will be delivered to guest. */
136 pVMMDevState->u32HostEventFlags &= ~u32EventFlags;
137 Log(("vmmdevSetIRQ: pVMMDevState->u32HostEventFlags = 0x%08X\n",
138 pVMMDevState->u32HostEventFlags));
139 u32IRQLevel = 1;
140 }
141
142 /* Set IRQ level for pin 0 */
143 /** @todo make IRQ pin configurable, at least a symbolic constant */
144 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
145 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, u32IRQLevel);
146 Log(("vmmdevSetIRQ: IRQ set %d\n", u32IRQLevel));
147}
148
149static void vmmdevMaybeSetIRQ_EMT (VMMDevState *pVMMDevState)
150{
151 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS (pVMMDevState);
152
153#ifdef DEBUG_sunlover
154 Log(("vmmdevMaybeSetIRQ_EMT: u32HostEventFlags = 0x%08X, u32GuestFilterMask = 0x%08X.\n",
155 pVMMDevState->u32HostEventFlags, pVMMDevState->u32GuestFilterMask));
156#endif /* DEBUG_sunlover */
157
158 if (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask)
159 {
160 pVMMDevState->pVMMDevRAMHC->V.V1_04.fHaveEvents = true;
161 PDMDevHlpPCISetIrqNoWait (pDevIns, 0, 1);
162#ifdef DEBUG_sunlover
163 Log(("vmmdevMaybeSetIRQ_EMT: IRQ set.\n"));
164#endif /* DEBUG_sunlover */
165 }
166}
167
168static void vmmdevNotifyGuest_EMT (VMMDevState *pVMMDevState, uint32_t u32EventMask)
169{
170#ifdef DEBUG_sunlover
171 Log(("VMMDevNotifyGuest_EMT: u32EventMask = 0x%08X.\n", u32EventMask));
172#endif /* DEBUG_sunlover */
173
174 if (VBOX_GUEST_ADDITIONS_VERSION_1_03 (pVMMDevState))
175 {
176#ifdef DEBUG_sunlover
177 Log(("VMMDevNotifyGuest_EMT: Old additions detected.\n"));
178#endif /* DEBUG_sunlover */
179
180 pVMMDevState->u32HostEventFlags |= u32EventMask;
181 vmmdevSetIRQ_Legacy_EMT (pVMMDevState);
182 }
183 else
184 {
185#ifdef DEBUG_sunlover
186 Log(("VMMDevNotifyGuest_EMT: New additions detected.\n"));
187#endif /* DEBUG_sunlover */
188
189 if (!pVMMDevState->fu32AdditionsOk)
190 {
191 pVMMDevState->u32HostEventFlags |= u32EventMask;
192 Log(("vmmdevNotifyGuest_EMT: IRQ is not generated, guest has not yet reported to us.\n"));
193 return;
194 }
195
196 const bool fHadEvents =
197 (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask) != 0;
198
199#ifdef DEBUG_sunlover
200 Log(("VMMDevNotifyGuest_EMT: fHadEvents = %d, u32HostEventFlags = 0x%08X, u32GuestFilterMask = 0x%08X.\n",
201 fHadEvents, pVMMDevState->u32HostEventFlags, pVMMDevState->u32GuestFilterMask));
202#endif /* DEBUG_sunlover */
203
204 pVMMDevState->u32HostEventFlags |= u32EventMask;
205
206 if (!fHadEvents)
207 vmmdevMaybeSetIRQ_EMT (pVMMDevState);
208 }
209}
210
211static void vmmdevCtlGuestFilterMask_EMT (VMMDevState *pVMMDevState,
212 uint32_t u32OrMask,
213 uint32_t u32NotMask)
214{
215 const bool fHadEvents =
216 (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask) != 0;
217
218 if (fHadEvents)
219 {
220 if (!pVMMDevState->fNewGuestFilterMask)
221 pVMMDevState->u32NewGuestFilterMask = pVMMDevState->u32GuestFilterMask;
222
223 pVMMDevState->u32NewGuestFilterMask |= u32OrMask;
224 pVMMDevState->u32NewGuestFilterMask &= ~u32NotMask;
225 pVMMDevState->fNewGuestFilterMask = true;
226 }
227 else
228 {
229 pVMMDevState->u32GuestFilterMask |= u32OrMask;
230 pVMMDevState->u32GuestFilterMask &= ~u32NotMask;
231 vmmdevMaybeSetIRQ_EMT (pVMMDevState);
232 }
233}
234
235void VMMDevNotifyGuest (VMMDevState *pVMMDevState, uint32_t u32EventMask)
236{
237 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
238 PVM pVM = PDMDevHlpGetVM(pDevIns);
239 int rc;
240 PVMREQ pReq;
241
242#ifdef DEBUG_sunlover
243 Log(("VMMDevNotifyGuest: u32EventMask = 0x%08X.\n", u32EventMask));
244#endif /* DEBUG_sunlover */
245
246 rc = VMR3ReqCallVoid (pVM, &pReq, RT_INDEFINITE_WAIT,
247 (PFNRT) vmmdevNotifyGuest_EMT,
248 2, pVMMDevState, u32EventMask);
249 AssertReleaseRC (rc);
250 VMR3ReqFree (pReq);
251}
252
253/**
254 * Port I/O Handler for OUT operations.
255 *
256 * @returns VBox status code.
257 *
258 * @param pDevIns The device instance.
259 * @param pvUser User argument - ignored.
260 * @param uPort Port number used for the IN operation.
261 * @param u32 The value to output.
262 * @param cb The value size in bytes.
263 */
264#undef LOG_GROUP
265#define LOG_GROUP LOG_GROUP_DEV_VMM_BACKDOOR
266
267static DECLCALLBACK(int) vmmdevBackdoorLog(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
268{
269 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
270
271 if (!pData->fBackdoorLogDisabled && cb == 1 && Port == RTLOG_DEBUG_PORT)
272 {
273
274 /* The raw version. */
275 switch (u32)
276 {
277 case '\r': Log2(("vmmdev: <return>\n")); break;
278 case '\n': Log2(("vmmdev: <newline>\n")); break;
279 case '\t': Log2(("vmmdev: <tab>\n")); break;
280 default: Log2(("vmmdev: %c (%02x)\n", u32, u32)); break;
281 }
282
283 /* The readable, buffered version. */
284 if (u32 == '\n' || u32 == '\r')
285 {
286 pData->szMsg[pData->iMsg] = '\0';
287 if (pData->iMsg)
288 LogRel(("Guest Log: %s\n", pData->szMsg));
289 pData->iMsg = 0;
290 }
291 else
292 {
293 if (pData->iMsg >= sizeof(pData->szMsg)-1)
294 {
295 pData->szMsg[pData->iMsg] = '\0';
296 LogRel(("Guest Log: %s\n", pData->szMsg));
297 pData->iMsg = 0;
298 }
299 pData->szMsg[pData->iMsg] = (char )u32;
300 pData->szMsg[++pData->iMsg] = '\0';
301 }
302 }
303 return VINF_SUCCESS;
304}
305#undef LOG_GROUP
306#define LOG_GROUP LOG_GROUP_DEV_VMM
307
308#ifdef TIMESYNC_BACKDOOR
309/**
310 * Port I/O Handler for OUT operations.
311 *
312 * @returns VBox status code.
313 *
314 * @param pDevIns The device instance.
315 * @param pvUser User argument - ignored.
316 * @param uPort Port number used for the IN operation.
317 * @param u32 The value to output.
318 * @param cb The value size in bytes.
319 */
320static DECLCALLBACK(int) vmmdevTimesyncBackdoorWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
321{
322 NOREF(pvUser);
323 if (cb == 4)
324 {
325 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
326 switch (u32)
327 {
328 case 0:
329 pData->fTimesyncBackdoorLo = false;
330 break;
331 case 1:
332 pData->fTimesyncBackdoorLo = true;
333 }
334 return VINF_SUCCESS;
335
336 }
337 return VINF_SUCCESS;
338}
339
340/**
341 * Port I/O Handler for backdoor timesync IN operations.
342 *
343 * @returns VBox status code.
344 *
345 * @param pDevIns The device instance.
346 * @param pvUser User argument - ignored.
347 * @param uPort Port number used for the IN operation.
348 * @param pu32 Where to store the result.
349 * @param cb Number of bytes read.
350 */
351static DECLCALLBACK(int) vmmdevTimesyncBackdoorRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
352{
353 int rc;
354 NOREF(pvUser);
355 if (cb == 4)
356 {
357 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
358 RTTIMESPEC now;
359
360 if (pData->fTimesyncBackdoorLo)
361 {
362 *pu32 = (uint32_t)(pData->hostTime & (uint64_t)0xFFFFFFFF);
363 }
364 else
365 {
366 pData->hostTime = RTTimeSpecGetMilli(PDMDevHlpUTCNow(pDevIns, &now));
367 *pu32 = (uint32_t)(pData->hostTime >> 32);
368 }
369 rc = VINF_SUCCESS;
370 }
371 else
372 rc = VERR_IOM_IOPORT_UNUSED;
373 return rc;
374}
375#endif /* TIMESYNC_BACKDOOR */
376
377/**
378 * Port I/O Handler for the generic request interface
379 * @see FNIOMIOPORTOUT for details.
380 */
381static DECLCALLBACK(int) vmmdevRequestHandler(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
382{
383 VMMDevState *pData = (VMMDevState*)pvUser;
384 int rcRet = VINF_SUCCESS;
385 int rc;
386
387 /*
388 * The caller has passed the guest context physical address
389 * of the request structure. Get the corresponding host virtual
390 * address.
391 */
392 VMMDevRequestHeader *requestHeader = NULL;
393 rc = PDMDevHlpPhys2HCVirt(pDevIns, (RTGCPHYS)u32, 0, (PRTHCPTR)&requestHeader);
394 if (VBOX_FAILURE(rc) || !requestHeader)
395 {
396 AssertMsgFailed(("VMMDev could not convert guest physical address to host virtual! rc = %Vrc\n", rc));
397 return VINF_SUCCESS;
398 }
399
400 /* the structure size must be greater or equal to the header size */
401 if (requestHeader->size < sizeof(VMMDevRequestHeader))
402 {
403 Log(("VMMDev request header size too small! size = %d\n", requestHeader->size));
404 return VINF_SUCCESS;
405 }
406
407 /* check the version of the header structure */
408 if (requestHeader->version != VMMDEV_REQUEST_HEADER_VERSION)
409 {
410 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader->version, VMMDEV_REQUEST_HEADER_VERSION));
411 return VINF_SUCCESS;
412 }
413
414 Log(("VMMDev request issued: %d\n", requestHeader->requestType));
415
416 if (requestHeader->requestType != VMMDevReq_ReportGuestInfo
417 && !pData->fu32AdditionsOk)
418 {
419 Log(("VMMDev: guest has not yet reported to us. Refusing operation.\n"));
420 requestHeader->rc = VERR_NOT_SUPPORTED;
421 return VINF_SUCCESS;
422 }
423
424 /* which request was sent? */
425 switch (requestHeader->requestType)
426 {
427 /*
428 * Guest wants to give up a timeslice
429 */
430 case VMMDevReq_Idle:
431 {
432 /* just return to EMT telling it that we want to halt */
433 return VINF_EM_HALT;
434 break;
435 }
436
437 /*
438 * Guest is reporting its information
439 */
440 case VMMDevReq_ReportGuestInfo:
441 {
442 if (requestHeader->size < sizeof(VMMDevReportGuestInfo))
443 {
444 AssertMsgFailed(("VMMDev guest information structure has invalid size!\n"));
445 requestHeader->rc = VERR_INVALID_PARAMETER;
446 }
447 else
448 {
449 VMMDevReportGuestInfo *guestInfo = (VMMDevReportGuestInfo*)requestHeader;
450
451 if (memcmp (&pData->guestInfo, &guestInfo->guestInfo, sizeof (guestInfo->guestInfo)) != 0)
452 {
453 /* make a copy of supplied information */
454 pData->guestInfo = guestInfo->guestInfo;
455
456 /* Check additions version */
457 pData->fu32AdditionsOk = VBOX_GUEST_ADDITIONS_VERSION_OK(pData->guestInfo.additionsVersion);
458
459 LogRel(("Guest Additions information report: additionsVersion = 0x%08X osType = 0x%08X\n",
460 pData->guestInfo.additionsVersion,
461 pData->guestInfo.osType));
462 pData->pDrv->pfnUpdateGuestVersion(pData->pDrv, &pData->guestInfo);
463 }
464
465 if (pData->fu32AdditionsOk)
466 {
467 requestHeader->rc = VINF_SUCCESS;
468 }
469 else
470 {
471 requestHeader->rc = VERR_VERSION_MISMATCH;
472 }
473 }
474 break;
475 }
476
477 /*
478 * Retrieve mouse information
479 */
480 case VMMDevReq_GetMouseStatus:
481 {
482 if (requestHeader->size != sizeof(VMMDevReqMouseStatus))
483 {
484 AssertMsgFailed(("VMMDev mouse status structure has invalid size!\n"));
485 requestHeader->rc = VERR_INVALID_PARAMETER;
486 }
487 else
488 {
489 VMMDevReqMouseStatus *mouseStatus = (VMMDevReqMouseStatus*)requestHeader;
490 mouseStatus->mouseFeatures = 0;
491 if (pData->mouseCapabilities & VMMDEV_MOUSEHOSTWANTSABS)
492 {
493 mouseStatus->mouseFeatures |= VBOXGUEST_MOUSE_HOST_CAN_ABSOLUTE;
494 }
495 if (pData->mouseCapabilities & VMMDEV_MOUSEGUESTWANTSABS)
496 {
497 mouseStatus->mouseFeatures |= VBOXGUEST_MOUSE_GUEST_CAN_ABSOLUTE;
498 }
499 if (pData->mouseCapabilities & VMMDEV_MOUSEHOSTCANNOTHWPOINTER)
500 {
501 mouseStatus->mouseFeatures |= VBOXGUEST_MOUSE_HOST_CANNOT_HWPOINTER;
502 }
503 mouseStatus->pointerXPos = pData->mouseXAbs;
504 mouseStatus->pointerYPos = pData->mouseYAbs;
505 Log(("returning mouse status: features = %d, absX = %d, absY = %d\n", mouseStatus->mouseFeatures,
506 mouseStatus->pointerXPos, mouseStatus->pointerYPos));
507 requestHeader->rc = VINF_SUCCESS;
508 }
509 break;
510 }
511
512 /*
513 * Set mouse information
514 */
515 case VMMDevReq_SetMouseStatus:
516 {
517 if (requestHeader->size != sizeof(VMMDevReqMouseStatus))
518 {
519 AssertMsgFailed(("VMMDev mouse status structure has invalid size %d (%#x) version=%d!\n",
520 requestHeader->size, requestHeader->size, requestHeader->size, requestHeader->version));
521 requestHeader->rc = VERR_INVALID_PARAMETER;
522 }
523 else
524 {
525 bool bCapsChanged = false;
526
527 VMMDevReqMouseStatus *mouseStatus = (VMMDevReqMouseStatus*)requestHeader;
528
529 /* check if the guest wants absolute coordinates */
530 if (mouseStatus->mouseFeatures & VBOXGUEST_MOUSE_GUEST_CAN_ABSOLUTE)
531 {
532 /* set the capability flag and the changed flag if it's actually a change */
533 if (!(pData->mouseCapabilities & VMMDEV_MOUSEGUESTWANTSABS))
534 {
535 pData->mouseCapabilities |= VMMDEV_MOUSEGUESTWANTSABS;
536 bCapsChanged = true;
537 LogRel(("Guest requests mouse pointer integration\n"));
538 }
539 } else
540 {
541 if (pData->mouseCapabilities & VMMDEV_MOUSEGUESTWANTSABS)
542 {
543 pData->mouseCapabilities &= ~VMMDEV_MOUSEGUESTWANTSABS;
544 bCapsChanged = true;
545 LogRel(("Guest disables mouse pointer integration\n"));
546 }
547 }
548 if (mouseStatus->mouseFeatures & VBOXGUEST_MOUSE_GUEST_NEEDS_HOST_CURSOR)
549 pData->mouseCapabilities |= VMMDEV_MOUSEGUESTNEEDSHOSTCUR;
550 else
551 pData->mouseCapabilities &= ~VMMDEV_MOUSEGUESTNEEDSHOSTCUR;
552
553 /*
554 * Notify connector if something has changed
555 */
556 if (bCapsChanged)
557 {
558 Log(("VMMDevReq_SetMouseStatus: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
559 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
560 }
561 requestHeader->rc = VINF_SUCCESS;
562 }
563
564 break;
565 }
566
567 /*
568 * Set a new mouse pointer shape
569 */
570 case VMMDevReq_SetPointerShape:
571 {
572 if (requestHeader->size < sizeof(VMMDevReqMousePointer))
573 {
574 AssertMsg(requestHeader->size == 0x10028 && requestHeader->version == 10000, /* don't bitch about legacy!!! */
575 ("VMMDev mouse shape structure has invalid size %d (%#x) version=%d!\n",
576 requestHeader->size, requestHeader->size, requestHeader->size, requestHeader->version));
577 requestHeader->rc = VERR_INVALID_PARAMETER;
578 }
579 else
580 {
581 VMMDevReqMousePointer *pointerShape = (VMMDevReqMousePointer*)requestHeader;
582
583 bool fVisible = (pointerShape->fFlags & VBOX_MOUSE_POINTER_VISIBLE) != 0;
584 bool fAlpha = (pointerShape->fFlags & VBOX_MOUSE_POINTER_ALPHA) != 0;
585 bool fShape = (pointerShape->fFlags & VBOX_MOUSE_POINTER_SHAPE) != 0;
586
587 Log(("VMMDevReq_SetPointerShape: visible: %d, alpha: %d, shape = %d, width: %d, height: %d\n",
588 fVisible, fAlpha, fShape, pointerShape->width, pointerShape->height));
589
590 /* forward call to driver */
591 if (fShape)
592 {
593 pData->pDrv->pfnUpdatePointerShape(pData->pDrv,
594 fVisible,
595 fAlpha,
596 pointerShape->xHot, pointerShape->yHot,
597 pointerShape->width, pointerShape->height,
598 pointerShape->pointerData);
599 }
600 else
601 {
602 pData->pDrv->pfnUpdatePointerShape(pData->pDrv,
603 fVisible,
604 0,
605 0, 0,
606 0, 0,
607 NULL);
608 }
609 requestHeader->rc = VINF_SUCCESS;
610 }
611 break;
612 }
613
614 /*
615 * Query the system time from the host
616 */
617 case VMMDevReq_GetHostTime:
618 {
619 if (requestHeader->size != sizeof(VMMDevReqHostTime))
620 {
621 AssertMsgFailed(("VMMDev host time structure has invalid size!\n"));
622 requestHeader->rc = VERR_INVALID_PARAMETER;
623 }
624 else if (RT_UNLIKELY(pData->fGetHostTimeDisabled))
625 requestHeader->rc = VERR_NOT_SUPPORTED;
626 else
627 {
628 VMMDevReqHostTime *hostTimeReq = (VMMDevReqHostTime*)requestHeader;
629 RTTIMESPEC now;
630 hostTimeReq->time = RTTimeSpecGetMilli(PDMDevHlpUTCNow(pDevIns, &now));
631 requestHeader->rc = VINF_SUCCESS;
632 }
633 break;
634 }
635
636 /*
637 * Query information about the hypervisor
638 */
639 case VMMDevReq_GetHypervisorInfo:
640 {
641 if (requestHeader->size != sizeof(VMMDevReqHypervisorInfo))
642 {
643 AssertMsgFailed(("VMMDev hypervisor info structure has invalid size!\n"));
644 requestHeader->rc = VERR_INVALID_PARAMETER;
645 }
646 else
647 {
648 VMMDevReqHypervisorInfo *hypervisorInfo = (VMMDevReqHypervisorInfo*)requestHeader;
649 PVM pVM = PDMDevHlpGetVM(pDevIns);
650 size_t hypervisorSize = 0;
651 requestHeader->rc = PGMR3MappingsSize(pVM, &hypervisorSize);
652 hypervisorInfo->hypervisorSize = (uint32_t)hypervisorSize;
653 Assert(hypervisorInfo->hypervisorSize == hypervisorSize);
654 }
655 break;
656 }
657
658 /*
659 * Set hypervisor information
660 */
661 case VMMDevReq_SetHypervisorInfo:
662 {
663 if (requestHeader->size != sizeof(VMMDevReqHypervisorInfo))
664 {
665 AssertMsgFailed(("VMMDev hypervisor info structure has invalid size!\n"));
666 requestHeader->rc = VERR_INVALID_PARAMETER;
667 }
668 else
669 {
670 VMMDevReqHypervisorInfo *hypervisorInfo = (VMMDevReqHypervisorInfo*)requestHeader;
671 PVM pVM = PDMDevHlpGetVM(pDevIns);
672 if (hypervisorInfo->hypervisorStart == 0)
673 {
674 requestHeader->rc = PGMR3MappingsUnfix(pVM);
675 } else
676 {
677 /* only if the client has queried the size before! */
678 size_t mappingsSize;
679 requestHeader->rc = PGMR3MappingsSize(pVM, &mappingsSize);
680 if (VBOX_SUCCESS(requestHeader->rc) && (hypervisorInfo->hypervisorSize == mappingsSize))
681 {
682 /* new reservation */
683 requestHeader->rc = PGMR3MappingsFix(pVM, hypervisorInfo->hypervisorStart,
684 hypervisorInfo->hypervisorSize);
685 LogRel(("Guest reported fixed hypervisor window at 0x%p (size = 0x%x, rc = %Vrc)\n",
686 hypervisorInfo->hypervisorStart,
687 hypervisorInfo->hypervisorSize,
688 requestHeader->rc));
689 }
690 }
691 }
692 break;
693 }
694
695 /*
696 * Set the system power status
697 */
698 case VMMDevReq_SetPowerStatus:
699 {
700 if (requestHeader->size != sizeof(VMMDevPowerStateRequest))
701 {
702 AssertMsgFailed(("VMMDev power state request structure has invalid size!\n"));
703 requestHeader->rc = VERR_INVALID_PARAMETER;
704 }
705 else
706 {
707 VMMDevPowerStateRequest *powerStateRequest = (VMMDevPowerStateRequest*)requestHeader;
708 switch(powerStateRequest->powerState)
709 {
710 case VMMDevPowerState_Pause:
711 {
712 LogRel(("Guest requests the VM to be suspended (paused)\n"));
713 requestHeader->rc = rcRet = PDMDevHlpVMSuspend(pDevIns);
714 break;
715 }
716
717 case VMMDevPowerState_PowerOff:
718 {
719 LogRel(("Guest requests the VM to be turned off\n"));
720 requestHeader->rc = rcRet = PDMDevHlpVMPowerOff(pDevIns);
721 break;
722 }
723
724 case VMMDevPowerState_SaveState:
725 {
726 /** @todo no API for that yet */
727 requestHeader->rc = VERR_NOT_IMPLEMENTED;
728 break;
729 }
730
731 default:
732 AssertMsgFailed(("VMMDev invalid power state request: %d\n", powerStateRequest->powerState));
733 requestHeader->rc = VERR_INVALID_PARAMETER;
734 break;
735 }
736 }
737 break;
738 }
739
740 /*
741 * Get display change request
742 */
743 case VMMDevReq_GetDisplayChangeRequest:
744 {
745 if (requestHeader->size != sizeof(VMMDevDisplayChangeRequest))
746 {
747 /* Assert only if the size also not equal to a previous version size to prevent
748 * assertion with old additions.
749 */
750 AssertMsg(requestHeader->size == sizeof(VMMDevDisplayChangeRequest) - sizeof (uint32_t),
751 ("VMMDev display change request structure has invalid size!\n"));
752 requestHeader->rc = VERR_INVALID_PARAMETER;
753 }
754 else
755 {
756 VMMDevDisplayChangeRequest *displayChangeRequest = (VMMDevDisplayChangeRequest*)requestHeader;
757 /* just pass on the information */
758 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d\n",
759 pData->displayChangeRequest.xres, pData->displayChangeRequest.yres, pData->displayChangeRequest.bpp));
760 displayChangeRequest->xres = pData->displayChangeRequest.xres;
761 displayChangeRequest->yres = pData->displayChangeRequest.yres;
762 displayChangeRequest->bpp = pData->displayChangeRequest.bpp;
763
764 if (displayChangeRequest->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
765 {
766 /* Remember which resolution the client have queried. */
767 pData->lastReadDisplayChangeRequest = pData->displayChangeRequest;
768 }
769
770 requestHeader->rc = VINF_SUCCESS;
771 }
772 break;
773 }
774
775 case VMMDevReq_GetDisplayChangeRequest2:
776 {
777 if (requestHeader->size != sizeof(VMMDevDisplayChangeRequest2))
778 {
779 requestHeader->rc = VERR_INVALID_PARAMETER;
780 }
781 else
782 {
783 VMMDevDisplayChangeRequest2 *displayChangeRequest = (VMMDevDisplayChangeRequest2*)requestHeader;
784 /* just pass on the information */
785 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d at %d\n",
786 pData->displayChangeRequest.xres, pData->displayChangeRequest.yres, pData->displayChangeRequest.bpp, pData->displayChangeRequest.display));
787 displayChangeRequest->xres = pData->displayChangeRequest.xres;
788 displayChangeRequest->yres = pData->displayChangeRequest.yres;
789 displayChangeRequest->bpp = pData->displayChangeRequest.bpp;
790 displayChangeRequest->display = pData->displayChangeRequest.display;
791
792 if (displayChangeRequest->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
793 {
794 /* Remember which resolution the client have queried. */
795 pData->lastReadDisplayChangeRequest = pData->displayChangeRequest;
796 }
797
798 requestHeader->rc = VINF_SUCCESS;
799 }
800 break;
801 }
802
803 /*
804 * Query whether the given video mode is supported
805 */
806 case VMMDevReq_VideoModeSupported:
807 {
808 if (requestHeader->size != sizeof(VMMDevVideoModeSupportedRequest))
809 {
810 AssertMsgFailed(("VMMDev video mode supported request structure has invalid size!\n"));
811 requestHeader->rc = VERR_INVALID_PARAMETER;
812 }
813 else
814 {
815 VMMDevVideoModeSupportedRequest *videoModeSupportedRequest = (VMMDevVideoModeSupportedRequest*)requestHeader;
816 /* forward the call */
817 requestHeader->rc = pData->pDrv->pfnVideoModeSupported(pData->pDrv,
818 videoModeSupportedRequest->width,
819 videoModeSupportedRequest->height,
820 videoModeSupportedRequest->bpp,
821 &videoModeSupportedRequest->fSupported);
822 }
823 break;
824 }
825
826 /*
827 * Query the height reduction in pixels
828 */
829 case VMMDevReq_GetHeightReduction:
830 {
831 if (requestHeader->size != sizeof(VMMDevGetHeightReductionRequest))
832 {
833 AssertMsgFailed(("VMMDev height reduction request structure has invalid size!\n"));
834 requestHeader->rc = VERR_INVALID_PARAMETER;
835 }
836 else
837 {
838 VMMDevGetHeightReductionRequest *heightReductionRequest = (VMMDevGetHeightReductionRequest*)requestHeader;
839 /* forward the call */
840 requestHeader->rc = pData->pDrv->pfnGetHeightReduction(pData->pDrv,
841 &heightReductionRequest->heightReduction);
842 }
843 break;
844 }
845
846 /*
847 * Acknowledge VMMDev events
848 */
849 case VMMDevReq_AcknowledgeEvents:
850 {
851 if (requestHeader->size != sizeof(VMMDevEvents))
852 {
853 AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
854 requestHeader->rc = VERR_INVALID_PARAMETER;
855 }
856 else
857 {
858 if (VBOX_GUEST_ADDITIONS_VERSION_1_03 (pData))
859 {
860 vmmdevSetIRQ_Legacy_EMT (pData);
861 }
862 else
863 {
864 VMMDevEvents *pAckRequest;
865
866 if (pData->fNewGuestFilterMask)
867 {
868 pData->fNewGuestFilterMask = false;
869 pData->u32GuestFilterMask = pData->u32NewGuestFilterMask;
870 }
871
872 pAckRequest = (VMMDevEvents *) requestHeader;
873 pAckRequest->events =
874 pData->u32HostEventFlags & pData->u32GuestFilterMask;
875
876 pData->u32HostEventFlags &= ~pData->u32GuestFilterMask;
877 pData->pVMMDevRAMHC->V.V1_04.fHaveEvents = false;
878 PDMDevHlpPCISetIrqNoWait (pData->pDevIns, 0, 0);
879 }
880 requestHeader->rc = VINF_SUCCESS;
881 }
882 break;
883 }
884
885 /*
886 * Change guest filter mask
887 */
888 case VMMDevReq_CtlGuestFilterMask:
889 {
890 if (requestHeader->size != sizeof(VMMDevCtlGuestFilterMask))
891 {
892 AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
893 requestHeader->rc = VERR_INVALID_PARAMETER;
894 }
895 else
896 {
897 VMMDevCtlGuestFilterMask *pCtlMaskRequest;
898
899 pCtlMaskRequest = (VMMDevCtlGuestFilterMask *) requestHeader;
900 vmmdevCtlGuestFilterMask_EMT (pData,
901 pCtlMaskRequest->u32OrMask,
902 pCtlMaskRequest->u32NotMask);
903 requestHeader->rc = VINF_SUCCESS;
904
905 }
906 break;
907 }
908
909#ifdef VBOX_HGCM
910 /*
911 * Process HGCM request
912 */
913 case VMMDevReq_HGCMConnect:
914 {
915 if (requestHeader->size < sizeof(VMMDevHGCMConnect))
916 {
917 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
918 requestHeader->rc = VERR_INVALID_PARAMETER;
919 }
920 else if (!pData->pHGCMDrv)
921 {
922 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
923 requestHeader->rc = VERR_NOT_SUPPORTED;
924 }
925 else
926 {
927 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)requestHeader;
928
929 Log(("VMMDevReq_HGCMConnect\n"));
930
931 requestHeader->rc = vmmdevHGCMConnect (pData, pHGCMConnect, (RTGCPHYS)u32);
932 }
933 break;
934 }
935
936 case VMMDevReq_HGCMDisconnect:
937 {
938 if (requestHeader->size < sizeof(VMMDevHGCMDisconnect))
939 {
940 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
941 requestHeader->rc = VERR_INVALID_PARAMETER;
942 }
943 else if (!pData->pHGCMDrv)
944 {
945 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
946 requestHeader->rc = VERR_NOT_SUPPORTED;
947 }
948 else
949 {
950 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
951
952 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
953 requestHeader->rc = vmmdevHGCMDisconnect (pData, pHGCMDisconnect, (RTGCPHYS)u32);
954 }
955 break;
956 }
957
958 case VMMDevReq_HGCMCall:
959 {
960 if (requestHeader->size < sizeof(VMMDevHGCMCall))
961 {
962 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
963 requestHeader->rc = VERR_INVALID_PARAMETER;
964 }
965 else if (!pData->pHGCMDrv)
966 {
967 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
968 requestHeader->rc = VERR_NOT_SUPPORTED;
969 }
970 else
971 {
972 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)requestHeader;
973
974 Log(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
975
976 Log(("%.*Vhxd\n", requestHeader->size, requestHeader));
977
978 requestHeader->rc = vmmdevHGCMCall (pData, pHGCMCall, (RTGCPHYS)u32);
979 }
980 break;
981 }
982#endif /* VBOX_HGCM */
983
984 case VMMDevReq_VideoAccelEnable:
985 {
986 if (requestHeader->size < sizeof(VMMDevVideoAccelEnable))
987 {
988 Log(("VMMDevReq_VideoAccelEnable request size too small!!!\n"));
989 requestHeader->rc = VERR_INVALID_PARAMETER;
990 }
991 else if (!pData->pDrv)
992 {
993 Log(("VMMDevReq_VideoAccelEnable Connector is NULL!!!\n"));
994 requestHeader->rc = VERR_NOT_SUPPORTED;
995 }
996 else
997 {
998 VMMDevVideoAccelEnable *ptr = (VMMDevVideoAccelEnable *)requestHeader;
999
1000 if (ptr->cbRingBuffer != VBVA_RING_BUFFER_SIZE)
1001 {
1002 /* The guest driver seems compiled with another headers. */
1003 Log(("VMMDevReq_VideoAccelEnable guest ring buffer size %d, should be %d!!!\n", ptr->cbRingBuffer, VBVA_RING_BUFFER_SIZE));
1004 requestHeader->rc = VERR_INVALID_PARAMETER;
1005 }
1006 else
1007 {
1008 /* The request is correct. */
1009 ptr->fu32Status |= VBVA_F_STATUS_ACCEPTED;
1010
1011 LogFlow(("VMMDevReq_VideoAccelEnable ptr->u32Enable = %d\n", ptr->u32Enable));
1012
1013 requestHeader->rc = ptr->u32Enable?
1014 pData->pDrv->pfnVideoAccelEnable (pData->pDrv, true, &pData->pVMMDevRAMHC->vbvaMemory):
1015 pData->pDrv->pfnVideoAccelEnable (pData->pDrv, false, NULL);
1016
1017 if ( ptr->u32Enable
1018 && VBOX_SUCCESS (requestHeader->rc))
1019 {
1020 ptr->fu32Status |= VBVA_F_STATUS_ENABLED;
1021
1022 /* Remember that guest successfully enabled acceleration.
1023 * We need to reestablish it on restoring the VM from saved state.
1024 */
1025 pData->u32VideoAccelEnabled = 1;
1026 }
1027 else
1028 {
1029 /* The acceleration was not enabled. Remember that. */
1030 pData->u32VideoAccelEnabled = 0;
1031 }
1032 }
1033 }
1034 break;
1035 }
1036
1037 case VMMDevReq_VideoAccelFlush:
1038 {
1039 if (requestHeader->size < sizeof(VMMDevVideoAccelFlush))
1040 {
1041 AssertMsgFailed(("VMMDevReq_VideoAccelFlush request size too small.\n"));
1042 requestHeader->rc = VERR_INVALID_PARAMETER;
1043 }
1044 else if (!pData->pDrv)
1045 {
1046 Log(("VMMDevReq_VideoAccelFlush Connector is NULL!\n"));
1047 requestHeader->rc = VERR_NOT_SUPPORTED;
1048 }
1049 else
1050 {
1051 pData->pDrv->pfnVideoAccelFlush (pData->pDrv);
1052
1053 requestHeader->rc = VINF_SUCCESS;
1054 }
1055 break;
1056 }
1057
1058 case VMMDevReq_QueryCredentials:
1059 {
1060 if (requestHeader->size != sizeof(VMMDevCredentials))
1061 {
1062 AssertMsgFailed(("VMMDevReq_QueryCredentials request size too small.\n"));
1063 requestHeader->rc = VERR_INVALID_PARAMETER;
1064 }
1065 else
1066 {
1067 VMMDevCredentials *credentials = (VMMDevCredentials*)requestHeader;
1068
1069 /* let's start by nulling out the data */
1070 memset(credentials->szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1071 memset(credentials->szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1072 memset(credentials->szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1073
1074 /* should we return whether we got credentials for a logon? */
1075 if (credentials->u32Flags & VMMDEV_CREDENTIALS_QUERYPRESENCE)
1076 {
1077 if ( pData->credentialsLogon.szUserName[0]
1078 || pData->credentialsLogon.szPassword[0]
1079 || pData->credentialsLogon.szDomain[0])
1080 {
1081 credentials->u32Flags |= VMMDEV_CREDENTIALS_PRESENT;
1082 }
1083 else
1084 {
1085 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_PRESENT;
1086 }
1087 }
1088
1089 /* does the guest want to read logon credentials? */
1090 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READ)
1091 {
1092 if (pData->credentialsLogon.szUserName[0])
1093 strcpy(credentials->szUserName, pData->credentialsLogon.szUserName);
1094 if (pData->credentialsLogon.szPassword[0])
1095 strcpy(credentials->szPassword, pData->credentialsLogon.szPassword);
1096 if (pData->credentialsLogon.szDomain[0])
1097 strcpy(credentials->szDomain, pData->credentialsLogon.szDomain);
1098 if (!pData->credentialsLogon.fAllowInteractiveLogon)
1099 credentials->u32Flags |= VMMDEV_CREDENTIALS_NOLOCALLOGON;
1100 else
1101 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_NOLOCALLOGON;
1102 }
1103
1104 /* does the caller want us to destroy the logon credentials? */
1105 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEAR)
1106 {
1107 memset(pData->credentialsLogon.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1108 memset(pData->credentialsLogon.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1109 memset(pData->credentialsLogon.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1110 }
1111
1112 /* does the guest want to read credentials for verification? */
1113 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READJUDGE)
1114 {
1115 if (pData->credentialsJudge.szUserName[0])
1116 strcpy(credentials->szUserName, pData->credentialsJudge.szUserName);
1117 if (pData->credentialsJudge.szPassword[0])
1118 strcpy(credentials->szPassword, pData->credentialsJudge.szPassword);
1119 if (pData->credentialsJudge.szDomain[0])
1120 strcpy(credentials->szDomain, pData->credentialsJudge.szDomain);
1121 }
1122
1123 /* does the caller want us to destroy the judgement credentials? */
1124 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEARJUDGE)
1125 {
1126 memset(pData->credentialsJudge.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1127 memset(pData->credentialsJudge.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1128 memset(pData->credentialsJudge.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1129 }
1130
1131 requestHeader->rc = VINF_SUCCESS;
1132 }
1133 break;
1134 }
1135
1136 case VMMDevReq_ReportCredentialsJudgement:
1137 {
1138 if (requestHeader->size != sizeof(VMMDevCredentials))
1139 {
1140 AssertMsgFailed(("VMMDevReq_ReportCredentialsJudgement request size too small.\n"));
1141 requestHeader->rc = VERR_INVALID_PARAMETER;
1142 }
1143 else
1144 {
1145 VMMDevCredentials *credentials = (VMMDevCredentials*)requestHeader;
1146
1147 /* what does the guest think about the credentials? (note: the order is important here!) */
1148 if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_DENY)
1149 {
1150 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_DENY);
1151 }
1152 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT)
1153 {
1154 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT);
1155 }
1156 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_OK)
1157 {
1158 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_OK);
1159 }
1160 else
1161 Log(("VMMDevReq_ReportCredentialsJudgement: invalid flags: %d!!!\n", credentials->u32Flags));
1162
1163 requestHeader->rc = VINF_SUCCESS;
1164 }
1165 break;
1166 }
1167
1168 default:
1169 {
1170 requestHeader->rc = VERR_NOT_IMPLEMENTED;
1171
1172 Log(("VMMDev unknown request type %d\n", requestHeader->requestType));
1173
1174 break;
1175 }
1176 }
1177
1178 return rcRet;
1179}
1180
1181/**
1182 * Callback function for mapping an PCI I/O region.
1183 *
1184 * @return VBox status code.
1185 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1186 * @param iRegion The region number.
1187 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1188 * I/O port, else it's a physical address.
1189 * This address is *NOT* relative to pci_mem_base like earlier!
1190 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1191 */
1192static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1193{
1194 int rc;
1195 VMMDevState *pData = PCIDEV_2_VMMDEVSTATE(pPciDev);
1196 LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%VGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
1197
1198
1199 Assert(pData->pVMMDevRAMHC != NULL);
1200
1201 memset (pData->pVMMDevRAMHC, 0, sizeof (VMMDevMemory));
1202 pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
1203 pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
1204
1205 /*
1206 * VMMDev RAM mapping.
1207 */
1208 if (iRegion == 1 && enmType == PCI_ADDRESS_SPACE_MEM)
1209 {
1210 /*
1211 * Register and lock the RAM.
1212 *
1213 * Windows usually re-initializes the PCI devices, so we have to check whether the memory was
1214 * already registered before trying to do that all over again.
1215 */
1216 PVM pVM = PDMDevHlpGetVM(pPciDev->pDevIns);
1217
1218 if (pData->GCPhysVMMDevRAM)
1219 {
1220 /*
1221 * Relocate the already registered VMMDevRAM.
1222 */
1223 rc = MMR3PhysRelocate(pVM, pData->GCPhysVMMDevRAM, GCPhysAddress, VMMDEV_RAM_SIZE);
1224 if (VBOX_SUCCESS(rc))
1225 {
1226 pData->GCPhysVMMDevRAM = GCPhysAddress;
1227 return VINF_SUCCESS;
1228 }
1229 AssertReleaseMsgFailed(("Failed to relocate VMMDev RAM from %VGp to %VGp! rc=%Vra\n", pData->GCPhysVMMDevRAM, GCPhysAddress, rc));
1230 }
1231 else
1232 {
1233 /*
1234 * Register and lock the VMMDevRAM.
1235 */
1236 /** @todo MM_RAM_FLAGS_MMIO2 seems to be appropriate for a RW memory.
1237 * Need to check. May be a RO memory is enough for the device.
1238 */
1239 rc = MMR3PhysRegister(pVM, pData->pVMMDevRAMHC, GCPhysAddress, VMMDEV_RAM_SIZE, MM_RAM_FLAGS_MMIO2, "VBoxDev");
1240 if (VBOX_SUCCESS(rc))
1241 {
1242 pData->GCPhysVMMDevRAM = GCPhysAddress;
1243 return VINF_SUCCESS;
1244 }
1245 AssertReleaseMsgFailed(("Failed to register VMMDev RAM! rc=%Vra\n", rc));
1246 }
1247 return rc;
1248 }
1249
1250 AssertReleaseMsgFailed(("VMMDev wrong region type: iRegion=%d enmType=%d\n", iRegion, enmType));
1251 return VERR_INTERNAL_ERROR;
1252}
1253
1254
1255/**
1256 * Callback function for mapping a PCI I/O region.
1257 *
1258 * @return VBox status code.
1259 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1260 * @param iRegion The region number.
1261 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1262 * I/O port, else it's a physical address.
1263 * This address is *NOT* relative to pci_mem_base like earlier!
1264 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1265 */
1266static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1267{
1268 VMMDevState *pData = PCIDEV_2_VMMDEVSTATE(pPciDev);
1269 int rc = VINF_SUCCESS;
1270
1271 Assert(enmType == PCI_ADDRESS_SPACE_IO);
1272 Assert(iRegion == 0);
1273 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
1274
1275 /*
1276 * Save the base port address to simplify Port offset calculations.
1277 */
1278 pData->PortBase = (RTIOPORT)GCPhysAddress;
1279
1280 /*
1281 * Register our port IO handlers.
1282 */
1283 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns,
1284 (RTIOPORT)GCPhysAddress + PORT_VMMDEV_REQUEST_OFFSET, 1,
1285 (void*)pData, vmmdevRequestHandler,
1286 NULL, NULL, NULL, "VMMDev Request Handler");
1287 AssertRC(rc);
1288 return rc;
1289}
1290
1291/**
1292 * Queries an interface to the driver.
1293 *
1294 * @returns Pointer to interface.
1295 * @returns NULL if the interface was not supported by the driver.
1296 * @param pInterface Pointer to this interface structure.
1297 * @param enmInterface The requested interface identification.
1298 * @thread Any thread.
1299 */
1300static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
1301{
1302 VMMDevState *pData = (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, Base));
1303 switch (enmInterface)
1304 {
1305 case PDMINTERFACE_BASE:
1306 return &pData->Base;
1307 case PDMINTERFACE_VMMDEV_PORT:
1308 return &pData->Port;
1309#ifdef VBOX_HGCM
1310 case PDMINTERFACE_HGCM_PORT:
1311 return &pData->HGCMPort;
1312#endif
1313 default:
1314 return NULL;
1315 }
1316}
1317
1318/* -=-=-=-=-=- IVMMDevPort -=-=-=-=-=- */
1319
1320/** Converts a VMMDev port interface pointer to a VMMDev state pointer. */
1321#define IVMMDEVPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, Port)) )
1322
1323
1324/**
1325 * Return the current absolute mouse position in pixels
1326 *
1327 * @returns VBox status code
1328 * @param pAbsX Pointer of result value, can be NULL
1329 * @param pAbsY Pointer of result value, can be NULL
1330 */
1331static DECLCALLBACK(int) vmmdevQueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t *pAbsX, uint32_t *pAbsY)
1332{
1333 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1334 if (pAbsX)
1335 *pAbsX = pData->mouseXAbs;
1336 if (pAbsY)
1337 *pAbsY = pData->mouseYAbs;
1338 return VINF_SUCCESS;
1339}
1340
1341/**
1342 * Set the new absolute mouse position in pixels
1343 *
1344 * @returns VBox status code
1345 * @param absX New absolute X position
1346 * @param absY New absolute Y position
1347 */
1348static DECLCALLBACK(int) vmmdevSetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t absX, uint32_t absY)
1349{
1350 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1351 Log(("vmmdevSetAbsoluteMouse: settings absolute position to x = %d, y = %d\n", absX, absY));
1352 pData->mouseXAbs = absX;
1353 pData->mouseYAbs = absY;
1354 return VINF_SUCCESS;
1355}
1356
1357/**
1358 * Return the current mouse capability flags
1359 *
1360 * @returns VBox status code
1361 * @param pCapabilities Pointer of result value
1362 */
1363static DECLCALLBACK(int) vmmdevQueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pCapabilities)
1364{
1365 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1366 if (!pCapabilities)
1367 return VERR_INVALID_PARAMETER;
1368 *pCapabilities = pData->mouseCapabilities;
1369 return VINF_SUCCESS;
1370}
1371
1372/**
1373 * Set the current mouse capability flag (host side)
1374 *
1375 * @returns VBox status code
1376 * @param capabilities Capability mask
1377 */
1378static DECLCALLBACK(int) vmmdevSetMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t capabilities)
1379{
1380 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1381
1382 bool bCapsChanged = ((capabilities & VMMDEV_MOUSEHOSTWANTSABS)
1383 != (pData->mouseCapabilities & VMMDEV_MOUSEHOSTWANTSABS));
1384
1385 Log(("vmmdevSetMouseCapabilities: bCapsChanged %d\n", bCapsChanged));
1386
1387 if (capabilities & VMMDEV_MOUSEHOSTCANNOTHWPOINTER)
1388 pData->mouseCapabilities |= VMMDEV_MOUSEHOSTCANNOTHWPOINTER;
1389 else
1390 pData->mouseCapabilities &= ~VMMDEV_MOUSEHOSTCANNOTHWPOINTER;
1391
1392 if (capabilities & VMMDEV_MOUSEHOSTWANTSABS)
1393 pData->mouseCapabilities |= VMMDEV_MOUSEHOSTWANTSABS;
1394 else
1395 pData->mouseCapabilities &= ~VMMDEV_MOUSEHOSTWANTSABS;
1396
1397 if (bCapsChanged)
1398 VMMDevNotifyGuest (pData, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
1399
1400 return VINF_SUCCESS;
1401}
1402
1403
1404static DECLCALLBACK(int) vmmdevRequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t xres, uint32_t yres, uint32_t bpp, uint32_t display)
1405{
1406 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1407
1408 /* Verify that the new resolution is different and that guest does not yet know about it. */
1409 bool fSameResolution = (!xres || (pData->lastReadDisplayChangeRequest.xres == xres)) &&
1410 (!yres || (pData->lastReadDisplayChangeRequest.yres == yres)) &&
1411 (!bpp || (pData->lastReadDisplayChangeRequest.bpp == bpp)) &&
1412 pData->lastReadDisplayChangeRequest.display == display;
1413
1414 if (!xres && !yres && !bpp)
1415 {
1416 /* Special case of reset video mode. */
1417 fSameResolution = false;
1418 }
1419
1420#ifdef DEBUG_sunlover
1421 Log(("vmmdevRequestDisplayChange: same=%d. new: xres=%d, yres=%d, bpp=%d, display=%d. old: xres=%d, yres=%d, bpp=%d, display=%d.\n",
1422 fSameResolution, xres, yres, bpp, display, pData->lastReadDisplayChangeRequest.xres, pData->lastReadDisplayChangeRequest.yres, pData->lastReadDisplayChangeRequest.bpp, pData->lastReadDisplayChangeRequest.display));
1423#endif /* DEBUG_sunlover */
1424
1425 if (!fSameResolution)
1426 {
1427 LogRel(("VMMDev::SetVideoModeHint: got a video mode hint (%dx%dx%d) at %d\n",
1428 xres, yres, bpp, display));
1429
1430 /* we could validate the information here but hey, the guest can do that as well! */
1431 pData->displayChangeRequest.xres = xres;
1432 pData->displayChangeRequest.yres = yres;
1433 pData->displayChangeRequest.bpp = bpp;
1434 pData->displayChangeRequest.display = display;
1435
1436 /* IRQ so the guest knows what's going on */
1437 VMMDevNotifyGuest (pData, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
1438 }
1439
1440 return VINF_SUCCESS;
1441}
1442
1443static DECLCALLBACK(int) vmmdevSetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
1444 const char *pszPassword, const char *pszDomain,
1445 uint32_t u32Flags)
1446{
1447 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1448
1449 /* logon mode? */
1450 if (u32Flags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
1451 {
1452 /* memorize the data */
1453 strcpy(pData->credentialsLogon.szUserName, pszUsername);
1454 strcpy(pData->credentialsLogon.szPassword, pszPassword);
1455 strcpy(pData->credentialsLogon.szDomain, pszDomain);
1456 pData->credentialsLogon.fAllowInteractiveLogon = !(u32Flags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
1457 }
1458 /* credentials verification mode? */
1459 else if (u32Flags & VMMDEV_SETCREDENTIALS_JUDGE)
1460 {
1461 /* memorize the data */
1462 strcpy(pData->credentialsJudge.szUserName, pszUsername);
1463 strcpy(pData->credentialsJudge.szPassword, pszPassword);
1464 strcpy(pData->credentialsJudge.szDomain, pszDomain);
1465
1466 VMMDevNotifyGuest (pData, VMMDEV_EVENT_JUDGE_CREDENTIALS);
1467 }
1468 else
1469 return VERR_INVALID_PARAMETER;
1470
1471 return VINF_SUCCESS;
1472}
1473
1474/**
1475 * Notification from the Display. Especially useful when
1476 * acceleration is disabled after a video mode change.
1477 *
1478 * @param fEnable Current acceleration status.
1479 */
1480static DECLCALLBACK(void) vmmdevVBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
1481{
1482 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1483
1484 Log(("vmmdevVBVAChange: fEnabled = %d\n", fEnabled));
1485
1486 if (pData)
1487 {
1488 pData->u32VideoAccelEnabled = fEnabled;
1489 }
1490
1491 return;
1492}
1493
1494
1495/* -=-=-=-=-=- IHGCMPort -=-=-=-=-=- */
1496
1497/** Converts a VMMDev port interface pointer to a VMMDev state pointer. */
1498#define IHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, HGCMPort)) )
1499
1500
1501
1502#define VMMDEV_SSM_VERSION 3
1503
1504/**
1505 * Saves a state of the VMM device.
1506 *
1507 * @returns VBox status code.
1508 * @param pDevIns The device instance.
1509 * @param pSSMHandle The handle to save the state to.
1510 */
1511static DECLCALLBACK(int) vmmdevSaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1512{
1513 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
1514 SSMR3PutU32(pSSMHandle, pData->hypervisorSize);
1515 SSMR3PutU32(pSSMHandle, pData->mouseCapabilities);
1516 SSMR3PutU32(pSSMHandle, pData->mouseXAbs);
1517 SSMR3PutU32(pSSMHandle, pData->mouseYAbs);
1518
1519 SSMR3PutBool(pSSMHandle, pData->fNewGuestFilterMask);
1520 SSMR3PutU32(pSSMHandle, pData->u32NewGuestFilterMask);
1521 SSMR3PutU32(pSSMHandle, pData->u32GuestFilterMask);
1522 SSMR3PutU32(pSSMHandle, pData->u32HostEventFlags);
1523 // here be dragons (probably)
1524// SSMR3PutBool(pSSMHandle, pData->pVMMDevRAMHC->V.V1_04.fHaveEvents);
1525 SSMR3PutMem(pSSMHandle, &pData->pVMMDevRAMHC->V, sizeof (pData->pVMMDevRAMHC->V));
1526
1527 SSMR3PutMem(pSSMHandle, &pData->guestInfo, sizeof (pData->guestInfo));
1528 SSMR3PutU32(pSSMHandle, pData->fu32AdditionsOk);
1529 SSMR3PutU32(pSSMHandle, pData->u32VideoAccelEnabled);
1530
1531#ifdef VBOX_HGCM
1532 vmmdevHGCMSaveState (pData, pSSMHandle);
1533#endif /* VBOX_HGCM */
1534
1535 return VINF_SUCCESS;
1536}
1537
1538/**
1539 * Loads the saved VMM device state.
1540 *
1541 * @returns VBox status code.
1542 * @param pDevIns The device instance.
1543 * @param pSSMHandle The handle to the saved state.
1544 * @param u32Version The data unit version number.
1545 */
1546static DECLCALLBACK(int) vmmdevLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
1547{
1548 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
1549 if (u32Version != VMMDEV_SSM_VERSION)
1550 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1551 SSMR3GetU32(pSSMHandle, &pData->hypervisorSize);
1552 SSMR3GetU32(pSSMHandle, &pData->mouseCapabilities);
1553 SSMR3GetU32(pSSMHandle, &pData->mouseXAbs);
1554 SSMR3GetU32(pSSMHandle, &pData->mouseYAbs);
1555
1556 SSMR3GetBool(pSSMHandle, &pData->fNewGuestFilterMask);
1557 SSMR3GetU32(pSSMHandle, &pData->u32NewGuestFilterMask);
1558 SSMR3GetU32(pSSMHandle, &pData->u32GuestFilterMask);
1559 SSMR3GetU32(pSSMHandle, &pData->u32HostEventFlags);
1560// SSMR3GetBool(pSSMHandle, &pData->pVMMDevRAMHC->fHaveEvents);
1561 // here be dragons (probably)
1562 SSMR3GetMem(pSSMHandle, &pData->pVMMDevRAMHC->V, sizeof (pData->pVMMDevRAMHC->V));
1563
1564 SSMR3GetMem(pSSMHandle, &pData->guestInfo, sizeof (pData->guestInfo));
1565 SSMR3GetU32(pSSMHandle, &pData->fu32AdditionsOk);
1566 SSMR3GetU32(pSSMHandle, &pData->u32VideoAccelEnabled);
1567
1568#ifdef VBOX_HGCM
1569 vmmdevHGCMLoadState (pData, pSSMHandle);
1570#endif /* VBOX_HGCM */
1571
1572 /*
1573 * On a resume, we send the capabilities changed message so
1574 * that listeners can sync their state again
1575 */
1576 Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
1577 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
1578
1579 /* Reestablish the acceleration status. */
1580 if (pData->u32VideoAccelEnabled)
1581 {
1582 pData->pDrv->pfnVideoAccelEnable (pData->pDrv, !!pData->u32VideoAccelEnabled, &pData->pVMMDevRAMHC->vbvaMemory);
1583 }
1584
1585 return VINF_SUCCESS;
1586}
1587
1588/**
1589 * Load state done callback. Notify guest of restore event.
1590 *
1591 * @returns VBox status code.
1592 * @param pDevIns The device instance.
1593 * @param pSSMHandle The handle to the saved state.
1594 */
1595static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1596{
1597 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
1598
1599#ifdef VBOX_HGCM
1600 vmmdevHGCMLoadStateDone (pData, pSSMHandle);
1601#endif /* VBOX_HGCM */
1602
1603 VMMDevNotifyGuest (pData, VMMDEV_EVENT_RESTORED);
1604
1605 return VINF_SUCCESS;
1606}
1607
1608/**
1609 * Construct a device instance for a VM.
1610 *
1611 * @returns VBox status.
1612 * @param pDevIns The device instance data.
1613 * If the registration structure is needed, pDevIns->pDevReg points to it.
1614 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1615 * The device number is also found in pDevIns->iInstance, but since it's
1616 * likely to be freqently used PDM passes it as parameter.
1617 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1618 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1619 * iInstance it's expected to be used a bit in this function.
1620 */
1621static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1622{
1623 int rc;
1624 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
1625
1626 Assert(iInstance == 0);
1627
1628 /*
1629 * Validate and read the configuration.
1630 */
1631 if (!CFGMR3AreValuesValid(pCfgHandle, "GetHostTimeDisabled\0BackdoorLogDisabled\0"))
1632 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1633
1634 rc = CFGMR3QueryBool(pCfgHandle, "GetHostTimeDisabled", &pData->fGetHostTimeDisabled);
1635 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1636 pData->fGetHostTimeDisabled = false;
1637 else if (VBOX_FAILURE(rc))
1638 return PDMDEV_SET_ERROR(pDevIns, rc,
1639 N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
1640
1641 rc = CFGMR3QueryBool(pCfgHandle, "BackdoorLogDisabled", &pData->fBackdoorLogDisabled);
1642 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1643 pData->fBackdoorLogDisabled = false;
1644 else if (VBOX_FAILURE(rc))
1645 return PDMDEV_SET_ERROR(pDevIns, rc,
1646 N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
1647
1648 /*
1649 * Initialize data (most of it anyway).
1650 */
1651 /* Save PDM device instance data for future reference. */
1652 pData->pDevIns = pDevIns;
1653
1654 /* PCI vendor, just a free bogus value */
1655 pData->dev.config[0x00] = 0xee;
1656 pData->dev.config[0x01] = 0x80;
1657 /* device ID */
1658 pData->dev.config[0x02] = 0xfe;
1659 pData->dev.config[0x03] = 0xca;
1660 /* class sub code (other type of system peripheral) */
1661 pData->dev.config[0x0a] = 0x80;
1662 /* class base code (base system peripheral) */
1663 pData->dev.config[0x0b] = 0x08;
1664 /* header type */
1665 pData->dev.config[0x0e] = 0x00;
1666 /* interrupt on pin 0 */
1667 pData->dev.config[0x3d] = 0x01;
1668
1669 /*
1670 * Register the backdoor logging port
1671 */
1672 rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog, NULL, NULL, NULL, "VMMDev backdoor logging");
1673 AssertRCReturn(rc, rc);
1674
1675#ifdef TIMESYNC_BACKDOOR
1676 /*
1677 * Alternative timesync source (temporary!)
1678 */
1679 rc = PDMDevHlpIOPortRegister(pDevIns, 0x505, 1, NULL, vmmdevTimesyncBackdoorWrite, vmmdevTimesyncBackdoorRead, NULL, NULL, "VMMDev timesync backdoor");
1680 AssertRCReturn(rc, rc);
1681#endif
1682
1683 /*
1684 * Register the PCI device.
1685 */
1686 rc = PDMDevHlpPCIRegister(pDevIns, &pData->dev);
1687 if (VBOX_FAILURE(rc))
1688 return rc;
1689 if (pData->dev.devfn == 32 || iInstance != 0)
1690 Log(("!!WARNING!!: pData->dev.devfn=%d (ignore if testcase or no started by Main)\n", pData->dev.devfn));
1691 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
1692 if (VBOX_FAILURE(rc))
1693 return rc;
1694 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, vmmdevIORAMRegionMap);
1695 if (VBOX_FAILURE(rc))
1696 return rc;
1697
1698 /*
1699 * Interfaces
1700 */
1701 /* Base */
1702 pData->Base.pfnQueryInterface = vmmdevPortQueryInterface;
1703
1704 /* VMMDev port */
1705 pData->Port.pfnQueryAbsoluteMouse = vmmdevQueryAbsoluteMouse;
1706 pData->Port.pfnSetAbsoluteMouse = vmmdevSetAbsoluteMouse;
1707 pData->Port.pfnQueryMouseCapabilities = vmmdevQueryMouseCapabilities;
1708 pData->Port.pfnSetMouseCapabilities = vmmdevSetMouseCapabilities;
1709 pData->Port.pfnRequestDisplayChange = vmmdevRequestDisplayChange;
1710 pData->Port.pfnSetCredentials = vmmdevSetCredentials;
1711 pData->Port.pfnVBVAChange = vmmdevVBVAChange;
1712
1713
1714#ifdef VBOX_HGCM
1715 /* HGCM port */
1716 pData->HGCMPort.pfnCompleted = hgcmCompleted;
1717#endif
1718
1719 /*
1720 * Get the corresponding connector interface
1721 */
1722 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->Base, &pData->pDrvBase, "VMM Driver Port");
1723 if (VBOX_SUCCESS(rc))
1724 {
1725 pData->pDrv = (PPDMIVMMDEVCONNECTOR)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_VMMDEV_CONNECTOR);
1726 if (!pData->pDrv)
1727 AssertMsgFailedReturn(("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
1728#ifdef VBOX_HGCM
1729 pData->pHGCMDrv = (PPDMIHGCMCONNECTOR)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_HGCM_CONNECTOR);
1730 if (!pData->pHGCMDrv)
1731 {
1732 Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Vrc\n", rc));
1733 /* this is not actually an error, just means that there is no support for HGCM */
1734 }
1735#endif
1736 }
1737 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
1738 {
1739 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
1740 rc = VINF_SUCCESS;
1741 }
1742 else
1743 AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Vrc\n", rc), rc);
1744
1745 /*
1746 * Register saved state and init the HGCM CmdList critsect.
1747 */
1748 rc = PDMDevHlpSSMRegister(pDevIns, "VMMDev", iInstance, VMMDEV_SSM_VERSION, sizeof(*pData),
1749 NULL, vmmdevSaveState, NULL,
1750 NULL, vmmdevLoadState, vmmdevLoadStateDone);
1751 AssertRCReturn(rc, rc);
1752
1753#ifdef VBOX_HGCM
1754 rc = RTCritSectInit(&pData->critsectHGCMCmdList);
1755 AssertRCReturn(rc, rc);
1756#endif /* VBOX_HGCM */
1757
1758 /*
1759 * Allocate the VMMDev RAM region.
1760 */
1761 /** @todo freeing of the RAM. */
1762 rc = SUPPageAlloc(VMMDEV_RAM_SIZE >> PAGE_SHIFT, (void **)&pData->pVMMDevRAMHC);
1763 AssertMsgRCReturn(rc, ("VMMDev SUPPageAlloc(%#x,) -> %Vrc\n", VMMDEV_RAM_SIZE, rc), rc);
1764
1765 /* initialize the VMMDev memory */
1766 pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
1767 pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
1768
1769 return rc;
1770}
1771
1772/**
1773 * Reset notification.
1774 *
1775 * @returns VBox status.
1776 * @param pDrvIns The driver instance data.
1777 */
1778static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
1779{
1780 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
1781 /*
1782 * Reset the mouse integration feature bit
1783 */
1784 if (pData->mouseCapabilities & (VMMDEV_MOUSEGUESTWANTSABS|VMMDEV_MOUSEGUESTNEEDSHOSTCUR))
1785 {
1786 pData->mouseCapabilities &= ~VMMDEV_MOUSEGUESTWANTSABS;
1787 /* notify the connector */
1788 Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
1789 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
1790 }
1791
1792 pData->hypervisorSize = 0;
1793
1794 pData->u32HostEventFlags = 0;
1795
1796 if (pData->pVMMDevRAMHC)
1797 {
1798 /* re-initialize the VMMDev memory */
1799 memset (pData->pVMMDevRAMHC, 0, VMMDEV_RAM_SIZE);
1800 pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
1801 pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
1802 }
1803
1804 /* credentials have to go away */
1805 memset(pData->credentialsLogon.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1806 memset(pData->credentialsLogon.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1807 memset(pData->credentialsLogon.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1808 memset(pData->credentialsJudge.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1809 memset(pData->credentialsJudge.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1810 memset(pData->credentialsJudge.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1811
1812 /* Reset means that additions will report again. */
1813 pData->fu32AdditionsOk = false;
1814 memset (&pData->guestInfo, 0, sizeof (pData->guestInfo));
1815
1816 memset (&pData->lastReadDisplayChangeRequest, 0, sizeof (pData->lastReadDisplayChangeRequest));
1817
1818 /* Clear the event variables.
1819 *
1820 * Note: The pData->u32HostEventFlags is not cleared.
1821 * It is designed that way so host events do not
1822 * depend on guest resets.
1823 */
1824 pData->u32GuestFilterMask = 0;
1825 pData->u32NewGuestFilterMask = 0;
1826 pData->fNewGuestFilterMask = 0;
1827}
1828
1829
1830/**
1831 * The device registration structure.
1832 */
1833extern "C" const PDMDEVREG g_DeviceVMMDev =
1834{
1835 /* u32Version */
1836 PDM_DEVREG_VERSION,
1837 /* szDeviceName */
1838 "VMMDev",
1839 /* szGCMod */
1840 "",
1841 /* szR0Mod */
1842 "",
1843 /* pszDescription */
1844 "VirtualBox VMM Device\n",
1845 /* fFlags */
1846 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32,
1847 /* fClass */
1848 PDM_DEVREG_CLASS_VMM_DEV,
1849 /* cMaxInstances */
1850 1,
1851 /* cbInstance */
1852 sizeof(VMMDevState),
1853 /* pfnConstruct */
1854 vmmdevConstruct,
1855 /* pfnDestruct */
1856 NULL,
1857 /* pfnRelocate */
1858 NULL,
1859 /* pfnIOCtl */
1860 NULL,
1861 /* pfnPowerOn */
1862 NULL,
1863 /* pfnReset */
1864 vmmdevReset,
1865 /* pfnSuspend */
1866 NULL,
1867 /* pfnResume */
1868 NULL,
1869 /* pfnAttach */
1870 NULL,
1871 /* pfnDetach */
1872 NULL,
1873 /* pfnQueryInterface. */
1874 NULL
1875};
1876#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
1877
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette