VirtualBox

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

Last change on this file since 5025 was 4915, checked in by vboxsync, 17 years ago

warning

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 88.5 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
19/* #define LOG_ENABLED */
20
21#include <stdio.h>
22#include <string.h>
23
24#define LOG_GROUP LOG_GROUP_DEV_VMM
25#include <VBox/log.h>
26
27#include <VBox/VBoxDev.h>
28#include <VBox/VBoxGuest.h>
29#include <VBox/param.h>
30#include <VBox/mm.h>
31#include <VBox/pgm.h>
32#include <VBox/err.h>
33#include <VBox/vm.h> /* for VM_IS_EMT */
34
35#include <iprt/assert.h>
36#include <iprt/time.h>
37
38#include "VMMDevState.h"
39
40#ifdef VBOX_HGCM
41#include "VMMDevHGCM.h"
42#endif
43
44#define PCIDEV_2_VMMDEVSTATE(pPciDev) ( (VMMDevState *)(pPciDev) )
45#define VMMDEVSTATE_2_DEVINS(pVMMDevState) ( (pVMMDevState)->pDevIns )
46
47#define VBOX_GUEST_ADDITIONS_VERSION_1_03(s) \
48 ((RT_HIWORD ((s)->guestInfo.additionsVersion) == 1) && \
49 (RT_LOWORD ((s)->guestInfo.additionsVersion) == 3))
50
51#define VBOX_GUEST_ADDITIONS_VERSION_OK(additionsVersion) \
52 (RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
53 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION))
54
55#define VBOX_GUEST_ADDITIONS_VERSION_OLD(additionsVersion) \
56 ((RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) \
57 || ((RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
58 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION))
59
60#define VBOX_GUEST_ADDITIONS_VERSION_TOO_OLD(additionsVersion) \
61 (RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION))
62
63#define VBOX_GUEST_ADDITIONS_VERSION_NEW(additionsVersion) \
64 ((RT_HIWORD(additionsVersion) > RT_HIWORD(VMMDEV_VERSION) \
65 || ((RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
66 && RT_LOWORD(additionsVersion) > RT_LOWORD(VMMDEV_VERSION))
67
68#ifndef VBOX_DEVICE_STRUCT_TESTCASE
69
70/* Whenever host wants to inform guest about something
71 * an IRQ notification will be raised.
72 *
73 * VMMDev PDM interface will contain the guest notification method.
74 *
75 * There is a 32 bit event mask which will be read
76 * by guest on an interrupt. A non zero bit in the mask
77 * means that the specific event occured and requires
78 * processing on guest side.
79 *
80 * After reading the event mask guest must issue a
81 * generic request AcknowlegdeEvents.
82 *
83 * IRQ line is set to 1 (request) if there are unprocessed
84 * events, that is the event mask is not zero.
85 *
86 * After receiving an interrupt and checking event mask,
87 * the guest must process events using the event specific
88 * mechanism.
89 *
90 * That is if mouse capabilities were changed,
91 * guest will use VMMDev_GetMouseStatus generic request.
92 *
93 * Event mask is only a set of flags indicating that guest
94 * must proceed with a procedure.
95 *
96 * Unsupported events are therefore ignored.
97 * The guest additions must inform host which events they
98 * want to receive, to avoid unnecessary IRQ processing.
99 * By default no events are signalled to guest.
100 *
101 * This seems to be fast method. It requires
102 * only one context switch for an event processing.
103 *
104 */
105
106static void vmmdevSetIRQ_Legacy_EMT (VMMDevState *pVMMDevState)
107{
108 if (!pVMMDevState->fu32AdditionsOk)
109 {
110 Log(("vmmdevSetIRQ: IRQ is not generated, guest has not yet reported to us.\n"));
111 return;
112 }
113
114 uint32_t u32IRQLevel = 0;
115
116 /* Filter unsupported events */
117 uint32_t u32EventFlags =
118 pVMMDevState->u32HostEventFlags
119 & pVMMDevState->pVMMDevRAMHC->V.V1_03.u32GuestEventMask;
120
121 Log(("vmmdevSetIRQ: u32EventFlags = 0x%08X, "
122 "pVMMDevState->u32HostEventFlags = 0x%08X, "
123 "pVMMDevState->pVMMDevRAMHC->u32GuestEventMask = 0x%08X\n",
124 u32EventFlags,
125 pVMMDevState->u32HostEventFlags,
126 pVMMDevState->pVMMDevRAMHC->V.V1_03.u32GuestEventMask));
127
128 /* Move event flags to VMMDev RAM */
129 pVMMDevState->pVMMDevRAMHC->V.V1_03.u32HostEvents = u32EventFlags;
130
131 if (u32EventFlags)
132 {
133 /* Clear host flags which will be delivered to guest. */
134 pVMMDevState->u32HostEventFlags &= ~u32EventFlags;
135 Log(("vmmdevSetIRQ: pVMMDevState->u32HostEventFlags = 0x%08X\n",
136 pVMMDevState->u32HostEventFlags));
137 u32IRQLevel = 1;
138 }
139
140 /* Set IRQ level for pin 0 */
141 /** @todo make IRQ pin configurable, at least a symbolic constant */
142 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
143 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, u32IRQLevel);
144 Log(("vmmdevSetIRQ: IRQ set %d\n", u32IRQLevel));
145}
146
147static void vmmdevMaybeSetIRQ_EMT (VMMDevState *pVMMDevState)
148{
149 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS (pVMMDevState);
150
151#ifdef DEBUG_sunlover
152 Log(("vmmdevMaybeSetIRQ_EMT: u32HostEventFlags = 0x%08X, u32GuestFilterMask = 0x%08X.\n",
153 pVMMDevState->u32HostEventFlags, pVMMDevState->u32GuestFilterMask));
154#endif /* DEBUG_sunlover */
155
156 if (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask)
157 {
158 pVMMDevState->pVMMDevRAMHC->V.V1_04.fHaveEvents = true;
159 PDMDevHlpPCISetIrqNoWait (pDevIns, 0, 1);
160#ifdef DEBUG_sunlover
161 Log(("vmmdevMaybeSetIRQ_EMT: IRQ set.\n"));
162#endif /* DEBUG_sunlover */
163 }
164}
165
166static void vmmdevNotifyGuest_EMT (VMMDevState *pVMMDevState, uint32_t u32EventMask)
167{
168#ifdef DEBUG_sunlover
169 Log(("VMMDevNotifyGuest_EMT: u32EventMask = 0x%08X.\n", u32EventMask));
170#endif /* DEBUG_sunlover */
171
172 if (VBOX_GUEST_ADDITIONS_VERSION_1_03 (pVMMDevState))
173 {
174#ifdef DEBUG_sunlover
175 Log(("VMMDevNotifyGuest_EMT: Old additions detected.\n"));
176#endif /* DEBUG_sunlover */
177
178 pVMMDevState->u32HostEventFlags |= u32EventMask;
179 vmmdevSetIRQ_Legacy_EMT (pVMMDevState);
180 }
181 else
182 {
183#ifdef DEBUG_sunlover
184 Log(("VMMDevNotifyGuest_EMT: New additions detected.\n"));
185#endif /* DEBUG_sunlover */
186
187 if (!pVMMDevState->fu32AdditionsOk)
188 {
189 pVMMDevState->u32HostEventFlags |= u32EventMask;
190 Log(("vmmdevNotifyGuest_EMT: IRQ is not generated, guest has not yet reported to us.\n"));
191 return;
192 }
193
194 const bool fHadEvents =
195 (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask) != 0;
196
197#ifdef DEBUG_sunlover
198 Log(("VMMDevNotifyGuest_EMT: fHadEvents = %d, u32HostEventFlags = 0x%08X, u32GuestFilterMask = 0x%08X.\n",
199 fHadEvents, pVMMDevState->u32HostEventFlags, pVMMDevState->u32GuestFilterMask));
200#endif /* DEBUG_sunlover */
201
202 pVMMDevState->u32HostEventFlags |= u32EventMask;
203
204 if (!fHadEvents)
205 vmmdevMaybeSetIRQ_EMT (pVMMDevState);
206 }
207}
208
209static void vmmdevCtlGuestFilterMask_EMT (VMMDevState *pVMMDevState,
210 uint32_t u32OrMask,
211 uint32_t u32NotMask)
212{
213 const bool fHadEvents =
214 (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask) != 0;
215
216 Log(("vmmdevCtlGuestFilterMask_EMT: u32OrMask = 0x%08X, u32NotMask = 0x%08X, fHadEvents = %d.\n", u32OrMask, u32NotMask, fHadEvents));
217 if (fHadEvents)
218 {
219 if (!pVMMDevState->fNewGuestFilterMask)
220 pVMMDevState->u32NewGuestFilterMask = pVMMDevState->u32GuestFilterMask;
221
222 pVMMDevState->u32NewGuestFilterMask |= u32OrMask;
223 pVMMDevState->u32NewGuestFilterMask &= ~u32NotMask;
224 pVMMDevState->fNewGuestFilterMask = true;
225 }
226 else
227 {
228 pVMMDevState->u32GuestFilterMask |= u32OrMask;
229 pVMMDevState->u32GuestFilterMask &= ~u32NotMask;
230 vmmdevMaybeSetIRQ_EMT (pVMMDevState);
231 }
232}
233
234void VMMDevCtlSetGuestFilterMask (VMMDevState *pVMMDevState,
235 uint32_t u32OrMask,
236 uint32_t u32NotMask)
237{
238 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
239 PVM pVM = PDMDevHlpGetVM(pDevIns);
240
241 Log(("VMMDevCtlSetGuestFilterMask: u32OrMask = 0x%08X, u32NotMask = 0x%08X.\n", u32OrMask, u32NotMask));
242
243 if (VM_IS_EMT(pVM))
244 {
245 vmmdevCtlGuestFilterMask_EMT (pVMMDevState, u32OrMask, u32NotMask);
246 }
247 else
248 {
249 int rc;
250 PVMREQ pReq;
251
252 rc = VMR3ReqCallVoid (pVM, &pReq, RT_INDEFINITE_WAIT,
253 (PFNRT) vmmdevCtlGuestFilterMask_EMT,
254 3, pVMMDevState, u32OrMask, u32NotMask);
255 AssertReleaseRC (rc);
256 VMR3ReqFree (pReq);
257 }
258}
259
260void VMMDevNotifyGuest (VMMDevState *pVMMDevState, uint32_t u32EventMask)
261{
262 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
263 PVM pVM = PDMDevHlpGetVM(pDevIns);
264 int rc;
265 PVMREQ pReq;
266
267#ifdef DEBUG_sunlover
268 Log(("VMMDevNotifyGuest: u32EventMask = 0x%08X.\n", u32EventMask));
269#endif /* DEBUG_sunlover */
270
271 rc = VMR3ReqCallVoid (pVM, &pReq, RT_INDEFINITE_WAIT,
272 (PFNRT) vmmdevNotifyGuest_EMT,
273 2, pVMMDevState, u32EventMask);
274 AssertReleaseRC (rc);
275 VMR3ReqFree (pReq);
276}
277
278/**
279 * Port I/O Handler for OUT operations.
280 *
281 * @returns VBox status code.
282 *
283 * @param pDevIns The device instance.
284 * @param pvUser User argument - ignored.
285 * @param uPort Port number used for the IN operation.
286 * @param u32 The value to output.
287 * @param cb The value size in bytes.
288 */
289#undef LOG_GROUP
290#define LOG_GROUP LOG_GROUP_DEV_VMM_BACKDOOR
291
292static DECLCALLBACK(int) vmmdevBackdoorLog(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
293{
294 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
295
296 if (!pData->fBackdoorLogDisabled && cb == 1 && Port == RTLOG_DEBUG_PORT)
297 {
298
299 /* The raw version. */
300 switch (u32)
301 {
302 case '\r': Log2(("vmmdev: <return>\n")); break;
303 case '\n': Log2(("vmmdev: <newline>\n")); break;
304 case '\t': Log2(("vmmdev: <tab>\n")); break;
305 default: Log2(("vmmdev: %c (%02x)\n", u32, u32)); break;
306 }
307
308 /* The readable, buffered version. */
309 if (u32 == '\n' || u32 == '\r')
310 {
311 pData->szMsg[pData->iMsg] = '\0';
312 if (pData->iMsg)
313 LogRel(("Guest Log: %s\n", pData->szMsg));
314 pData->iMsg = 0;
315 }
316 else
317 {
318 if (pData->iMsg >= sizeof(pData->szMsg)-1)
319 {
320 pData->szMsg[pData->iMsg] = '\0';
321 LogRel(("Guest Log: %s\n", pData->szMsg));
322 pData->iMsg = 0;
323 }
324 pData->szMsg[pData->iMsg] = (char )u32;
325 pData->szMsg[++pData->iMsg] = '\0';
326 }
327 }
328 return VINF_SUCCESS;
329}
330#undef LOG_GROUP
331#define LOG_GROUP LOG_GROUP_DEV_VMM
332
333#ifdef TIMESYNC_BACKDOOR
334/**
335 * Port I/O Handler for OUT operations.
336 *
337 * @returns VBox status code.
338 *
339 * @param pDevIns The device instance.
340 * @param pvUser User argument - ignored.
341 * @param uPort Port number used for the IN operation.
342 * @param u32 The value to output.
343 * @param cb The value size in bytes.
344 */
345static DECLCALLBACK(int) vmmdevTimesyncBackdoorWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
346{
347 NOREF(pvUser);
348 if (cb == 4)
349 {
350 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
351 switch (u32)
352 {
353 case 0:
354 pData->fTimesyncBackdoorLo = false;
355 break;
356 case 1:
357 pData->fTimesyncBackdoorLo = true;
358 }
359 return VINF_SUCCESS;
360
361 }
362 return VINF_SUCCESS;
363}
364
365/**
366 * Port I/O Handler for backdoor timesync IN operations.
367 *
368 * @returns VBox status code.
369 *
370 * @param pDevIns The device instance.
371 * @param pvUser User argument - ignored.
372 * @param uPort Port number used for the IN operation.
373 * @param pu32 Where to store the result.
374 * @param cb Number of bytes read.
375 */
376static DECLCALLBACK(int) vmmdevTimesyncBackdoorRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
377{
378 int rc;
379 NOREF(pvUser);
380 if (cb == 4)
381 {
382 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
383 RTTIMESPEC now;
384
385 if (pData->fTimesyncBackdoorLo)
386 {
387 *pu32 = (uint32_t)(pData->hostTime & (uint64_t)0xFFFFFFFF);
388 }
389 else
390 {
391 pData->hostTime = RTTimeSpecGetMilli(PDMDevHlpUTCNow(pDevIns, &now));
392 *pu32 = (uint32_t)(pData->hostTime >> 32);
393 }
394 rc = VINF_SUCCESS;
395 }
396 else
397 rc = VERR_IOM_IOPORT_UNUSED;
398 return rc;
399}
400#endif /* TIMESYNC_BACKDOOR */
401
402/**
403 * Port I/O Handler for the generic request interface
404 * @see FNIOMIOPORTOUT for details.
405 */
406static DECLCALLBACK(int) vmmdevRequestHandler(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
407{
408 VMMDevState *pData = (VMMDevState*)pvUser;
409 int rcRet = VINF_SUCCESS;
410 int rc;
411
412 /*
413 * The caller has passed the guest context physical address
414 * of the request structure. Get the corresponding host virtual
415 * address.
416 */
417 VMMDevRequestHeader *requestHeader = NULL;
418 rc = PDMDevHlpPhys2HCVirt(pDevIns, (RTGCPHYS)u32, 0, (PRTHCPTR)&requestHeader);
419 if (VBOX_FAILURE(rc) || !requestHeader)
420 {
421 AssertMsgFailed(("VMMDev could not convert guest physical address to host virtual! rc = %Vrc\n", rc));
422 return VINF_SUCCESS;
423 }
424
425 /* the structure size must be greater or equal to the header size */
426 if (requestHeader->size < sizeof(VMMDevRequestHeader))
427 {
428 Log(("VMMDev request header size too small! size = %d\n", requestHeader->size));
429 return VINF_SUCCESS;
430 }
431
432 /* check the version of the header structure */
433 if (requestHeader->version != VMMDEV_REQUEST_HEADER_VERSION)
434 {
435 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader->version, VMMDEV_REQUEST_HEADER_VERSION));
436 return VINF_SUCCESS;
437 }
438
439 Log2(("VMMDev request issued: %d\n", requestHeader->requestType));
440
441 if (requestHeader->requestType != VMMDevReq_ReportGuestInfo
442 && !pData->fu32AdditionsOk)
443 {
444 Log(("VMMDev: guest has not yet reported to us. Refusing operation.\n"));
445 requestHeader->rc = VERR_NOT_SUPPORTED;
446 return VINF_SUCCESS;
447 }
448
449 /* which request was sent? */
450 switch (requestHeader->requestType)
451 {
452 /*
453 * Guest wants to give up a timeslice
454 */
455 case VMMDevReq_Idle:
456 {
457 /* just return to EMT telling it that we want to halt */
458 return VINF_EM_HALT;
459 break;
460 }
461
462 /*
463 * Guest is reporting its information
464 */
465 case VMMDevReq_ReportGuestInfo:
466 {
467 if (requestHeader->size < sizeof(VMMDevReportGuestInfo))
468 {
469 AssertMsgFailed(("VMMDev guest information structure has invalid size!\n"));
470 requestHeader->rc = VERR_INVALID_PARAMETER;
471 }
472 else
473 {
474 VMMDevReportGuestInfo *guestInfo = (VMMDevReportGuestInfo*)requestHeader;
475
476 if (memcmp (&pData->guestInfo, &guestInfo->guestInfo, sizeof (guestInfo->guestInfo)) != 0)
477 {
478 /* make a copy of supplied information */
479 pData->guestInfo = guestInfo->guestInfo;
480
481 /* Check additions version */
482 pData->fu32AdditionsOk = VBOX_GUEST_ADDITIONS_VERSION_OK(pData->guestInfo.additionsVersion);
483
484 LogRel(("Guest Additions information report: additionsVersion = 0x%08X osType = 0x%08X\n",
485 pData->guestInfo.additionsVersion,
486 pData->guestInfo.osType));
487 pData->pDrv->pfnUpdateGuestVersion(pData->pDrv, &pData->guestInfo);
488 }
489
490 if (pData->fu32AdditionsOk)
491 {
492 requestHeader->rc = VINF_SUCCESS;
493 }
494 else
495 {
496 requestHeader->rc = VERR_VERSION_MISMATCH;
497 }
498 }
499 break;
500 }
501
502 /* Report guest capabilities */
503 case VMMDevReq_ReportGuestCapabilities:
504 {
505 if (requestHeader->size != sizeof(VMMDevReqGuestCapabilities))
506 {
507 AssertMsgFailed(("VMMDev guest caps structure has invalid size!\n"));
508 requestHeader->rc = VERR_INVALID_PARAMETER;
509 }
510 else
511 {
512 VMMDevReqGuestCapabilities *guestCaps = (VMMDevReqGuestCapabilities*)requestHeader;
513
514 if (pData->guestCaps != guestCaps->caps)
515 {
516 /* make a copy of supplied information */
517 pData->guestCaps = guestCaps->caps;
518
519 LogRel(("Guest Additions capability report: (0x%x) "
520 "VMMDEV_GUEST_SUPPORTS_SEAMLESS: %s "
521 "VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING: %s\n",
522 guestCaps->caps,
523 guestCaps->caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
524 guestCaps->caps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no"));
525
526 pData->pDrv->pfnUpdateGuestCapabilities(pData->pDrv, guestCaps->caps);
527 }
528 requestHeader->rc = VINF_SUCCESS;
529 }
530 break;
531 }
532
533 /*
534 * Retrieve mouse information
535 */
536 case VMMDevReq_GetMouseStatus:
537 {
538 if (requestHeader->size != sizeof(VMMDevReqMouseStatus))
539 {
540 AssertMsgFailed(("VMMDev mouse status structure has invalid size!\n"));
541 requestHeader->rc = VERR_INVALID_PARAMETER;
542 }
543 else
544 {
545 VMMDevReqMouseStatus *mouseStatus = (VMMDevReqMouseStatus*)requestHeader;
546 mouseStatus->mouseFeatures = 0;
547 if (pData->mouseCapabilities & VMMDEV_MOUSEHOSTWANTSABS)
548 {
549 mouseStatus->mouseFeatures |= VBOXGUEST_MOUSE_HOST_CAN_ABSOLUTE;
550 }
551 if (pData->mouseCapabilities & VMMDEV_MOUSEGUESTWANTSABS)
552 {
553 mouseStatus->mouseFeatures |= VBOXGUEST_MOUSE_GUEST_CAN_ABSOLUTE;
554 }
555 if (pData->mouseCapabilities & VMMDEV_MOUSEHOSTCANNOTHWPOINTER)
556 {
557 mouseStatus->mouseFeatures |= VBOXGUEST_MOUSE_HOST_CANNOT_HWPOINTER;
558 }
559 mouseStatus->pointerXPos = pData->mouseXAbs;
560 mouseStatus->pointerYPos = pData->mouseYAbs;
561 Log2(("returning mouse status: features = %d, absX = %d, absY = %d\n", mouseStatus->mouseFeatures,
562 mouseStatus->pointerXPos, mouseStatus->pointerYPos));
563 requestHeader->rc = VINF_SUCCESS;
564 }
565 break;
566 }
567
568 /*
569 * Set mouse information
570 */
571 case VMMDevReq_SetMouseStatus:
572 {
573 if (requestHeader->size != sizeof(VMMDevReqMouseStatus))
574 {
575 AssertMsgFailed(("VMMDev mouse status 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 bool bCapsChanged = false;
582
583 VMMDevReqMouseStatus *mouseStatus = (VMMDevReqMouseStatus*)requestHeader;
584
585 /* check if the guest wants absolute coordinates */
586 if (mouseStatus->mouseFeatures & VBOXGUEST_MOUSE_GUEST_CAN_ABSOLUTE)
587 {
588 /* set the capability flag and the changed flag if it's actually a change */
589 if (!(pData->mouseCapabilities & VMMDEV_MOUSEGUESTWANTSABS))
590 {
591 pData->mouseCapabilities |= VMMDEV_MOUSEGUESTWANTSABS;
592 bCapsChanged = true;
593 LogRel(("Guest requests mouse pointer integration\n"));
594 }
595 } else
596 {
597 if (pData->mouseCapabilities & VMMDEV_MOUSEGUESTWANTSABS)
598 {
599 pData->mouseCapabilities &= ~VMMDEV_MOUSEGUESTWANTSABS;
600 bCapsChanged = true;
601 LogRel(("Guest disables mouse pointer integration\n"));
602 }
603 }
604 if (mouseStatus->mouseFeatures & VBOXGUEST_MOUSE_GUEST_NEEDS_HOST_CURSOR)
605 pData->mouseCapabilities |= VMMDEV_MOUSEGUESTNEEDSHOSTCUR;
606 else
607 pData->mouseCapabilities &= ~VMMDEV_MOUSEGUESTNEEDSHOSTCUR;
608
609 /*
610 * Notify connector if something has changed
611 */
612 if (bCapsChanged)
613 {
614 Log(("VMMDevReq_SetMouseStatus: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
615 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
616 }
617 requestHeader->rc = VINF_SUCCESS;
618 }
619
620 break;
621 }
622
623 /*
624 * Set a new mouse pointer shape
625 */
626 case VMMDevReq_SetPointerShape:
627 {
628 if (requestHeader->size < sizeof(VMMDevReqMousePointer))
629 {
630 AssertMsg(requestHeader->size == 0x10028 && requestHeader->version == 10000, /* don't bitch about legacy!!! */
631 ("VMMDev mouse shape structure has invalid size %d (%#x) version=%d!\n",
632 requestHeader->size, requestHeader->size, requestHeader->size, requestHeader->version));
633 requestHeader->rc = VERR_INVALID_PARAMETER;
634 }
635 else
636 {
637 VMMDevReqMousePointer *pointerShape = (VMMDevReqMousePointer*)requestHeader;
638
639 bool fVisible = (pointerShape->fFlags & VBOX_MOUSE_POINTER_VISIBLE) != 0;
640 bool fAlpha = (pointerShape->fFlags & VBOX_MOUSE_POINTER_ALPHA) != 0;
641 bool fShape = (pointerShape->fFlags & VBOX_MOUSE_POINTER_SHAPE) != 0;
642
643 Log(("VMMDevReq_SetPointerShape: visible: %d, alpha: %d, shape = %d, width: %d, height: %d\n",
644 fVisible, fAlpha, fShape, pointerShape->width, pointerShape->height));
645
646 /* forward call to driver */
647 if (fShape)
648 {
649 pData->pDrv->pfnUpdatePointerShape(pData->pDrv,
650 fVisible,
651 fAlpha,
652 pointerShape->xHot, pointerShape->yHot,
653 pointerShape->width, pointerShape->height,
654 pointerShape->pointerData);
655 }
656 else
657 {
658 pData->pDrv->pfnUpdatePointerShape(pData->pDrv,
659 fVisible,
660 0,
661 0, 0,
662 0, 0,
663 NULL);
664 }
665 requestHeader->rc = VINF_SUCCESS;
666 }
667 break;
668 }
669
670 /*
671 * Query the system time from the host
672 */
673 case VMMDevReq_GetHostTime:
674 {
675 if (requestHeader->size != sizeof(VMMDevReqHostTime))
676 {
677 AssertMsgFailed(("VMMDev host time structure has invalid size!\n"));
678 requestHeader->rc = VERR_INVALID_PARAMETER;
679 }
680 else if (RT_UNLIKELY(pData->fGetHostTimeDisabled))
681 requestHeader->rc = VERR_NOT_SUPPORTED;
682 else
683 {
684 VMMDevReqHostTime *hostTimeReq = (VMMDevReqHostTime*)requestHeader;
685 RTTIMESPEC now;
686 hostTimeReq->time = RTTimeSpecGetMilli(PDMDevHlpUTCNow(pDevIns, &now));
687 requestHeader->rc = VINF_SUCCESS;
688 }
689 break;
690 }
691
692 /*
693 * Query information about the hypervisor
694 */
695 case VMMDevReq_GetHypervisorInfo:
696 {
697 if (requestHeader->size != sizeof(VMMDevReqHypervisorInfo))
698 {
699 AssertMsgFailed(("VMMDev hypervisor info structure has invalid size!\n"));
700 requestHeader->rc = VERR_INVALID_PARAMETER;
701 }
702 else
703 {
704 VMMDevReqHypervisorInfo *hypervisorInfo = (VMMDevReqHypervisorInfo*)requestHeader;
705 PVM pVM = PDMDevHlpGetVM(pDevIns);
706 size_t hypervisorSize = 0;
707 requestHeader->rc = PGMR3MappingsSize(pVM, &hypervisorSize);
708 hypervisorInfo->hypervisorSize = (uint32_t)hypervisorSize;
709 Assert(hypervisorInfo->hypervisorSize == hypervisorSize);
710 }
711 break;
712 }
713
714 /*
715 * Set hypervisor information
716 */
717 case VMMDevReq_SetHypervisorInfo:
718 {
719 if (requestHeader->size != sizeof(VMMDevReqHypervisorInfo))
720 {
721 AssertMsgFailed(("VMMDev hypervisor info structure has invalid size!\n"));
722 requestHeader->rc = VERR_INVALID_PARAMETER;
723 }
724 else
725 {
726 VMMDevReqHypervisorInfo *hypervisorInfo = (VMMDevReqHypervisorInfo*)requestHeader;
727 PVM pVM = PDMDevHlpGetVM(pDevIns);
728 if (hypervisorInfo->hypervisorStart == 0)
729 {
730 requestHeader->rc = PGMR3MappingsUnfix(pVM);
731 } else
732 {
733 /* only if the client has queried the size before! */
734 size_t mappingsSize;
735 requestHeader->rc = PGMR3MappingsSize(pVM, &mappingsSize);
736 if (VBOX_SUCCESS(requestHeader->rc) && (hypervisorInfo->hypervisorSize == mappingsSize))
737 {
738 /* new reservation */
739 requestHeader->rc = PGMR3MappingsFix(pVM, hypervisorInfo->hypervisorStart,
740 hypervisorInfo->hypervisorSize);
741 LogRel(("Guest reported fixed hypervisor window at 0x%p (size = 0x%x, rc = %Vrc)\n",
742 hypervisorInfo->hypervisorStart,
743 hypervisorInfo->hypervisorSize,
744 requestHeader->rc));
745 }
746 }
747 }
748 break;
749 }
750
751 /*
752 * Set the system power status
753 */
754 case VMMDevReq_SetPowerStatus:
755 {
756 if (requestHeader->size != sizeof(VMMDevPowerStateRequest))
757 {
758 AssertMsgFailed(("VMMDev power state request structure has invalid size!\n"));
759 requestHeader->rc = VERR_INVALID_PARAMETER;
760 }
761 else
762 {
763 VMMDevPowerStateRequest *powerStateRequest = (VMMDevPowerStateRequest*)requestHeader;
764 switch(powerStateRequest->powerState)
765 {
766 case VMMDevPowerState_Pause:
767 {
768 LogRel(("Guest requests the VM to be suspended (paused)\n"));
769 requestHeader->rc = rcRet = PDMDevHlpVMSuspend(pDevIns);
770 break;
771 }
772
773 case VMMDevPowerState_PowerOff:
774 {
775 LogRel(("Guest requests the VM to be turned off\n"));
776 requestHeader->rc = rcRet = PDMDevHlpVMPowerOff(pDevIns);
777 break;
778 }
779
780 case VMMDevPowerState_SaveState:
781 {
782 /** @todo no API for that yet */
783 requestHeader->rc = VERR_NOT_IMPLEMENTED;
784 break;
785 }
786
787 default:
788 AssertMsgFailed(("VMMDev invalid power state request: %d\n", powerStateRequest->powerState));
789 requestHeader->rc = VERR_INVALID_PARAMETER;
790 break;
791 }
792 }
793 break;
794 }
795
796 /*
797 * Get display change request
798 */
799 case VMMDevReq_GetDisplayChangeRequest:
800 {
801 if (requestHeader->size != sizeof(VMMDevDisplayChangeRequest))
802 {
803 /* Assert only if the size also not equal to a previous version size to prevent
804 * assertion with old additions.
805 */
806 AssertMsg(requestHeader->size == sizeof(VMMDevDisplayChangeRequest) - sizeof (uint32_t),
807 ("VMMDev display change request structure has invalid size!\n"));
808 requestHeader->rc = VERR_INVALID_PARAMETER;
809 }
810 else
811 {
812 VMMDevDisplayChangeRequest *displayChangeRequest = (VMMDevDisplayChangeRequest*)requestHeader;
813 /* just pass on the information */
814 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d\n",
815 pData->displayChangeRequest.xres, pData->displayChangeRequest.yres, pData->displayChangeRequest.bpp));
816 displayChangeRequest->xres = pData->displayChangeRequest.xres;
817 displayChangeRequest->yres = pData->displayChangeRequest.yres;
818 displayChangeRequest->bpp = pData->displayChangeRequest.bpp;
819
820 if (displayChangeRequest->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
821 {
822 /* Remember which resolution the client has queried. */
823 pData->lastReadDisplayChangeRequest = pData->displayChangeRequest;
824 }
825
826 requestHeader->rc = VINF_SUCCESS;
827 }
828 break;
829 }
830
831 case VMMDevReq_GetDisplayChangeRequest2:
832 {
833 if (requestHeader->size != sizeof(VMMDevDisplayChangeRequest2))
834 {
835 requestHeader->rc = VERR_INVALID_PARAMETER;
836 }
837 else
838 {
839 VMMDevDisplayChangeRequest2 *displayChangeRequest = (VMMDevDisplayChangeRequest2*)requestHeader;
840 /* just pass on the information */
841 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d at %d\n",
842 pData->displayChangeRequest.xres, pData->displayChangeRequest.yres, pData->displayChangeRequest.bpp, pData->displayChangeRequest.display));
843 displayChangeRequest->xres = pData->displayChangeRequest.xres;
844 displayChangeRequest->yres = pData->displayChangeRequest.yres;
845 displayChangeRequest->bpp = pData->displayChangeRequest.bpp;
846 displayChangeRequest->display = pData->displayChangeRequest.display;
847
848 if (displayChangeRequest->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
849 {
850 /* Remember which resolution the client has queried. */
851 pData->lastReadDisplayChangeRequest = pData->displayChangeRequest;
852 }
853
854 requestHeader->rc = VINF_SUCCESS;
855 }
856 break;
857 }
858
859 /*
860 * Query whether the given video mode is supported
861 */
862 case VMMDevReq_VideoModeSupported:
863 {
864 if (requestHeader->size != sizeof(VMMDevVideoModeSupportedRequest))
865 {
866 AssertMsgFailed(("VMMDev video mode supported request structure has invalid size!\n"));
867 requestHeader->rc = VERR_INVALID_PARAMETER;
868 }
869 else
870 {
871 VMMDevVideoModeSupportedRequest *videoModeSupportedRequest = (VMMDevVideoModeSupportedRequest*)requestHeader;
872 /* forward the call */
873 requestHeader->rc = pData->pDrv->pfnVideoModeSupported(pData->pDrv,
874 videoModeSupportedRequest->width,
875 videoModeSupportedRequest->height,
876 videoModeSupportedRequest->bpp,
877 &videoModeSupportedRequest->fSupported);
878 }
879 break;
880 }
881
882 /*
883 * Query the height reduction in pixels
884 */
885 case VMMDevReq_GetHeightReduction:
886 {
887 if (requestHeader->size != sizeof(VMMDevGetHeightReductionRequest))
888 {
889 AssertMsgFailed(("VMMDev height reduction request structure has invalid size!\n"));
890 requestHeader->rc = VERR_INVALID_PARAMETER;
891 }
892 else
893 {
894 VMMDevGetHeightReductionRequest *heightReductionRequest = (VMMDevGetHeightReductionRequest*)requestHeader;
895 /* forward the call */
896 requestHeader->rc = pData->pDrv->pfnGetHeightReduction(pData->pDrv,
897 &heightReductionRequest->heightReduction);
898 }
899 break;
900 }
901
902 /*
903 * Acknowledge VMMDev events
904 */
905 case VMMDevReq_AcknowledgeEvents:
906 {
907 if (requestHeader->size != sizeof(VMMDevEvents))
908 {
909 AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
910 requestHeader->rc = VERR_INVALID_PARAMETER;
911 }
912 else
913 {
914 if (VBOX_GUEST_ADDITIONS_VERSION_1_03 (pData))
915 {
916 vmmdevSetIRQ_Legacy_EMT (pData);
917 }
918 else
919 {
920 VMMDevEvents *pAckRequest;
921
922 if (pData->fNewGuestFilterMask)
923 {
924 pData->fNewGuestFilterMask = false;
925 pData->u32GuestFilterMask = pData->u32NewGuestFilterMask;
926 }
927
928 pAckRequest = (VMMDevEvents *) requestHeader;
929 pAckRequest->events =
930 pData->u32HostEventFlags & pData->u32GuestFilterMask;
931
932 pData->u32HostEventFlags &= ~pData->u32GuestFilterMask;
933 pData->pVMMDevRAMHC->V.V1_04.fHaveEvents = false;
934 PDMDevHlpPCISetIrqNoWait (pData->pDevIns, 0, 0);
935 }
936 requestHeader->rc = VINF_SUCCESS;
937 }
938 break;
939 }
940
941 /*
942 * Change guest filter mask
943 */
944 case VMMDevReq_CtlGuestFilterMask:
945 {
946 if (requestHeader->size != sizeof(VMMDevCtlGuestFilterMask))
947 {
948 AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
949 requestHeader->rc = VERR_INVALID_PARAMETER;
950 }
951 else
952 {
953 VMMDevCtlGuestFilterMask *pCtlMaskRequest;
954
955 pCtlMaskRequest = (VMMDevCtlGuestFilterMask *) requestHeader;
956 /* The HGCM events are enabled by the VMMDev device automatically when any
957 * HGCM command is issued. The guest then can not disable these events.
958 */
959 vmmdevCtlGuestFilterMask_EMT (pData,
960 pCtlMaskRequest->u32OrMask,
961 pCtlMaskRequest->u32NotMask & ~VMMDEV_EVENT_HGCM);
962 requestHeader->rc = VINF_SUCCESS;
963
964 }
965 break;
966 }
967
968#ifdef VBOX_HGCM
969 /*
970 * Process HGCM request
971 */
972 case VMMDevReq_HGCMConnect:
973 {
974 if (requestHeader->size < sizeof(VMMDevHGCMConnect))
975 {
976 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
977 requestHeader->rc = VERR_INVALID_PARAMETER;
978 }
979 else if (!pData->pHGCMDrv)
980 {
981 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
982 requestHeader->rc = VERR_NOT_SUPPORTED;
983 }
984 else
985 {
986 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)requestHeader;
987
988 Log(("VMMDevReq_HGCMConnect\n"));
989
990 requestHeader->rc = vmmdevHGCMConnect (pData, pHGCMConnect, (RTGCPHYS)u32);
991 }
992 break;
993 }
994
995 case VMMDevReq_HGCMDisconnect:
996 {
997 if (requestHeader->size < sizeof(VMMDevHGCMDisconnect))
998 {
999 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
1000 requestHeader->rc = VERR_INVALID_PARAMETER;
1001 }
1002 else if (!pData->pHGCMDrv)
1003 {
1004 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
1005 requestHeader->rc = VERR_NOT_SUPPORTED;
1006 }
1007 else
1008 {
1009 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)requestHeader;
1010
1011 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
1012 requestHeader->rc = vmmdevHGCMDisconnect (pData, pHGCMDisconnect, (RTGCPHYS)u32);
1013 }
1014 break;
1015 }
1016
1017 case VMMDevReq_HGCMCall:
1018 {
1019 if (requestHeader->size < sizeof(VMMDevHGCMCall))
1020 {
1021 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
1022 requestHeader->rc = VERR_INVALID_PARAMETER;
1023 }
1024 else if (!pData->pHGCMDrv)
1025 {
1026 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
1027 requestHeader->rc = VERR_NOT_SUPPORTED;
1028 }
1029 else
1030 {
1031 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)requestHeader;
1032
1033 Log2(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
1034 Log2(("%.*Vhxd\n", requestHeader->size, requestHeader));
1035
1036 requestHeader->rc = vmmdevHGCMCall (pData, pHGCMCall, (RTGCPHYS)u32);
1037 }
1038 break;
1039 }
1040#endif /* VBOX_HGCM */
1041
1042 case VMMDevReq_VideoAccelEnable:
1043 {
1044 if (requestHeader->size < sizeof(VMMDevVideoAccelEnable))
1045 {
1046 Log(("VMMDevReq_VideoAccelEnable request size too small!!!\n"));
1047 requestHeader->rc = VERR_INVALID_PARAMETER;
1048 }
1049 else if (!pData->pDrv)
1050 {
1051 Log(("VMMDevReq_VideoAccelEnable Connector is NULL!!!\n"));
1052 requestHeader->rc = VERR_NOT_SUPPORTED;
1053 }
1054 else
1055 {
1056 VMMDevVideoAccelEnable *ptr = (VMMDevVideoAccelEnable *)requestHeader;
1057
1058 if (ptr->cbRingBuffer != VBVA_RING_BUFFER_SIZE)
1059 {
1060 /* The guest driver seems compiled with another headers. */
1061 Log(("VMMDevReq_VideoAccelEnable guest ring buffer size %d, should be %d!!!\n", ptr->cbRingBuffer, VBVA_RING_BUFFER_SIZE));
1062 requestHeader->rc = VERR_INVALID_PARAMETER;
1063 }
1064 else
1065 {
1066 /* The request is correct. */
1067 ptr->fu32Status |= VBVA_F_STATUS_ACCEPTED;
1068
1069 LogFlow(("VMMDevReq_VideoAccelEnable ptr->u32Enable = %d\n", ptr->u32Enable));
1070
1071 requestHeader->rc = ptr->u32Enable?
1072 pData->pDrv->pfnVideoAccelEnable (pData->pDrv, true, &pData->pVMMDevRAMHC->vbvaMemory):
1073 pData->pDrv->pfnVideoAccelEnable (pData->pDrv, false, NULL);
1074
1075 if ( ptr->u32Enable
1076 && VBOX_SUCCESS (requestHeader->rc))
1077 {
1078 ptr->fu32Status |= VBVA_F_STATUS_ENABLED;
1079
1080 /* Remember that guest successfully enabled acceleration.
1081 * We need to reestablish it on restoring the VM from saved state.
1082 */
1083 pData->u32VideoAccelEnabled = 1;
1084 }
1085 else
1086 {
1087 /* The acceleration was not enabled. Remember that. */
1088 pData->u32VideoAccelEnabled = 0;
1089 }
1090 }
1091 }
1092 break;
1093 }
1094
1095 case VMMDevReq_VideoAccelFlush:
1096 {
1097 if (requestHeader->size < sizeof(VMMDevVideoAccelFlush))
1098 {
1099 AssertMsgFailed(("VMMDevReq_VideoAccelFlush request size too small.\n"));
1100 requestHeader->rc = VERR_INVALID_PARAMETER;
1101 }
1102 else if (!pData->pDrv)
1103 {
1104 Log(("VMMDevReq_VideoAccelFlush Connector is NULL!\n"));
1105 requestHeader->rc = VERR_NOT_SUPPORTED;
1106 }
1107 else
1108 {
1109 pData->pDrv->pfnVideoAccelFlush (pData->pDrv);
1110
1111 requestHeader->rc = VINF_SUCCESS;
1112 }
1113 break;
1114 }
1115
1116 case VMMDevReq_VideoSetVisibleRegion:
1117 {
1118 if (requestHeader->size < sizeof(VMMDevVideoSetVisibleRegion))
1119 {
1120 Log(("VMMDevReq_VideoSetVisibleRegion request size too small!!!\n"));
1121 requestHeader->rc = VERR_INVALID_PARAMETER;
1122 }
1123 else if (!pData->pDrv)
1124 {
1125 Log(("VMMDevReq_VideoSetVisibleRegion Connector is NULL!!!\n"));
1126 requestHeader->rc = VERR_NOT_SUPPORTED;
1127 }
1128 else
1129 {
1130 VMMDevVideoSetVisibleRegion *ptr = (VMMDevVideoSetVisibleRegion *)requestHeader;
1131
1132 if (!ptr->cRect)
1133 {
1134 Log(("VMMDevReq_VideoSetVisibleRegion no rectangles!!!\n"));
1135 requestHeader->rc = VERR_INVALID_PARAMETER;
1136 }
1137 else
1138 if (requestHeader->size != sizeof(VMMDevVideoSetVisibleRegion) + (ptr->cRect-1)*sizeof(RTRECT))
1139 {
1140 Log(("VMMDevReq_VideoSetVisibleRegion request size too small!!!\n"));
1141 requestHeader->rc = VERR_INVALID_PARAMETER;
1142 }
1143 else
1144 {
1145 Log(("VMMDevReq_VideoSetVisibleRegion %d rectangles\n", ptr->cRect));
1146 /* forward the call */
1147 requestHeader->rc = pData->pDrv->pfnSetVisibleRegion(pData->pDrv, ptr->cRect, &ptr->Rect);
1148 }
1149 }
1150 break;
1151 }
1152
1153 case VMMDevReq_GetSeamlessChangeRequest:
1154 {
1155 if (requestHeader->size != sizeof(VMMDevSeamlessChangeRequest))
1156 {
1157 requestHeader->rc = VERR_INVALID_PARAMETER;
1158 }
1159 else
1160 {
1161 VMMDevSeamlessChangeRequest *seamlessChangeRequest = (VMMDevSeamlessChangeRequest*)requestHeader;
1162 /* just pass on the information */
1163 Log(("VMMDev: returning seamless change request mode=%d\n", pData->fSeamlessEnabled));
1164 if (pData->fSeamlessEnabled)
1165 seamlessChangeRequest->mode = VMMDev_Seamless_Visible_Region;
1166 else
1167 seamlessChangeRequest->mode = VMMDev_Seamless_Disabled;
1168
1169 if (seamlessChangeRequest->eventAck == VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
1170 {
1171 /* Remember which mode the client has queried. */
1172 pData->fLastSeamlessEnabled = pData->fSeamlessEnabled;
1173 }
1174
1175 requestHeader->rc = VINF_SUCCESS;
1176 }
1177 break;
1178 }
1179
1180 case VMMDevReq_GetVRDPChangeRequest:
1181 {
1182 if (requestHeader->size != sizeof(VMMDevVRDPChangeRequest))
1183 {
1184 requestHeader->rc = VERR_INVALID_PARAMETER;
1185 }
1186 else
1187 {
1188 VMMDevVRDPChangeRequest *vrdpChangeRequest = (VMMDevVRDPChangeRequest*)requestHeader;
1189 /* just pass on the information */
1190 Log(("VMMDev: returning VRDP status %d level %d\n", pData->fVRDPEnabled, pData->u32VRDPExperienceLevel));
1191
1192 vrdpChangeRequest->u8VRDPActive = pData->fVRDPEnabled;
1193 vrdpChangeRequest->u32VRDPExperienceLevel = pData->u32VRDPExperienceLevel;
1194
1195 requestHeader->rc = VINF_SUCCESS;
1196 }
1197 break;
1198 }
1199
1200 case VMMDevReq_GetMemBalloonChangeRequest:
1201 {
1202 Log(("VMMDevReq_GetMemBalloonChangeRequest\n"));
1203 if (requestHeader->size != sizeof(VMMDevGetMemBalloonChangeRequest))
1204 {
1205 AssertFailed();
1206 requestHeader->rc = VERR_INVALID_PARAMETER;
1207 }
1208 else
1209 {
1210 VMMDevGetMemBalloonChangeRequest *memBalloonChangeRequest = (VMMDevGetMemBalloonChangeRequest*)requestHeader;
1211 /* just pass on the information */
1212 Log(("VMMDev: returning memory balloon size =%d\n", pData->u32MemoryBalloonSize));
1213 memBalloonChangeRequest->u32BalloonSize = pData->u32MemoryBalloonSize;
1214 memBalloonChangeRequest->u32PhysMemSize = (pData->u64GuestRAMSize / (uint64_t)_1M);
1215
1216 if (memBalloonChangeRequest->eventAck == VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
1217 {
1218 /* Remember which mode the client has queried. */
1219 pData->u32LastMemoryBalloonSize = pData->u32MemoryBalloonSize;
1220 }
1221
1222 requestHeader->rc = VINF_SUCCESS;
1223 }
1224 break;
1225 }
1226
1227 case VMMDevReq_ChangeMemBalloon:
1228 {
1229 VMMDevChangeMemBalloon *memBalloonChange = (VMMDevChangeMemBalloon*)requestHeader;
1230
1231 Log(("VMMDevReq_ChangeMemBalloon\n"));
1232 if ( requestHeader->size < sizeof(VMMDevChangeMemBalloon)
1233 || memBalloonChange->cPages != VMMDEV_MEMORY_BALLOON_CHUNK_PAGES
1234 || requestHeader->size != (uint32_t)RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[memBalloonChange->cPages]))
1235 {
1236 AssertFailed();
1237 requestHeader->rc = VERR_INVALID_PARAMETER;
1238 }
1239 else
1240 {
1241 requestHeader->rc = pData->pDrv->pfnChangeMemoryBalloon(pData->pDrv, !!memBalloonChange->fInflate, memBalloonChange->cPages, memBalloonChange->aPhysPage);
1242 }
1243 break;
1244 }
1245
1246 case VMMDevReq_GetStatisticsChangeRequest:
1247 {
1248 Log(("VMMDevReq_GetStatisticsChangeRequest\n"));
1249 if (requestHeader->size != sizeof(VMMDevGetStatisticsChangeRequest))
1250 {
1251 AssertFailed();
1252 requestHeader->rc = VERR_INVALID_PARAMETER;
1253 }
1254 else
1255 {
1256 VMMDevGetStatisticsChangeRequest *statIntervalChangeRequest = (VMMDevGetStatisticsChangeRequest*)requestHeader;
1257 /* just pass on the information */
1258 Log(("VMMDev: returning statistics interval %d seconds\n", pData->u32StatIntervalSize));
1259 statIntervalChangeRequest->u32StatInterval = pData->u32StatIntervalSize;
1260
1261 if (statIntervalChangeRequest->eventAck == VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)
1262 {
1263 /* Remember which mode the client has queried. */
1264 pData->u32LastStatIntervalSize= pData->u32StatIntervalSize;
1265 }
1266
1267 requestHeader->rc = VINF_SUCCESS;
1268 }
1269 break;
1270 }
1271
1272 case VMMDevReq_ReportGuestStats:
1273 {
1274 Log(("VMMDevReq_ReportGuestStats\n"));
1275 if (requestHeader->size != sizeof(VMMDevReportGuestStats))
1276 {
1277 requestHeader->rc = VERR_INVALID_PARAMETER;
1278 }
1279 else
1280 {
1281 VMMDevReportGuestStats *stats = (VMMDevReportGuestStats*)requestHeader;
1282
1283#ifdef DEBUG
1284 VBoxGuestStatistics *pGuestStats = &stats->guestStats;
1285
1286 Log(("Current statistics:\n"));
1287 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_IDLE)
1288 Log(("CPU%d: CPU Load Idle %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Idle));
1289
1290 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_KERNEL)
1291 Log(("CPU%d: CPU Load Kernel %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Kernel));
1292
1293 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_USER)
1294 Log(("CPU%d: CPU Load User %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_User));
1295
1296 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_THREADS)
1297 Log(("CPU%d: Thread %d\n", pGuestStats->u32CpuId, pGuestStats->u32Threads));
1298
1299 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PROCESSES)
1300 Log(("CPU%d: Processes %d\n", pGuestStats->u32CpuId, pGuestStats->u32Processes));
1301
1302 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_HANDLES)
1303 Log(("CPU%d: Handles %d\n", pGuestStats->u32CpuId, pGuestStats->u32Handles));
1304
1305 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEMORY_LOAD)
1306 Log(("CPU%d: Memory Load %d%%\n", pGuestStats->u32CpuId, pGuestStats->u32MemoryLoad));
1307
1308 /* Note that reported values are in pages; upper layers expect them in megabytes */
1309 Assert(pGuestStats->u32PageSize == 4096);
1310 if (pGuestStats->u32PageSize != 4096)
1311 pGuestStats->u32PageSize = 4096;
1312
1313 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_TOTAL)
1314 Log(("CPU%d: Total physical memory %-4d MB\n", pGuestStats->u32CpuId, (pGuestStats->u32PhysMemTotal + (_1M/pGuestStats->u32PageSize)-1)/ (_1M/pGuestStats->u32PageSize)));
1315
1316 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_AVAIL)
1317 Log(("CPU%d: Free physical memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemAvail / (_1M/pGuestStats->u32PageSize)));
1318
1319 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON)
1320 Log(("CPU%d: Memory balloon size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemBalloon / (_1M/pGuestStats->u32PageSize)));
1321
1322 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_COMMIT_TOTAL)
1323 Log(("CPU%d: Committed memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemCommitTotal / (_1M/pGuestStats->u32PageSize)));
1324
1325 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_TOTAL)
1326 Log(("CPU%d: Total kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelTotal / (_1M/pGuestStats->u32PageSize)));
1327
1328 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_PAGED)
1329 Log(("CPU%d: Paged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelPaged / (_1M/pGuestStats->u32PageSize)));
1330
1331 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED)
1332 Log(("CPU%d: Nonpaged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelNonPaged / (_1M/pGuestStats->u32PageSize)));
1333
1334 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE)
1335 Log(("CPU%d: System cache size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemSystemCache / (_1M/pGuestStats->u32PageSize)));
1336
1337 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE)
1338 Log(("CPU%d: Page file size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PageFileSize / (_1M/pGuestStats->u32PageSize)));
1339 Log(("Statistics end *******************\n"));
1340#endif
1341
1342 /* forward the call */
1343 requestHeader->rc = pData->pDrv->pfnReportStatistics(pData->pDrv, &stats->guestStats);
1344 }
1345 break;
1346 }
1347
1348 case VMMDevReq_QueryCredentials:
1349 {
1350 if (requestHeader->size != sizeof(VMMDevCredentials))
1351 {
1352 AssertMsgFailed(("VMMDevReq_QueryCredentials request size too small.\n"));
1353 requestHeader->rc = VERR_INVALID_PARAMETER;
1354 }
1355 else
1356 {
1357 VMMDevCredentials *credentials = (VMMDevCredentials*)requestHeader;
1358
1359 /* let's start by nulling out the data */
1360 memset(credentials->szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1361 memset(credentials->szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1362 memset(credentials->szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1363
1364 /* should we return whether we got credentials for a logon? */
1365 if (credentials->u32Flags & VMMDEV_CREDENTIALS_QUERYPRESENCE)
1366 {
1367 if ( pData->credentialsLogon.szUserName[0]
1368 || pData->credentialsLogon.szPassword[0]
1369 || pData->credentialsLogon.szDomain[0])
1370 {
1371 credentials->u32Flags |= VMMDEV_CREDENTIALS_PRESENT;
1372 }
1373 else
1374 {
1375 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_PRESENT;
1376 }
1377 }
1378
1379 /* does the guest want to read logon credentials? */
1380 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READ)
1381 {
1382 if (pData->credentialsLogon.szUserName[0])
1383 strcpy(credentials->szUserName, pData->credentialsLogon.szUserName);
1384 if (pData->credentialsLogon.szPassword[0])
1385 strcpy(credentials->szPassword, pData->credentialsLogon.szPassword);
1386 if (pData->credentialsLogon.szDomain[0])
1387 strcpy(credentials->szDomain, pData->credentialsLogon.szDomain);
1388 if (!pData->credentialsLogon.fAllowInteractiveLogon)
1389 credentials->u32Flags |= VMMDEV_CREDENTIALS_NOLOCALLOGON;
1390 else
1391 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_NOLOCALLOGON;
1392 }
1393
1394 /* does the caller want us to destroy the logon credentials? */
1395 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEAR)
1396 {
1397 memset(pData->credentialsLogon.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1398 memset(pData->credentialsLogon.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1399 memset(pData->credentialsLogon.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1400 }
1401
1402 /* does the guest want to read credentials for verification? */
1403 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READJUDGE)
1404 {
1405 if (pData->credentialsJudge.szUserName[0])
1406 strcpy(credentials->szUserName, pData->credentialsJudge.szUserName);
1407 if (pData->credentialsJudge.szPassword[0])
1408 strcpy(credentials->szPassword, pData->credentialsJudge.szPassword);
1409 if (pData->credentialsJudge.szDomain[0])
1410 strcpy(credentials->szDomain, pData->credentialsJudge.szDomain);
1411 }
1412
1413 /* does the caller want us to destroy the judgement credentials? */
1414 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEARJUDGE)
1415 {
1416 memset(pData->credentialsJudge.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1417 memset(pData->credentialsJudge.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1418 memset(pData->credentialsJudge.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1419 }
1420
1421 requestHeader->rc = VINF_SUCCESS;
1422 }
1423 break;
1424 }
1425
1426 case VMMDevReq_ReportCredentialsJudgement:
1427 {
1428 if (requestHeader->size != sizeof(VMMDevCredentials))
1429 {
1430 AssertMsgFailed(("VMMDevReq_ReportCredentialsJudgement request size too small.\n"));
1431 requestHeader->rc = VERR_INVALID_PARAMETER;
1432 }
1433 else
1434 {
1435 VMMDevCredentials *credentials = (VMMDevCredentials*)requestHeader;
1436
1437 /* what does the guest think about the credentials? (note: the order is important here!) */
1438 if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_DENY)
1439 {
1440 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_DENY);
1441 }
1442 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT)
1443 {
1444 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT);
1445 }
1446 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_OK)
1447 {
1448 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_OK);
1449 }
1450 else
1451 Log(("VMMDevReq_ReportCredentialsJudgement: invalid flags: %d!!!\n", credentials->u32Flags));
1452
1453 requestHeader->rc = VINF_SUCCESS;
1454 }
1455 break;
1456 }
1457
1458#ifdef DEBUG
1459 case VMMDevReq_LogString:
1460 {
1461 if (requestHeader->size < sizeof(VMMDevReqLogString))
1462 {
1463 AssertMsgFailed(("VMMDevReq_LogString request size too small.\n"));
1464 requestHeader->rc = VERR_INVALID_PARAMETER;
1465 }
1466 else
1467 {
1468 VMMDevReqLogString *pReqLogString = (VMMDevReqLogString*)requestHeader;
1469#undef LOG_GROUP
1470#define LOG_GROUP LOG_GROUP_DEV_VMM_BACKDOOR
1471// Log(("Guest Log: %s", pReqLogString->szString));
1472 Log(("DEBUG LOG: %s", pReqLogString->szString));
1473
1474#undef LOG_GROUP
1475#define LOG_GROUP LOG_GROUP_DEV_VMM
1476 requestHeader->rc = VINF_SUCCESS;
1477 }
1478 break;
1479 }
1480#endif
1481 default:
1482 {
1483 requestHeader->rc = VERR_NOT_IMPLEMENTED;
1484
1485 Log(("VMMDev unknown request type %d\n", requestHeader->requestType));
1486
1487 break;
1488 }
1489 }
1490
1491 return rcRet;
1492}
1493
1494/**
1495 * Callback function for mapping an PCI I/O region.
1496 *
1497 * @return VBox status code.
1498 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1499 * @param iRegion The region number.
1500 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1501 * I/O port, else it's a physical address.
1502 * This address is *NOT* relative to pci_mem_base like earlier!
1503 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1504 */
1505static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1506{
1507 int rc;
1508 VMMDevState *pData = PCIDEV_2_VMMDEVSTATE(pPciDev);
1509 LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%VGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
1510
1511
1512 Assert(pData->pVMMDevRAMHC != NULL);
1513
1514 memset (pData->pVMMDevRAMHC, 0, sizeof (VMMDevMemory));
1515 pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
1516 pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
1517
1518 /*
1519 * VMMDev RAM mapping.
1520 */
1521 if (iRegion == 1 && enmType == PCI_ADDRESS_SPACE_MEM)
1522 {
1523 /*
1524 * Register and lock the RAM.
1525 *
1526 * Windows usually re-initializes the PCI devices, so we have to check whether the memory was
1527 * already registered before trying to do that all over again.
1528 */
1529 PVM pVM = PDMDevHlpGetVM(pPciDev->pDevIns);
1530
1531 if (pData->GCPhysVMMDevRAM)
1532 {
1533 /*
1534 * Relocate the already registered VMMDevRAM.
1535 */
1536 rc = MMR3PhysRelocate(pVM, pData->GCPhysVMMDevRAM, GCPhysAddress, VMMDEV_RAM_SIZE);
1537 if (VBOX_SUCCESS(rc))
1538 {
1539 pData->GCPhysVMMDevRAM = GCPhysAddress;
1540 return VINF_SUCCESS;
1541 }
1542 AssertReleaseMsgFailed(("Failed to relocate VMMDev RAM from %VGp to %VGp! rc=%Vra\n", pData->GCPhysVMMDevRAM, GCPhysAddress, rc));
1543 }
1544 else
1545 {
1546 /*
1547 * Register and lock the VMMDevRAM.
1548 */
1549 /** @todo MM_RAM_FLAGS_MMIO2 seems to be appropriate for a RW memory.
1550 * Need to check. May be a RO memory is enough for the device.
1551 */
1552 rc = MMR3PhysRegister(pVM, pData->pVMMDevRAMHC, GCPhysAddress, VMMDEV_RAM_SIZE, MM_RAM_FLAGS_MMIO2, "VBoxDev");
1553 if (VBOX_SUCCESS(rc))
1554 {
1555 pData->GCPhysVMMDevRAM = GCPhysAddress;
1556 return VINF_SUCCESS;
1557 }
1558 AssertReleaseMsgFailed(("Failed to register VMMDev RAM! rc=%Vra\n", rc));
1559 }
1560 return rc;
1561 }
1562
1563 AssertReleaseMsgFailed(("VMMDev wrong region type: iRegion=%d enmType=%d\n", iRegion, enmType));
1564 return VERR_INTERNAL_ERROR;
1565}
1566
1567
1568/**
1569 * Callback function for mapping a PCI I/O region.
1570 *
1571 * @return VBox status code.
1572 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1573 * @param iRegion The region number.
1574 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1575 * I/O port, else it's a physical address.
1576 * This address is *NOT* relative to pci_mem_base like earlier!
1577 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1578 */
1579static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1580{
1581 VMMDevState *pData = PCIDEV_2_VMMDEVSTATE(pPciDev);
1582 int rc = VINF_SUCCESS;
1583
1584 Assert(enmType == PCI_ADDRESS_SPACE_IO);
1585 Assert(iRegion == 0);
1586 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
1587
1588 /*
1589 * Save the base port address to simplify Port offset calculations.
1590 */
1591 pData->PortBase = (RTIOPORT)GCPhysAddress;
1592
1593 /*
1594 * Register our port IO handlers.
1595 */
1596 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns,
1597 (RTIOPORT)GCPhysAddress + PORT_VMMDEV_REQUEST_OFFSET, 1,
1598 (void*)pData, vmmdevRequestHandler,
1599 NULL, NULL, NULL, "VMMDev Request Handler");
1600 AssertRC(rc);
1601 return rc;
1602}
1603
1604/**
1605 * Queries an interface to the driver.
1606 *
1607 * @returns Pointer to interface.
1608 * @returns NULL if the interface was not supported by the driver.
1609 * @param pInterface Pointer to this interface structure.
1610 * @param enmInterface The requested interface identification.
1611 * @thread Any thread.
1612 */
1613static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
1614{
1615 VMMDevState *pData = (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, Base));
1616 switch (enmInterface)
1617 {
1618 case PDMINTERFACE_BASE:
1619 return &pData->Base;
1620 case PDMINTERFACE_VMMDEV_PORT:
1621 return &pData->Port;
1622#ifdef VBOX_HGCM
1623 case PDMINTERFACE_HGCM_PORT:
1624 return &pData->HGCMPort;
1625#endif
1626 case PDMINTERFACE_LED_PORTS:
1627 /* Currently only for shared folders */
1628 return &pData->SharedFolders.ILeds;
1629 default:
1630 return NULL;
1631 }
1632}
1633
1634/**
1635 * Gets the pointer to the status LED of a unit.
1636 *
1637 * @returns VBox status code.
1638 * @param pInterface Pointer to the interface structure containing the called function pointer.
1639 * @param iLUN The unit which status LED we desire.
1640 * @param ppLed Where to store the LED pointer.
1641 */
1642static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
1643{
1644 VMMDevState *pData = (VMMDevState *)( (uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, SharedFolders.ILeds) );
1645 if (iLUN == 0) /* LUN 0 is shared folders */
1646 {
1647 *ppLed = &pData->SharedFolders.Led;
1648 return VINF_SUCCESS;
1649 }
1650 return VERR_PDM_LUN_NOT_FOUND;
1651}
1652
1653/* -=-=-=-=-=- IVMMDevPort -=-=-=-=-=- */
1654
1655/** Converts a VMMDev port interface pointer to a VMMDev state pointer. */
1656#define IVMMDEVPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, Port)) )
1657
1658
1659/**
1660 * Return the current absolute mouse position in pixels
1661 *
1662 * @returns VBox status code
1663 * @param pAbsX Pointer of result value, can be NULL
1664 * @param pAbsY Pointer of result value, can be NULL
1665 */
1666static DECLCALLBACK(int) vmmdevQueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t *pAbsX, uint32_t *pAbsY)
1667{
1668 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1669 if (pAbsX)
1670 *pAbsX = pData->mouseXAbs;
1671 if (pAbsY)
1672 *pAbsY = pData->mouseYAbs;
1673 return VINF_SUCCESS;
1674}
1675
1676/**
1677 * Set the new absolute mouse position in pixels
1678 *
1679 * @returns VBox status code
1680 * @param absX New absolute X position
1681 * @param absY New absolute Y position
1682 */
1683static DECLCALLBACK(int) vmmdevSetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t absX, uint32_t absY)
1684{
1685 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1686 Log2(("vmmdevSetAbsoluteMouse: settings absolute position to x = %d, y = %d\n", absX, absY));
1687 pData->mouseXAbs = absX;
1688 pData->mouseYAbs = absY;
1689 return VINF_SUCCESS;
1690}
1691
1692/**
1693 * Return the current mouse capability flags
1694 *
1695 * @returns VBox status code
1696 * @param pCapabilities Pointer of result value
1697 */
1698static DECLCALLBACK(int) vmmdevQueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pCapabilities)
1699{
1700 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1701 if (!pCapabilities)
1702 return VERR_INVALID_PARAMETER;
1703 *pCapabilities = pData->mouseCapabilities;
1704 return VINF_SUCCESS;
1705}
1706
1707/**
1708 * Set the current mouse capability flag (host side)
1709 *
1710 * @returns VBox status code
1711 * @param capabilities Capability mask
1712 */
1713static DECLCALLBACK(int) vmmdevSetMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t capabilities)
1714{
1715 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1716
1717 bool bCapsChanged = ((capabilities & VMMDEV_MOUSEHOSTWANTSABS)
1718 != (pData->mouseCapabilities & VMMDEV_MOUSEHOSTWANTSABS));
1719
1720 Log(("vmmdevSetMouseCapabilities: bCapsChanged %d\n", bCapsChanged));
1721
1722 if (capabilities & VMMDEV_MOUSEHOSTCANNOTHWPOINTER)
1723 pData->mouseCapabilities |= VMMDEV_MOUSEHOSTCANNOTHWPOINTER;
1724 else
1725 pData->mouseCapabilities &= ~VMMDEV_MOUSEHOSTCANNOTHWPOINTER;
1726
1727 if (capabilities & VMMDEV_MOUSEHOSTWANTSABS)
1728 pData->mouseCapabilities |= VMMDEV_MOUSEHOSTWANTSABS;
1729 else
1730 pData->mouseCapabilities &= ~VMMDEV_MOUSEHOSTWANTSABS;
1731
1732 if (bCapsChanged)
1733 VMMDevNotifyGuest (pData, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
1734
1735 return VINF_SUCCESS;
1736}
1737
1738
1739static DECLCALLBACK(int) vmmdevRequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t xres, uint32_t yres, uint32_t bpp, uint32_t display)
1740{
1741 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1742
1743 /* Verify that the new resolution is different and that guest does not yet know about it. */
1744 bool fSameResolution = (!xres || (pData->lastReadDisplayChangeRequest.xres == xres)) &&
1745 (!yres || (pData->lastReadDisplayChangeRequest.yres == yres)) &&
1746 (!bpp || (pData->lastReadDisplayChangeRequest.bpp == bpp)) &&
1747 pData->lastReadDisplayChangeRequest.display == display;
1748
1749 if (!xres && !yres && !bpp)
1750 {
1751 /* Special case of reset video mode. */
1752 fSameResolution = false;
1753 }
1754
1755#ifdef DEBUG_sunlover
1756 Log(("vmmdevRequestDisplayChange: same=%d. new: xres=%d, yres=%d, bpp=%d, display=%d. old: xres=%d, yres=%d, bpp=%d, display=%d.\n",
1757 fSameResolution, xres, yres, bpp, display, pData->lastReadDisplayChangeRequest.xres, pData->lastReadDisplayChangeRequest.yres, pData->lastReadDisplayChangeRequest.bpp, pData->lastReadDisplayChangeRequest.display));
1758#endif /* DEBUG_sunlover */
1759
1760 if (!fSameResolution)
1761 {
1762 LogRel(("VMMDev::SetVideoModeHint: got a video mode hint (%dx%dx%d) at %d\n",
1763 xres, yres, bpp, display));
1764
1765 /* we could validate the information here but hey, the guest can do that as well! */
1766 pData->displayChangeRequest.xres = xres;
1767 pData->displayChangeRequest.yres = yres;
1768 pData->displayChangeRequest.bpp = bpp;
1769 pData->displayChangeRequest.display = display;
1770
1771 /* IRQ so the guest knows what's going on */
1772 VMMDevNotifyGuest (pData, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
1773 }
1774
1775 return VINF_SUCCESS;
1776}
1777
1778static DECLCALLBACK(int) vmmdevRequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
1779{
1780 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1781
1782 /* Verify that the new resolution is different and that guest does not yet know about it. */
1783 bool fSameMode = (pData->fLastSeamlessEnabled == fEnabled);
1784
1785 Log(("vmmdevRequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
1786
1787 if (!fSameMode)
1788 {
1789 /* we could validate the information here but hey, the guest can do that as well! */
1790 pData->fSeamlessEnabled = fEnabled;
1791
1792 /* IRQ so the guest knows what's going on */
1793 VMMDevNotifyGuest (pData, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
1794 }
1795
1796 return VINF_SUCCESS;
1797}
1798
1799static DECLCALLBACK(int) vmmdevSetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t ulBalloonSize)
1800{
1801 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1802
1803 /* Verify that the new resolution is different and that guest does not yet know about it. */
1804 bool fSame = (pData->u32LastMemoryBalloonSize == ulBalloonSize);
1805
1806 Log(("vmmdevSetMemoryBalloon: old=%d. new=%d\n", pData->u32LastMemoryBalloonSize, ulBalloonSize));
1807
1808 if (!fSame)
1809 {
1810 /* we could validate the information here but hey, the guest can do that as well! */
1811 pData->u32MemoryBalloonSize = ulBalloonSize;
1812
1813 /* IRQ so the guest knows what's going on */
1814 VMMDevNotifyGuest (pData, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
1815 }
1816
1817 return VINF_SUCCESS;
1818}
1819
1820static DECLCALLBACK(int) vmmdevVRDPChange(PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t u32VRDPExperienceLevel)
1821{
1822 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1823
1824 bool fSame = (pData->fVRDPEnabled == fVRDPEnabled);
1825
1826 Log(("vmmdevVRDPChange: old=%d. new=%d\n", pData->fVRDPEnabled, fVRDPEnabled));
1827
1828 if (!fSame)
1829 {
1830 pData->fVRDPEnabled = fVRDPEnabled;
1831 pData->u32VRDPExperienceLevel = u32VRDPExperienceLevel;
1832
1833 VMMDevNotifyGuest (pData, VMMDEV_EVENT_VRDP);
1834 }
1835
1836 return VINF_SUCCESS;
1837}
1838
1839static DECLCALLBACK(int) vmmdevSetStatisticsInterval(PPDMIVMMDEVPORT pInterface, uint32_t ulStatInterval)
1840{
1841 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1842
1843 /* Verify that the new resolution is different and that guest does not yet know about it. */
1844 bool fSame = (pData->u32LastStatIntervalSize == ulStatInterval);
1845
1846 Log(("vmmdevSetStatisticsInterval: old=%d. new=%d\n", pData->u32LastStatIntervalSize, ulStatInterval));
1847
1848 if (!fSame)
1849 {
1850 /* we could validate the information here but hey, the guest can do that as well! */
1851 pData->u32StatIntervalSize = ulStatInterval;
1852
1853 /* IRQ so the guest knows what's going on */
1854 VMMDevNotifyGuest (pData, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
1855 }
1856
1857 return VINF_SUCCESS;
1858}
1859
1860
1861static DECLCALLBACK(int) vmmdevSetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
1862 const char *pszPassword, const char *pszDomain,
1863 uint32_t u32Flags)
1864{
1865 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1866
1867 /* logon mode? */
1868 if (u32Flags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
1869 {
1870 /* memorize the data */
1871 strcpy(pData->credentialsLogon.szUserName, pszUsername);
1872 strcpy(pData->credentialsLogon.szPassword, pszPassword);
1873 strcpy(pData->credentialsLogon.szDomain, pszDomain);
1874 pData->credentialsLogon.fAllowInteractiveLogon = !(u32Flags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
1875 }
1876 /* credentials verification mode? */
1877 else if (u32Flags & VMMDEV_SETCREDENTIALS_JUDGE)
1878 {
1879 /* memorize the data */
1880 strcpy(pData->credentialsJudge.szUserName, pszUsername);
1881 strcpy(pData->credentialsJudge.szPassword, pszPassword);
1882 strcpy(pData->credentialsJudge.szDomain, pszDomain);
1883
1884 VMMDevNotifyGuest (pData, VMMDEV_EVENT_JUDGE_CREDENTIALS);
1885 }
1886 else
1887 return VERR_INVALID_PARAMETER;
1888
1889 return VINF_SUCCESS;
1890}
1891
1892/**
1893 * Notification from the Display. Especially useful when
1894 * acceleration is disabled after a video mode change.
1895 *
1896 * @param fEnable Current acceleration status.
1897 */
1898static DECLCALLBACK(void) vmmdevVBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
1899{
1900 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1901
1902 Log(("vmmdevVBVAChange: fEnabled = %d\n", fEnabled));
1903
1904 if (pData)
1905 {
1906 pData->u32VideoAccelEnabled = fEnabled;
1907 }
1908
1909 return;
1910}
1911
1912
1913/* -=-=-=-=-=- IHGCMPort -=-=-=-=-=- */
1914
1915/** Converts a VMMDev port interface pointer to a VMMDev state pointer. */
1916#define IHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, HGCMPort)) )
1917
1918
1919
1920#define VMMDEV_SSM_VERSION 5
1921
1922/**
1923 * Saves a state of the VMM device.
1924 *
1925 * @returns VBox status code.
1926 * @param pDevIns The device instance.
1927 * @param pSSMHandle The handle to save the state to.
1928 */
1929static DECLCALLBACK(int) vmmdevSaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1930{
1931 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
1932 SSMR3PutU32(pSSMHandle, pData->hypervisorSize);
1933 SSMR3PutU32(pSSMHandle, pData->mouseCapabilities);
1934 SSMR3PutU32(pSSMHandle, pData->mouseXAbs);
1935 SSMR3PutU32(pSSMHandle, pData->mouseYAbs);
1936
1937 SSMR3PutBool(pSSMHandle, pData->fNewGuestFilterMask);
1938 SSMR3PutU32(pSSMHandle, pData->u32NewGuestFilterMask);
1939 SSMR3PutU32(pSSMHandle, pData->u32GuestFilterMask);
1940 SSMR3PutU32(pSSMHandle, pData->u32HostEventFlags);
1941 // here be dragons (probably)
1942// SSMR3PutBool(pSSMHandle, pData->pVMMDevRAMHC->V.V1_04.fHaveEvents);
1943 SSMR3PutMem(pSSMHandle, &pData->pVMMDevRAMHC->V, sizeof (pData->pVMMDevRAMHC->V));
1944
1945 SSMR3PutMem(pSSMHandle, &pData->guestInfo, sizeof (pData->guestInfo));
1946 SSMR3PutU32(pSSMHandle, pData->fu32AdditionsOk);
1947 SSMR3PutU32(pSSMHandle, pData->u32VideoAccelEnabled);
1948
1949 SSMR3PutU32(pSSMHandle, pData->guestCaps);
1950
1951#ifdef VBOX_HGCM
1952 vmmdevHGCMSaveState (pData, pSSMHandle);
1953#endif /* VBOX_HGCM */
1954
1955 return VINF_SUCCESS;
1956}
1957
1958/**
1959 * Loads the saved VMM device state.
1960 *
1961 * @returns VBox status code.
1962 * @param pDevIns The device instance.
1963 * @param pSSMHandle The handle to the saved state.
1964 * @param u32Version The data unit version number.
1965 */
1966static DECLCALLBACK(int) vmmdevLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
1967{
1968 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
1969 if (u32Version != VMMDEV_SSM_VERSION)
1970 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1971 SSMR3GetU32(pSSMHandle, &pData->hypervisorSize);
1972 SSMR3GetU32(pSSMHandle, &pData->mouseCapabilities);
1973 SSMR3GetU32(pSSMHandle, &pData->mouseXAbs);
1974 SSMR3GetU32(pSSMHandle, &pData->mouseYAbs);
1975
1976 SSMR3GetBool(pSSMHandle, &pData->fNewGuestFilterMask);
1977 SSMR3GetU32(pSSMHandle, &pData->u32NewGuestFilterMask);
1978 SSMR3GetU32(pSSMHandle, &pData->u32GuestFilterMask);
1979 SSMR3GetU32(pSSMHandle, &pData->u32HostEventFlags);
1980// SSMR3GetBool(pSSMHandle, &pData->pVMMDevRAMHC->fHaveEvents);
1981 // here be dragons (probably)
1982 SSMR3GetMem(pSSMHandle, &pData->pVMMDevRAMHC->V, sizeof (pData->pVMMDevRAMHC->V));
1983
1984 SSMR3GetMem(pSSMHandle, &pData->guestInfo, sizeof (pData->guestInfo));
1985 SSMR3GetU32(pSSMHandle, &pData->fu32AdditionsOk);
1986 SSMR3GetU32(pSSMHandle, &pData->u32VideoAccelEnabled);
1987
1988 SSMR3GetU32(pSSMHandle, &pData->guestCaps);
1989
1990#ifdef VBOX_HGCM
1991 vmmdevHGCMLoadState (pData, pSSMHandle);
1992#endif /* VBOX_HGCM */
1993
1994 /*
1995 * On a resume, we send the capabilities changed message so
1996 * that listeners can sync their state again
1997 */
1998 Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
1999 if (pData->pDrv)
2000 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
2001
2002 /* Reestablish the acceleration status. */
2003 if ( pData->u32VideoAccelEnabled
2004 && pData->pDrv)
2005 {
2006 pData->pDrv->pfnVideoAccelEnable (pData->pDrv, !!pData->u32VideoAccelEnabled, &pData->pVMMDevRAMHC->vbvaMemory);
2007 }
2008
2009 if (pData->fu32AdditionsOk)
2010 {
2011 LogRel(("Guest Additions information report: additionsVersion = 0x%08X osType = 0x%08X\n",
2012 pData->guestInfo.additionsVersion,
2013 pData->guestInfo.osType));
2014 if (pData->pDrv)
2015 pData->pDrv->pfnUpdateGuestVersion(pData->pDrv, &pData->guestInfo);
2016 }
2017 if (pData->pDrv)
2018 pData->pDrv->pfnUpdateGuestCapabilities(pData->pDrv, pData->guestCaps);
2019
2020 return VINF_SUCCESS;
2021}
2022
2023/**
2024 * Load state done callback. Notify guest of restore event.
2025 *
2026 * @returns VBox status code.
2027 * @param pDevIns The device instance.
2028 * @param pSSMHandle The handle to the saved state.
2029 */
2030static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
2031{
2032 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
2033
2034#ifdef VBOX_HGCM
2035 vmmdevHGCMLoadStateDone (pData, pSSMHandle);
2036#endif /* VBOX_HGCM */
2037
2038 VMMDevNotifyGuest (pData, VMMDEV_EVENT_RESTORED);
2039
2040 return VINF_SUCCESS;
2041}
2042
2043/**
2044 * Construct a device instance for a VM.
2045 *
2046 * @returns VBox status.
2047 * @param pDevIns The device instance data.
2048 * If the registration structure is needed, pDevIns->pDevReg points to it.
2049 * @param iInstance Instance number. Use this to figure out which registers and such to use.
2050 * The device number is also found in pDevIns->iInstance, but since it's
2051 * likely to be freqently used PDM passes it as parameter.
2052 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
2053 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
2054 * iInstance it's expected to be used a bit in this function.
2055 */
2056static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
2057{
2058 int rc;
2059 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
2060
2061 Assert(iInstance == 0);
2062
2063 /*
2064 * Validate and read the configuration.
2065 */
2066 if (!CFGMR3AreValuesValid(pCfgHandle, "GetHostTimeDisabled\0BackdoorLogDisabled\0"))
2067 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2068
2069 rc = CFGMR3QueryBool(pCfgHandle, "GetHostTimeDisabled", &pData->fGetHostTimeDisabled);
2070 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2071 pData->fGetHostTimeDisabled = false;
2072 else if (VBOX_FAILURE(rc))
2073 return PDMDEV_SET_ERROR(pDevIns, rc,
2074 N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
2075
2076 rc = CFGMR3QueryBool(pCfgHandle, "BackdoorLogDisabled", &pData->fBackdoorLogDisabled);
2077 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2078 pData->fBackdoorLogDisabled = false;
2079 else if (VBOX_FAILURE(rc))
2080 return PDMDEV_SET_ERROR(pDevIns, rc,
2081 N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
2082
2083 /*
2084 * Initialize data (most of it anyway).
2085 */
2086 /* Save PDM device instance data for future reference. */
2087 pData->pDevIns = pDevIns;
2088
2089 /* PCI vendor, just a free bogus value */
2090 pData->dev.config[0x00] = 0xee;
2091 pData->dev.config[0x01] = 0x80;
2092 /* device ID */
2093 pData->dev.config[0x02] = 0xfe;
2094 pData->dev.config[0x03] = 0xca;
2095 /* class sub code (other type of system peripheral) */
2096 pData->dev.config[0x0a] = 0x80;
2097 /* class base code (base system peripheral) */
2098 pData->dev.config[0x0b] = 0x08;
2099 /* header type */
2100 pData->dev.config[0x0e] = 0x00;
2101 /* interrupt on pin 0 */
2102 pData->dev.config[0x3d] = 0x01;
2103
2104 /*
2105 * Register the backdoor logging port
2106 */
2107 rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog, NULL, NULL, NULL, "VMMDev backdoor logging");
2108 AssertRCReturn(rc, rc);
2109
2110#ifdef TIMESYNC_BACKDOOR
2111 /*
2112 * Alternative timesync source (temporary!)
2113 */
2114 rc = PDMDevHlpIOPortRegister(pDevIns, 0x505, 1, NULL, vmmdevTimesyncBackdoorWrite, vmmdevTimesyncBackdoorRead, NULL, NULL, "VMMDev timesync backdoor");
2115 AssertRCReturn(rc, rc);
2116#endif
2117
2118 /*
2119 * Register the PCI device.
2120 */
2121 rc = PDMDevHlpPCIRegister(pDevIns, &pData->dev);
2122 if (VBOX_FAILURE(rc))
2123 return rc;
2124 if (pData->dev.devfn == 32 || iInstance != 0)
2125 Log(("!!WARNING!!: pData->dev.devfn=%d (ignore if testcase or no started by Main)\n", pData->dev.devfn));
2126 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
2127 if (VBOX_FAILURE(rc))
2128 return rc;
2129 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, vmmdevIORAMRegionMap);
2130 if (VBOX_FAILURE(rc))
2131 return rc;
2132
2133 /*
2134 * Interfaces
2135 */
2136 /* Base */
2137 pData->Base.pfnQueryInterface = vmmdevPortQueryInterface;
2138
2139 /* VMMDev port */
2140 pData->Port.pfnQueryAbsoluteMouse = vmmdevQueryAbsoluteMouse;
2141 pData->Port.pfnSetAbsoluteMouse = vmmdevSetAbsoluteMouse;
2142 pData->Port.pfnQueryMouseCapabilities = vmmdevQueryMouseCapabilities;
2143 pData->Port.pfnSetMouseCapabilities = vmmdevSetMouseCapabilities;
2144 pData->Port.pfnRequestDisplayChange = vmmdevRequestDisplayChange;
2145 pData->Port.pfnSetCredentials = vmmdevSetCredentials;
2146 pData->Port.pfnVBVAChange = vmmdevVBVAChange;
2147 pData->Port.pfnRequestSeamlessChange = vmmdevRequestSeamlessChange;
2148 pData->Port.pfnSetMemoryBalloon = vmmdevSetMemoryBalloon;
2149 pData->Port.pfnSetStatisticsInterval = vmmdevSetStatisticsInterval;
2150 pData->Port.pfnVRDPChange = vmmdevVRDPChange;
2151
2152 /* Shared folder LED */
2153 pData->SharedFolders.Led.u32Magic = PDMLED_MAGIC;
2154 pData->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
2155
2156#ifdef VBOX_HGCM
2157 /* HGCM port */
2158 pData->HGCMPort.pfnCompleted = hgcmCompleted;
2159#endif
2160
2161 /*
2162 * Get the corresponding connector interface
2163 */
2164 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->Base, &pData->pDrvBase, "VMM Driver Port");
2165 if (VBOX_SUCCESS(rc))
2166 {
2167 pData->pDrv = (PPDMIVMMDEVCONNECTOR)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_VMMDEV_CONNECTOR);
2168 if (!pData->pDrv)
2169 AssertMsgFailedReturn(("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
2170#ifdef VBOX_HGCM
2171 pData->pHGCMDrv = (PPDMIHGCMCONNECTOR)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_HGCM_CONNECTOR);
2172 if (!pData->pHGCMDrv)
2173 {
2174 Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Vrc\n", rc));
2175 /* this is not actually an error, just means that there is no support for HGCM */
2176 }
2177#endif
2178 }
2179 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2180 {
2181 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
2182 rc = VINF_SUCCESS;
2183 }
2184 else
2185 AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Vrc\n", rc), rc);
2186
2187 /*
2188 * Attach status driver for shared folders (optional).
2189 */
2190 PPDMIBASE pBase;
2191 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pData->Base, &pBase, "Status Port");
2192 if (VBOX_SUCCESS(rc))
2193 pData->SharedFolders.pLedsConnector = (PPDMILEDCONNECTORS)
2194 pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
2195 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
2196 {
2197 AssertMsgFailed(("Failed to attach to status driver. rc=%Vrc\n", rc));
2198 return rc;
2199 }
2200
2201 /*
2202 * Register saved state and init the HGCM CmdList critsect.
2203 */
2204 rc = PDMDevHlpSSMRegister(pDevIns, "VMMDev", iInstance, VMMDEV_SSM_VERSION, sizeof(*pData),
2205 NULL, vmmdevSaveState, NULL,
2206 NULL, vmmdevLoadState, vmmdevLoadStateDone);
2207 AssertRCReturn(rc, rc);
2208
2209#ifdef VBOX_HGCM
2210 pData->pHGCMCmdList = NULL;
2211 rc = RTCritSectInit(&pData->critsectHGCMCmdList);
2212 AssertRCReturn(rc, rc);
2213 pData->u32HGCMEnabled = 0;
2214#endif /* VBOX_HGCM */
2215
2216 /*
2217 * Allocate the VMMDev RAM region.
2218 */
2219 /** @todo freeing of the RAM. */
2220 rc = SUPPageAlloc(VMMDEV_RAM_SIZE >> PAGE_SHIFT, (void **)&pData->pVMMDevRAMHC);
2221 AssertMsgRCReturn(rc, ("VMMDev SUPPageAlloc(%#x,) -> %Vrc\n", VMMDEV_RAM_SIZE, rc), rc);
2222
2223 /* initialize the VMMDev memory */
2224 pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
2225 pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
2226
2227 PVM pVM = PDMDevHlpGetVM(pDevIns);
2228 pData->u64GuestRAMSize = MMR3PhysGetRamSize(pVM);
2229 return rc;
2230}
2231
2232/**
2233 * Reset notification.
2234 *
2235 * @returns VBox status.
2236 * @param pDrvIns The driver instance data.
2237 */
2238static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
2239{
2240 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
2241 /*
2242 * Reset the mouse integration feature bit
2243 */
2244 if (pData->mouseCapabilities & (VMMDEV_MOUSEGUESTWANTSABS|VMMDEV_MOUSEGUESTNEEDSHOSTCUR))
2245 {
2246 pData->mouseCapabilities &= ~VMMDEV_MOUSEGUESTWANTSABS;
2247 /* notify the connector */
2248 Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
2249 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
2250 }
2251
2252 pData->hypervisorSize = 0;
2253
2254 pData->u32HostEventFlags = 0;
2255
2256 if (pData->pVMMDevRAMHC)
2257 {
2258 /* re-initialize the VMMDev memory */
2259 memset (pData->pVMMDevRAMHC, 0, VMMDEV_RAM_SIZE);
2260 pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
2261 pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
2262 }
2263
2264 /* credentials have to go away */
2265 memset(pData->credentialsLogon.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
2266 memset(pData->credentialsLogon.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
2267 memset(pData->credentialsLogon.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
2268 memset(pData->credentialsJudge.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
2269 memset(pData->credentialsJudge.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
2270 memset(pData->credentialsJudge.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
2271
2272 /* Reset means that additions will report again. */
2273 pData->fu32AdditionsOk = false;
2274 memset (&pData->guestInfo, 0, sizeof (pData->guestInfo));
2275 pData->guestCaps = 0;
2276
2277 memset (&pData->lastReadDisplayChangeRequest, 0, sizeof (pData->lastReadDisplayChangeRequest));
2278
2279 /* disable seamless mode */
2280 pData->fLastSeamlessEnabled = false;
2281
2282 /* disabled memory ballooning */
2283 pData->u32LastMemoryBalloonSize = 0;
2284
2285 /* disabled statistics updating */
2286 pData->u32LastStatIntervalSize = 0;
2287
2288 /* Clear the event variables.
2289 *
2290 * Note: The pData->u32HostEventFlags is not cleared.
2291 * It is designed that way so host events do not
2292 * depend on guest resets.
2293 */
2294 pData->u32GuestFilterMask = 0;
2295 pData->u32NewGuestFilterMask = 0;
2296 pData->fNewGuestFilterMask = 0;
2297}
2298
2299
2300/**
2301 * The device registration structure.
2302 */
2303extern "C" const PDMDEVREG g_DeviceVMMDev =
2304{
2305 /* u32Version */
2306 PDM_DEVREG_VERSION,
2307 /* szDeviceName */
2308 "VMMDev",
2309 /* szGCMod */
2310 "",
2311 /* szR0Mod */
2312 "",
2313 /* pszDescription */
2314 "VirtualBox VMM Device\n",
2315 /* fFlags */
2316 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32,
2317 /* fClass */
2318 PDM_DEVREG_CLASS_VMM_DEV,
2319 /* cMaxInstances */
2320 1,
2321 /* cbInstance */
2322 sizeof(VMMDevState),
2323 /* pfnConstruct */
2324 vmmdevConstruct,
2325 /* pfnDestruct */
2326 NULL,
2327 /* pfnRelocate */
2328 NULL,
2329 /* pfnIOCtl */
2330 NULL,
2331 /* pfnPowerOn */
2332 NULL,
2333 /* pfnReset */
2334 vmmdevReset,
2335 /* pfnSuspend */
2336 NULL,
2337 /* pfnResume */
2338 NULL,
2339 /* pfnAttach */
2340 NULL,
2341 /* pfnDetach */
2342 NULL,
2343 /* pfnQueryInterface. */
2344 NULL
2345};
2346#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2347
Note: See TracBrowser for help on using the repository browser.

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