VirtualBox

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

Last change on this file since 30888 was 30857, checked in by vboxsync, 15 years ago

dang

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 118.8 KB
Line 
1/* $Id: VMMDev.cpp 30857 2010-07-15 09:06:38Z vboxsync $ */
2/** @file
3 * VMMDev - Guest <-> VMM/Host communication device.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22/* #define LOG_ENABLED */
23/* Enable dev_vmm Log3 statements to get IRQ-related logging. */
24
25#define LOG_GROUP LOG_GROUP_DEV_VMM
26#include <VBox/VMMDev.h>
27#include <VBox/log.h>
28#include <VBox/param.h>
29#include <VBox/pgm.h>
30#include <VBox/err.h>
31#include <VBox/vm.h> /* for VM_IS_EMT */
32
33#include <iprt/asm.h>
34#include <iprt/asm-amd64-x86.h>
35#include <iprt/assert.h>
36#include <iprt/buildconfig.h>
37#include <iprt/string.h>
38#include <iprt/time.h>
39#ifndef IN_RC
40# include <iprt/mem.h>
41#endif
42#ifdef IN_RING3
43# include <iprt/uuid.h>
44#endif
45
46#include "VMMDevState.h"
47#ifdef VBOX_WITH_HGCM
48# include "VMMDevHGCM.h"
49#endif
50#ifndef VBOX_WITHOUT_TESTING_FEATURES
51# include "VMMDevTesting.h"
52#endif
53
54
55/*******************************************************************************
56* Defined Constants And Macros *
57*******************************************************************************/
58#define PCIDEV_2_VMMDEVSTATE(pPciDev) ( (VMMDevState *)(pPciDev) )
59#define VMMDEVSTATE_2_DEVINS(pVMMDevState) ( (pVMMDevState)->pDevIns )
60
61#define VBOX_GUEST_ADDITIONS_VERSION_1_03(s) \
62 ( RT_HIWORD((s)->guestInfo.additionsVersion) == 1 \
63 && RT_LOWORD((s)->guestInfo.additionsVersion) == 3 )
64
65#define VBOX_GUEST_ADDITIONS_VERSION_OK(additionsVersion) \
66 ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
67 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) )
68
69#define VBOX_GUEST_ADDITIONS_VERSION_OLD(additionsVersion) \
70 ( (RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) \
71 || ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
72 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION) ) )
73
74#define VBOX_GUEST_ADDITIONS_VERSION_TOO_OLD(additionsVersion) \
75 ( RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) )
76
77#define VBOX_GUEST_ADDITIONS_VERSION_NEW(additionsVersion) \
78 ( RT_HIWORD(additionsVersion) > RT_HIWORD(VMMDEV_VERSION) \
79 || ( RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
80 && RT_LOWORD(additionsVersion) > RT_LOWORD(VMMDEV_VERSION) ) )
81
82/** The saved state version. */
83#define VMMDEV_SAVED_STATE_VERSION 13
84/** The saved state version used by VirtualBox 3.0.
85 * This doesn't have the config part. */
86#define VMMDEV_SAVED_STATE_VERSION_VBOX_30 11
87
88
89#ifndef VBOX_DEVICE_STRUCT_TESTCASE
90
91/* Whenever host wants to inform guest about something
92 * an IRQ notification will be raised.
93 *
94 * VMMDev PDM interface will contain the guest notification method.
95 *
96 * There is a 32 bit event mask which will be read
97 * by guest on an interrupt. A non zero bit in the mask
98 * means that the specific event occurred and requires
99 * processing on guest side.
100 *
101 * After reading the event mask guest must issue a
102 * generic request AcknowlegdeEvents.
103 *
104 * IRQ line is set to 1 (request) if there are unprocessed
105 * events, that is the event mask is not zero.
106 *
107 * After receiving an interrupt and checking event mask,
108 * the guest must process events using the event specific
109 * mechanism.
110 *
111 * That is if mouse capabilities were changed,
112 * guest will use VMMDev_GetMouseStatus generic request.
113 *
114 * Event mask is only a set of flags indicating that guest
115 * must proceed with a procedure.
116 *
117 * Unsupported events are therefore ignored.
118 * The guest additions must inform host which events they
119 * want to receive, to avoid unnecessary IRQ processing.
120 * By default no events are signalled to guest.
121 *
122 * This seems to be fast method. It requires
123 * only one context switch for an event processing.
124 *
125 */
126
127static void vmmdevSetIRQ_Legacy_EMT (VMMDevState *pVMMDevState)
128{
129 if (!pVMMDevState->fu32AdditionsOk)
130 {
131 Log(("vmmdevSetIRQ: IRQ is not generated, guest has not yet reported to us.\n"));
132 return;
133 }
134
135 uint32_t u32IRQLevel = 0;
136
137 /* Filter unsupported events */
138 uint32_t u32EventFlags =
139 pVMMDevState->u32HostEventFlags
140 & pVMMDevState->pVMMDevRAMR3->V.V1_03.u32GuestEventMask;
141
142 Log(("vmmdevSetIRQ: u32EventFlags = 0x%08X, "
143 "pVMMDevState->u32HostEventFlags = 0x%08X, "
144 "pVMMDevState->pVMMDevRAMR3->u32GuestEventMask = 0x%08X\n",
145 u32EventFlags,
146 pVMMDevState->u32HostEventFlags,
147 pVMMDevState->pVMMDevRAMR3->V.V1_03.u32GuestEventMask));
148
149 /* Move event flags to VMMDev RAM */
150 pVMMDevState->pVMMDevRAMR3->V.V1_03.u32HostEvents = u32EventFlags;
151
152 if (u32EventFlags)
153 {
154 /* Clear host flags which will be delivered to guest. */
155 pVMMDevState->u32HostEventFlags &= ~u32EventFlags;
156 Log(("vmmdevSetIRQ: pVMMDevState->u32HostEventFlags = 0x%08X\n",
157 pVMMDevState->u32HostEventFlags));
158 u32IRQLevel = 1;
159 }
160
161 /* Set IRQ level for pin 0 */
162 /** @todo make IRQ pin configurable, at least a symbolic constant */
163 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
164 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, u32IRQLevel);
165 Log(("vmmdevSetIRQ: IRQ set %d\n", u32IRQLevel));
166}
167
168static void vmmdevMaybeSetIRQ_EMT (VMMDevState *pVMMDevState)
169{
170 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS (pVMMDevState);
171
172 Log3(("vmmdevMaybeSetIRQ_EMT: u32HostEventFlags = 0x%08X, u32GuestFilterMask = 0x%08X.\n",
173 pVMMDevState->u32HostEventFlags, pVMMDevState->u32GuestFilterMask));
174
175 if (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask)
176 {
177 pVMMDevState->pVMMDevRAMR3->V.V1_04.fHaveEvents = true;
178 PDMDevHlpPCISetIrqNoWait (pDevIns, 0, 1);
179 Log3(("vmmdevMaybeSetIRQ_EMT: IRQ set.\n"));
180 }
181}
182
183static void vmmdevNotifyGuest_EMT (VMMDevState *pVMMDevState, uint32_t u32EventMask)
184{
185 Log3(("VMMDevNotifyGuest_EMT: u32EventMask = 0x%08X.\n", u32EventMask));
186
187 if (VBOX_GUEST_ADDITIONS_VERSION_1_03 (pVMMDevState))
188 {
189 Log3(("VMMDevNotifyGuest_EMT: Old additions detected.\n"));
190
191 pVMMDevState->u32HostEventFlags |= u32EventMask;
192 vmmdevSetIRQ_Legacy_EMT (pVMMDevState);
193 }
194 else
195 {
196 Log3(("VMMDevNotifyGuest_EMT: New additions detected.\n"));
197
198 if (!pVMMDevState->fu32AdditionsOk)
199 {
200 pVMMDevState->u32HostEventFlags |= u32EventMask;
201 Log(("vmmdevNotifyGuest_EMT: IRQ is not generated, guest has not yet reported to us.\n"));
202 return;
203 }
204
205 const bool fHadEvents =
206 (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask) != 0;
207
208 Log3(("VMMDevNotifyGuest_EMT: fHadEvents = %d, u32HostEventFlags = 0x%08X, u32GuestFilterMask = 0x%08X.\n",
209 fHadEvents, pVMMDevState->u32HostEventFlags, pVMMDevState->u32GuestFilterMask));
210
211 pVMMDevState->u32HostEventFlags |= u32EventMask;
212
213 if (!fHadEvents)
214 vmmdevMaybeSetIRQ_EMT (pVMMDevState);
215 }
216}
217
218void VMMDevCtlSetGuestFilterMask (VMMDevState *pVMMDevState,
219 uint32_t u32OrMask,
220 uint32_t u32NotMask)
221{
222 PDMCritSectEnter(&pVMMDevState->CritSect, VERR_SEM_BUSY);
223
224 const bool fHadEvents =
225 (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask) != 0;
226
227 Log(("VMMDevCtlSetGuestFilterMask: u32OrMask = 0x%08X, u32NotMask = 0x%08X, fHadEvents = %d.\n", u32OrMask, u32NotMask, fHadEvents));
228 if (fHadEvents)
229 {
230 if (!pVMMDevState->fNewGuestFilterMask)
231 pVMMDevState->u32NewGuestFilterMask = pVMMDevState->u32GuestFilterMask;
232
233 pVMMDevState->u32NewGuestFilterMask |= u32OrMask;
234 pVMMDevState->u32NewGuestFilterMask &= ~u32NotMask;
235 pVMMDevState->fNewGuestFilterMask = true;
236 }
237 else
238 {
239 pVMMDevState->u32GuestFilterMask |= u32OrMask;
240 pVMMDevState->u32GuestFilterMask &= ~u32NotMask;
241 vmmdevMaybeSetIRQ_EMT (pVMMDevState);
242 }
243 PDMCritSectLeave(&pVMMDevState->CritSect);
244}
245
246void VMMDevNotifyGuest (VMMDevState *pVMMDevState, uint32_t u32EventMask)
247{
248 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
249
250 Log3(("VMMDevNotifyGuest: u32EventMask = 0x%08X.\n", u32EventMask));
251
252 /*
253 * Drop notifications if the VM is not running yet/anymore.
254 */
255 VMSTATE enmVMState = PDMDevHlpVMState(pDevIns);
256 if ( enmVMState != VMSTATE_RUNNING
257 && enmVMState != VMSTATE_RUNNING_LS)
258 return;
259
260 PDMCritSectEnter(&pVMMDevState->CritSect, VERR_SEM_BUSY);
261 /* No need to wait for the completion of this request. It is a notification
262 * about something, which has already happened.
263 */
264 vmmdevNotifyGuest_EMT(pVMMDevState, u32EventMask);
265 PDMCritSectLeave(&pVMMDevState->CritSect);
266}
267
268/**
269 * Port I/O Handler for OUT operations.
270 *
271 * @returns VBox status code.
272 *
273 * @param pDevIns The device instance.
274 * @param pvUser User argument - ignored.
275 * @param uPort Port number used for the IN operation.
276 * @param u32 The value to output.
277 * @param cb The value size in bytes.
278 */
279static DECLCALLBACK(int) vmmdevBackdoorLog(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
280{
281 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
282
283 if (!pThis->fBackdoorLogDisabled && cb == 1 && Port == RTLOG_DEBUG_PORT)
284 {
285
286 /* The raw version. */
287 switch (u32)
288 {
289 case '\r': LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <return>\n")); break;
290 case '\n': LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <newline>\n")); break;
291 case '\t': LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: <tab>\n")); break;
292 default: LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_2, LOG_GROUP_DEV_VMM_BACKDOOR, ("vmmdev: %c (%02x)\n", u32, u32)); break;
293 }
294
295 /* The readable, buffered version. */
296 if (u32 == '\n' || u32 == '\r')
297 {
298 pThis->szMsg[pThis->iMsg] = '\0';
299 if (pThis->iMsg)
300 LogRelIt(LOG_REL_INSTANCE, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("Guest Log: %s\n", pThis->szMsg));
301 pThis->iMsg = 0;
302 }
303 else
304 {
305 if (pThis->iMsg >= sizeof(pThis->szMsg)-1)
306 {
307 pThis->szMsg[pThis->iMsg] = '\0';
308 LogRelIt(LOG_REL_INSTANCE, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR, ("Guest Log: %s\n", pThis->szMsg));
309 pThis->iMsg = 0;
310 }
311 pThis->szMsg[pThis->iMsg] = (char )u32;
312 pThis->szMsg[++pThis->iMsg] = '\0';
313 }
314 }
315 return VINF_SUCCESS;
316}
317
318#ifdef TIMESYNC_BACKDOOR
319/**
320 * Port I/O Handler for OUT operations.
321 *
322 * @returns VBox status code.
323 *
324 * @param pDevIns The device instance.
325 * @param pvUser User argument - ignored.
326 * @param uPort Port number used for the IN operation.
327 * @param u32 The value to output.
328 * @param cb The value size in bytes.
329 */
330static DECLCALLBACK(int) vmmdevTimesyncBackdoorWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
331{
332 NOREF(pvUser);
333 if (cb == 4)
334 {
335 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
336 switch (u32)
337 {
338 case 0:
339 pThis->fTimesyncBackdoorLo = false;
340 break;
341 case 1:
342 pThis->fTimesyncBackdoorLo = true;
343 }
344 return VINF_SUCCESS;
345
346 }
347 return VINF_SUCCESS;
348}
349
350/**
351 * Port I/O Handler for backdoor timesync IN operations.
352 *
353 * @returns VBox status code.
354 *
355 * @param pDevIns The device instance.
356 * @param pvUser User argument - ignored.
357 * @param uPort Port number used for the IN operation.
358 * @param pu32 Where to store the result.
359 * @param cb Number of bytes read.
360 */
361static DECLCALLBACK(int) vmmdevTimesyncBackdoorRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
362{
363 int rc;
364 NOREF(pvUser);
365 if (cb == 4)
366 {
367 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
368 RTTIMESPEC now;
369
370 if (pThis->fTimesyncBackdoorLo)
371 *pu32 = (uint32_t)pThis->hostTime;
372 else
373 {
374 pThis->hostTime = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pDevIns, &now));
375 *pu32 = (uint32_t)(pThis->hostTime >> 32);
376 }
377 rc = VINF_SUCCESS;
378 }
379 else
380 rc = VERR_IOM_IOPORT_UNUSED;
381 return rc;
382}
383#endif /* TIMESYNC_BACKDOOR */
384
385/**
386 * Port I/O Handler for the generic request interface
387 * @see FNIOMIOPORTOUT for details.
388 *
389 * @todo Too long, suggest doing the request copying here and moving the
390 * switch into a different function (or better case -> functions), and
391 * looing the gotos.
392 */
393static DECLCALLBACK(int) vmmdevRequestHandler(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
394{
395 VMMDevState *pThis = (VMMDevState*)pvUser;
396 int rcRet = VINF_SUCCESS;
397 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
398
399 /*
400 * The caller has passed the guest context physical address
401 * of the request structure. Copy the request packet.
402 */
403 VMMDevRequestHeader *pRequestHeader = NULL;
404 VMMDevRequestHeader requestHeader;
405 RT_ZERO(requestHeader);
406
407 PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)u32, &requestHeader, sizeof(requestHeader));
408
409 /* the structure size must be greater or equal to the header size */
410 if (requestHeader.size < sizeof(VMMDevRequestHeader))
411 {
412 Log(("VMMDev request header size too small! size = %d\n", requestHeader.size));
413 rcRet = VINF_SUCCESS;
414 goto end; /** @todo shouldn't (/ no need to) write back.*/
415 }
416
417 /* check the version of the header structure */
418 if (requestHeader.version != VMMDEV_REQUEST_HEADER_VERSION)
419 {
420 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader.version, VMMDEV_REQUEST_HEADER_VERSION));
421 rcRet = VINF_SUCCESS;
422 goto end; /** @todo shouldn't (/ no need to) write back.*/
423 }
424
425 Log2(("VMMDev request issued: %d\n", requestHeader.requestType));
426
427 if ( requestHeader.requestType != VMMDevReq_ReportGuestInfo
428 && !pThis->fu32AdditionsOk)
429 {
430 Log(("VMMDev: guest has not yet reported to us. Refusing operation.\n"));
431 requestHeader.rc = VERR_NOT_SUPPORTED;
432 rcRet = VINF_SUCCESS;
433 goto end;
434 }
435
436 /* Check upper limit */
437 if (requestHeader.size > VMMDEV_MAX_VMMDEVREQ_SIZE)
438 {
439 LogRel(("VMMDev: request packet too big (%x). Refusing operation.\n", requestHeader.size));
440 requestHeader.rc = VERR_NOT_SUPPORTED;
441 rcRet = VINF_SUCCESS;
442 goto end;
443 }
444
445 /* Read the entire request packet */
446 pRequestHeader = (VMMDevRequestHeader *)RTMemAlloc(requestHeader.size);
447 if (!pRequestHeader)
448 {
449 Log(("VMMDev: RTMemAlloc failed!\n"));
450 rcRet = VINF_SUCCESS;
451 requestHeader.rc = VERR_NO_MEMORY;
452 goto end;
453 }
454 PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)u32, pRequestHeader, requestHeader.size);
455
456 /* which request was sent? */
457 switch (pRequestHeader->requestType)
458 {
459 /*
460 * Guest wants to give up a timeslice
461 */
462 case VMMDevReq_Idle:
463 {
464 /* just return to EMT telling it that we want to halt */
465 rcRet = VINF_EM_HALT;
466 break;
467 }
468
469 /*
470 * Guest is reporting its information
471 */
472 case VMMDevReq_ReportGuestInfo:
473 {
474 if (pRequestHeader->size != sizeof(VMMDevReportGuestInfo))
475 {
476 AssertMsgFailed(("VMMDev guest information structure has an invalid size!\n"));
477 pRequestHeader->rc = VERR_INVALID_PARAMETER;
478 }
479 else
480 {
481 VBoxGuestInfo *guestInfo = &((VMMDevReportGuestInfo*)pRequestHeader)->guestInfo;
482
483 if (memcmp (&pThis->guestInfo, guestInfo, sizeof(*guestInfo)) != 0)
484 {
485 /* make a copy of supplied information */
486 pThis->guestInfo = *guestInfo;
487
488 /* Check additions version */
489 pThis->fu32AdditionsOk = VBOX_GUEST_ADDITIONS_VERSION_OK(pThis->guestInfo.additionsVersion);
490
491 LogRel(("Guest Additions information report: Interface = 0x%08X osType = 0x%08X\n",
492 pThis->guestInfo.additionsVersion,
493 pThis->guestInfo.osType));
494 pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
495 }
496
497 if (pThis->fu32AdditionsOk)
498 {
499 pRequestHeader->rc = VINF_SUCCESS;
500 }
501 else
502 {
503 pRequestHeader->rc = VERR_VERSION_MISMATCH;
504 }
505 }
506 break;
507 }
508
509 case VMMDevReq_ReportGuestInfo2:
510 {
511 if (pRequestHeader->size != sizeof(VMMDevReportGuestInfo2))
512 {
513 AssertMsgFailed(("VMMDev guest information 2 structure has an invalid size!\n"));
514 pRequestHeader->rc = VERR_INVALID_PARAMETER;
515 }
516 else
517 {
518 VBoxGuestInfo2 *guestInfo2 = &((VMMDevReportGuestInfo2*)pRequestHeader)->guestInfo;
519 LogRel(("Guest Additions information report: Version %d.%d.%d r%d '%.*s'\n",
520 guestInfo2->additionsMajor, guestInfo2->additionsMinor, guestInfo2->additionsBuild,
521 guestInfo2->additionsRevision, sizeof(guestInfo2->szName), guestInfo2->szName));
522 pRequestHeader->rc = VINF_SUCCESS;
523 }
524 break;
525 }
526
527 case VMMDevReq_ReportGuestStatus:
528 {
529 if (pRequestHeader->size != sizeof(VMMDevReportGuestStatus))
530 {
531 AssertMsgFailed(("VMMDev guest status structure has an invalid size!\n"));
532 pRequestHeader->rc = VERR_INVALID_PARAMETER;
533 }
534 else
535 {
536 VBoxGuestStatus *guestStatus = &((VMMDevReportGuestStatus*)pRequestHeader)->guestStatus;
537 pThis->pDrv->pfnUpdateGuestStatus(pThis->pDrv, guestStatus);
538
539 pRequestHeader->rc = VINF_SUCCESS;
540 }
541 break;
542 }
543
544 /* Report guest capabilities */
545 case VMMDevReq_ReportGuestCapabilities:
546 {
547 if (pRequestHeader->size != sizeof(VMMDevReqGuestCapabilities))
548 {
549 AssertMsgFailed(("VMMDev guest caps structure has invalid size!\n"));
550 pRequestHeader->rc = VERR_INVALID_PARAMETER;
551 }
552 else
553 {
554 VMMDevReqGuestCapabilities *guestCaps = (VMMDevReqGuestCapabilities*)pRequestHeader;
555
556 /* Enable this automatically for guests using the old
557 request to report their capabilities. */
558 /** @todo change this when we next bump the interface version */
559 guestCaps->caps |= VMMDEV_GUEST_SUPPORTS_GRAPHICS;
560 if (pThis->guestCaps != guestCaps->caps)
561 {
562 /* make a copy of supplied information */
563 pThis->guestCaps = guestCaps->caps;
564
565 LogRel(("Guest Additions capability report: (0x%x) "
566 "seamless: %s, "
567 "hostWindowMapping: %s, "
568 "graphics: %s\n",
569 guestCaps->caps,
570 guestCaps->caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
571 guestCaps->caps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no",
572 guestCaps->caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? "yes" : "no"));
573
574 pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, guestCaps->caps);
575 }
576 pRequestHeader->rc = VINF_SUCCESS;
577 }
578 break;
579 }
580
581 /* Change guest capabilities */
582 case VMMDevReq_SetGuestCapabilities:
583 {
584 if (pRequestHeader->size != sizeof(VMMDevReqGuestCapabilities2))
585 {
586 AssertMsgFailed(("VMMDev guest caps structure has invalid size!\n"));
587 pRequestHeader->rc = VERR_INVALID_PARAMETER;
588 }
589 else
590 {
591 VMMDevReqGuestCapabilities2 *guestCaps = (VMMDevReqGuestCapabilities2*)pRequestHeader;
592
593 pThis->guestCaps |= guestCaps->u32OrMask;
594 pThis->guestCaps &= ~guestCaps->u32NotMask;
595
596 LogRel(("Guest Additions capability report: (0x%x) "
597 "seamless: %s, "
598 "hostWindowMapping: %s, "
599 "graphics: %s\n",
600 pThis->guestCaps,
601 pThis->guestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
602 pThis->guestCaps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no",
603 pThis->guestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? "yes" : "no"));
604
605 pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
606 pRequestHeader->rc = VINF_SUCCESS;
607 }
608 break;
609 }
610
611 /*
612 * Retrieve mouse information
613 */
614 case VMMDevReq_GetMouseStatus:
615 {
616 if (pRequestHeader->size != sizeof(VMMDevReqMouseStatus))
617 {
618 AssertMsgFailed(("VMMDev mouse status structure has invalid size!\n"));
619 pRequestHeader->rc = VERR_INVALID_PARAMETER;
620 }
621 else
622 {
623 VMMDevReqMouseStatus *mouseStatus = (VMMDevReqMouseStatus*)pRequestHeader;
624 mouseStatus->mouseFeatures = pThis->mouseCapabilities
625 & VMMDEV_MOUSE_MASK;
626 mouseStatus->pointerXPos = pThis->mouseXAbs;
627 mouseStatus->pointerYPos = pThis->mouseYAbs;
628 LogRel2(("%s: VMMDevReq_GetMouseStatus: features = 0x%x, absX = %d, absY = %d\n",
629 __PRETTY_FUNCTION__,
630 mouseStatus->mouseFeatures,
631 mouseStatus->pointerXPos,
632 mouseStatus->pointerYPos));
633 pRequestHeader->rc = VINF_SUCCESS;
634 }
635 break;
636 }
637
638 /*
639 * Set mouse information
640 */
641 case VMMDevReq_SetMouseStatus:
642 {
643 if (pRequestHeader->size != sizeof(VMMDevReqMouseStatus))
644 {
645 AssertMsgFailed(("VMMDev mouse status structure has invalid size %d (%#x) version=%d!\n",
646 pRequestHeader->size, pRequestHeader->size, pRequestHeader->size, pRequestHeader->version));
647 pRequestHeader->rc = VERR_INVALID_PARAMETER;
648 }
649 else
650 {
651 bool fNotify = false;
652
653 uint32_t fFeatures =
654 ((VMMDevReqMouseStatus*)pRequestHeader)->mouseFeatures;
655
656 LogRelFlowFunc(("VMMDevReqMouseStatus: mouseFeatures = 0x%x\n",
657 fFeatures));
658
659 if ( (fFeatures & VMMDEV_MOUSE_NOTIFY_HOST_MASK)
660 != ( pThis->mouseCapabilities
661 & VMMDEV_MOUSE_NOTIFY_HOST_MASK))
662 fNotify = true;
663 pThis->mouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
664 pThis->mouseCapabilities |=
665 (fFeatures & VMMDEV_MOUSE_GUEST_MASK);
666 LogRelFlowFunc(("VMMDevReq_SetMouseStatus: new host capabilities: 0x%x\n",
667 pThis->mouseCapabilities));
668
669 /*
670 * Notify connector if something has changed
671 */
672 if (fNotify)
673 {
674 LogRelFlowFunc(("VMMDevReq_SetMouseStatus: notifying connector\n"));
675 pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
676 }
677 pRequestHeader->rc = VINF_SUCCESS;
678 }
679
680 break;
681 }
682
683 /*
684 * Set a new mouse pointer shape
685 */
686 case VMMDevReq_SetPointerShape:
687 {
688 if (pRequestHeader->size < sizeof(VMMDevReqMousePointer))
689 {
690 AssertMsg(pRequestHeader->size == 0x10028 && pRequestHeader->version == 10000, /* don't bitch about legacy!!! */
691 ("VMMDev mouse shape structure has invalid size %d (%#x) version=%d!\n",
692 pRequestHeader->size, pRequestHeader->size, pRequestHeader->size, pRequestHeader->version));
693 pRequestHeader->rc = VERR_INVALID_PARAMETER;
694 }
695 else
696 {
697 VMMDevReqMousePointer *pointerShape = (VMMDevReqMousePointer*)pRequestHeader;
698
699 bool fVisible = (pointerShape->fFlags & VBOX_MOUSE_POINTER_VISIBLE) != 0;
700 bool fAlpha = (pointerShape->fFlags & VBOX_MOUSE_POINTER_ALPHA) != 0;
701 bool fShape = (pointerShape->fFlags & VBOX_MOUSE_POINTER_SHAPE) != 0;
702
703 Log(("VMMDevReq_SetPointerShape: visible: %d, alpha: %d, shape = %d, width: %d, height: %d\n",
704 fVisible, fAlpha, fShape, pointerShape->width, pointerShape->height));
705
706 if (pRequestHeader->size == sizeof(VMMDevReqMousePointer))
707 {
708 /* The guest did not provide the shape actually. */
709 fShape = false;
710 }
711
712 /* forward call to driver */
713 if (fShape)
714 {
715 pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
716 fVisible,
717 fAlpha,
718 pointerShape->xHot, pointerShape->yHot,
719 pointerShape->width, pointerShape->height,
720 pointerShape->pointerData);
721 }
722 else
723 {
724 pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
725 fVisible,
726 0,
727 0, 0,
728 0, 0,
729 NULL);
730 }
731 pThis->fHostCursorRequested = fVisible;
732 pRequestHeader->rc = VINF_SUCCESS;
733 }
734 break;
735 }
736
737 /*
738 * Query the system time from the host
739 */
740 case VMMDevReq_GetHostTime:
741 {
742 if (pRequestHeader->size != sizeof(VMMDevReqHostTime))
743 {
744 AssertMsgFailed(("VMMDev host time structure has invalid size!\n"));
745 pRequestHeader->rc = VERR_INVALID_PARAMETER;
746 }
747 else if (RT_UNLIKELY(pThis->fGetHostTimeDisabled))
748 pRequestHeader->rc = VERR_NOT_SUPPORTED;
749 else
750 {
751 VMMDevReqHostTime *hostTimeReq = (VMMDevReqHostTime*)pRequestHeader;
752 RTTIMESPEC now;
753 hostTimeReq->time = RTTimeSpecGetMilli(PDMDevHlpTMUtcNow(pDevIns, &now));
754 pRequestHeader->rc = VINF_SUCCESS;
755 }
756 break;
757 }
758
759 /*
760 * Query information about the hypervisor
761 */
762 case VMMDevReq_GetHypervisorInfo:
763 {
764 if (pRequestHeader->size != sizeof(VMMDevReqHypervisorInfo))
765 {
766 AssertMsgFailed(("VMMDev hypervisor info structure has invalid size!\n"));
767 pRequestHeader->rc = VERR_INVALID_PARAMETER;
768 }
769 else
770 {
771 VMMDevReqHypervisorInfo *hypervisorInfo = (VMMDevReqHypervisorInfo*)pRequestHeader;
772 PVM pVM = PDMDevHlpGetVM(pDevIns);
773 pRequestHeader->rc = PGMR3MappingsSize(pVM, &hypervisorInfo->hypervisorSize);
774 }
775 break;
776 }
777
778 /*
779 * Set hypervisor information
780 */
781 case VMMDevReq_SetHypervisorInfo:
782 {
783 if (pRequestHeader->size != sizeof(VMMDevReqHypervisorInfo))
784 {
785 AssertMsgFailed(("VMMDev hypervisor info structure has invalid size!\n"));
786 pRequestHeader->rc = VERR_INVALID_PARAMETER;
787 }
788 else
789 {
790 VMMDevReqHypervisorInfo *hypervisorInfo = (VMMDevReqHypervisorInfo*)pRequestHeader;
791 PVM pVM = PDMDevHlpGetVM(pDevIns);
792 if (hypervisorInfo->hypervisorStart == 0)
793 pRequestHeader->rc = PGMR3MappingsUnfix(pVM);
794 else
795 {
796 /* only if the client has queried the size before! */
797 uint32_t mappingsSize;
798 pRequestHeader->rc = PGMR3MappingsSize(pVM, &mappingsSize);
799 if (RT_SUCCESS(pRequestHeader->rc) && hypervisorInfo->hypervisorSize == mappingsSize)
800 {
801 /* new reservation */
802 pRequestHeader->rc = PGMR3MappingsFix(pVM, hypervisorInfo->hypervisorStart,
803 hypervisorInfo->hypervisorSize);
804 LogRel(("Guest reported fixed hypervisor window at 0x%p (size = 0x%x, rc = %Rrc)\n",
805 (uintptr_t)hypervisorInfo->hypervisorStart,
806 hypervisorInfo->hypervisorSize,
807 pRequestHeader->rc));
808 }
809 }
810 }
811 break;
812 }
813
814 case VMMDevReq_RegisterPatchMemory:
815 {
816 if (pRequestHeader->size != sizeof(VMMDevReqPatchMemory))
817 {
818 AssertMsgFailed(("VMMDevReq_RegisterPatchMemory structure has invalid size!\n"));
819 pRequestHeader->rc = VERR_INVALID_PARAMETER;
820 }
821 else
822 {
823 VMMDevReqPatchMemory *pPatchRequest = (VMMDevReqPatchMemory*)pRequestHeader;
824
825 pRequestHeader->rc = VMMR3RegisterPatchMemory(PDMDevHlpGetVM(pDevIns), pPatchRequest->pPatchMem, pPatchRequest->cbPatchMem);
826 }
827 break;
828 }
829
830 case VMMDevReq_DeregisterPatchMemory:
831 {
832 if (pRequestHeader->size != sizeof(VMMDevReqPatchMemory))
833 {
834 AssertMsgFailed(("VMMDevReq_DeregisterPatchMemory structure has invalid size!\n"));
835 pRequestHeader->rc = VERR_INVALID_PARAMETER;
836 }
837 else
838 {
839 VMMDevReqPatchMemory *pPatchRequest = (VMMDevReqPatchMemory*)pRequestHeader;
840
841 pRequestHeader->rc = VMMR3DeregisterPatchMemory(PDMDevHlpGetVM(pDevIns), pPatchRequest->pPatchMem, pPatchRequest->cbPatchMem);
842 }
843 break;
844 }
845
846 /*
847 * Set the system power status
848 */
849 case VMMDevReq_SetPowerStatus:
850 {
851 if (pRequestHeader->size != sizeof(VMMDevPowerStateRequest))
852 {
853 AssertMsgFailed(("VMMDev power state request structure has invalid size!\n"));
854 pRequestHeader->rc = VERR_INVALID_PARAMETER;
855 }
856 else
857 {
858 VMMDevPowerStateRequest *powerStateRequest = (VMMDevPowerStateRequest*)pRequestHeader;
859 switch(powerStateRequest->powerState)
860 {
861 case VMMDevPowerState_Pause:
862 {
863 LogRel(("Guest requests the VM to be suspended (paused)\n"));
864 pRequestHeader->rc = rcRet = PDMDevHlpVMSuspend(pDevIns);
865 break;
866 }
867
868 case VMMDevPowerState_PowerOff:
869 {
870 LogRel(("Guest requests the VM to be turned off\n"));
871 pRequestHeader->rc = rcRet = PDMDevHlpVMPowerOff(pDevIns);
872 break;
873 }
874
875 case VMMDevPowerState_SaveState:
876 {
877 /** @todo no API for that yet */
878 pRequestHeader->rc = VERR_NOT_IMPLEMENTED;
879 break;
880 }
881
882 default:
883 AssertMsgFailed(("VMMDev invalid power state request: %d\n", powerStateRequest->powerState));
884 pRequestHeader->rc = VERR_INVALID_PARAMETER;
885 break;
886 }
887 }
888 break;
889 }
890
891 /*
892 * Get display change request
893 */
894 case VMMDevReq_GetDisplayChangeRequest:
895 {
896 if (pRequestHeader->size != sizeof(VMMDevDisplayChangeRequest))
897 {
898 /* Assert only if the size also not equal to a previous version size to prevent
899 * assertion with old additions.
900 */
901 AssertMsg(pRequestHeader->size == sizeof(VMMDevDisplayChangeRequest) - sizeof (uint32_t),
902 ("VMMDev display change request structure has invalid size!\n"));
903 pRequestHeader->rc = VERR_INVALID_PARAMETER;
904 }
905 else
906 {
907 VMMDevDisplayChangeRequest *displayChangeRequest = (VMMDevDisplayChangeRequest*)pRequestHeader;
908
909 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[0];
910
911 if (displayChangeRequest->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
912 {
913 /* Current request has been read at least once. */
914 pRequest->fPending = false;
915
916 /* Check if there are more pending requests. */
917 for (unsigned i = 1; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
918 {
919 if (pThis->displayChangeData.aRequests[i].fPending)
920 {
921 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
922 break;
923 }
924 }
925
926 /* Remember which resolution the client has queried, subsequent reads
927 * will return the same values. */
928 pRequest->lastReadDisplayChangeRequest = pRequest->displayChangeRequest;
929 pThis->displayChangeData.fGuestSentChangeEventAck = true;
930 }
931
932 if (pThis->displayChangeData.fGuestSentChangeEventAck)
933 {
934 displayChangeRequest->xres = pRequest->lastReadDisplayChangeRequest.xres;
935 displayChangeRequest->yres = pRequest->lastReadDisplayChangeRequest.yres;
936 displayChangeRequest->bpp = pRequest->lastReadDisplayChangeRequest.bpp;
937 }
938 else
939 {
940 /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
941 * read the last valid video mode hint. This happens when the guest X server
942 * determines the initial mode. */
943 displayChangeRequest->xres = pRequest->displayChangeRequest.xres;
944 displayChangeRequest->yres = pRequest->displayChangeRequest.yres;
945 displayChangeRequest->bpp = pRequest->displayChangeRequest.bpp;
946 }
947 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d\n",
948 displayChangeRequest->xres, displayChangeRequest->yres, displayChangeRequest->bpp));
949
950 pRequestHeader->rc = VINF_SUCCESS;
951 }
952 break;
953 }
954
955 case VMMDevReq_GetDisplayChangeRequest2:
956 {
957 if (pRequestHeader->size != sizeof(VMMDevDisplayChangeRequest2))
958 {
959 pRequestHeader->rc = VERR_INVALID_PARAMETER;
960 }
961 else
962 {
963 VMMDevDisplayChangeRequest2 *displayChangeRequest = (VMMDevDisplayChangeRequest2*)pRequestHeader;
964
965 DISPLAYCHANGEREQUEST *pRequest = NULL;
966
967 if (displayChangeRequest->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
968 {
969 /* Select a pending request to report. */
970 unsigned i;
971 for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
972 {
973 if (pThis->displayChangeData.aRequests[i].fPending)
974 {
975 pRequest = &pThis->displayChangeData.aRequests[i];
976 /* Remember which request should be reported. */
977 pThis->displayChangeData.iCurrentMonitor = i;
978 Log3(("VMMDev: will report pending request for %d\n",
979 i));
980 break;
981 }
982 }
983
984 /* Check if there are more pending requests. */
985 i++;
986 for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
987 {
988 if (pThis->displayChangeData.aRequests[i].fPending)
989 {
990 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
991 Log3(("VMMDev: another pending at %d\n",
992 i));
993 break;
994 }
995 }
996
997 if (pRequest)
998 {
999 /* Current request has been read at least once. */
1000 pRequest->fPending = false;
1001
1002 /* Remember which resolution the client has queried, subsequent reads
1003 * will return the same values. */
1004 pRequest->lastReadDisplayChangeRequest = pRequest->displayChangeRequest;
1005 pThis->displayChangeData.fGuestSentChangeEventAck = true;
1006 }
1007 else
1008 {
1009 Log3(("VMMDev: no pending request!!!\n"));
1010 }
1011 }
1012
1013 if (!pRequest)
1014 {
1015 Log3(("VMMDev: default to %d\n",
1016 pThis->displayChangeData.iCurrentMonitor));
1017 pRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
1018 }
1019
1020 if (pThis->displayChangeData.fGuestSentChangeEventAck)
1021 {
1022 displayChangeRequest->xres = pRequest->lastReadDisplayChangeRequest.xres;
1023 displayChangeRequest->yres = pRequest->lastReadDisplayChangeRequest.yres;
1024 displayChangeRequest->bpp = pRequest->lastReadDisplayChangeRequest.bpp;
1025 displayChangeRequest->display = pRequest->lastReadDisplayChangeRequest.display;
1026 }
1027 else
1028 {
1029 /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
1030 * read the last valid video mode hint. This happens when the guest X server
1031 * determines the initial video mode. */
1032 displayChangeRequest->xres = pRequest->displayChangeRequest.xres;
1033 displayChangeRequest->yres = pRequest->displayChangeRequest.yres;
1034 displayChangeRequest->bpp = pRequest->displayChangeRequest.bpp;
1035 displayChangeRequest->display = pRequest->displayChangeRequest.display;
1036 }
1037 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d at %d\n",
1038 displayChangeRequest->xres, displayChangeRequest->yres, displayChangeRequest->bpp, displayChangeRequest->display));
1039
1040 pRequestHeader->rc = VINF_SUCCESS;
1041 }
1042 break;
1043 }
1044
1045 /*
1046 * Query whether the given video mode is supported
1047 */
1048 case VMMDevReq_VideoModeSupported:
1049 {
1050 if (pRequestHeader->size != sizeof(VMMDevVideoModeSupportedRequest))
1051 {
1052 AssertMsgFailed(("VMMDev video mode supported request structure has invalid size!\n"));
1053 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1054 }
1055 else
1056 {
1057 VMMDevVideoModeSupportedRequest *videoModeSupportedRequest = (VMMDevVideoModeSupportedRequest*)pRequestHeader;
1058 /* forward the call */
1059 pRequestHeader->rc = pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
1060 0, /* primary screen. */
1061 videoModeSupportedRequest->width,
1062 videoModeSupportedRequest->height,
1063 videoModeSupportedRequest->bpp,
1064 &videoModeSupportedRequest->fSupported);
1065 }
1066 break;
1067 }
1068
1069 /*
1070 * Query whether the given video mode is supported for a specific display
1071 */
1072 case VMMDevReq_VideoModeSupported2:
1073 {
1074 if (pRequestHeader->size != sizeof(VMMDevVideoModeSupportedRequest2))
1075 {
1076 AssertMsgFailed(("VMMDev video mode supported request 2 structure has invalid size!\n"));
1077 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1078 }
1079 else
1080 {
1081 VMMDevVideoModeSupportedRequest2 *videoModeSupportedRequest2 = (VMMDevVideoModeSupportedRequest2*)pRequestHeader;
1082 /* forward the call */
1083 pRequestHeader->rc = pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
1084 videoModeSupportedRequest2->display,
1085 videoModeSupportedRequest2->width,
1086 videoModeSupportedRequest2->height,
1087 videoModeSupportedRequest2->bpp,
1088 &videoModeSupportedRequest2->fSupported);
1089 }
1090 break;
1091 }
1092
1093 /*
1094 * Query the height reduction in pixels
1095 */
1096 case VMMDevReq_GetHeightReduction:
1097 {
1098 if (pRequestHeader->size != sizeof(VMMDevGetHeightReductionRequest))
1099 {
1100 AssertMsgFailed(("VMMDev height reduction request structure has invalid size!\n"));
1101 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1102 }
1103 else
1104 {
1105 VMMDevGetHeightReductionRequest *heightReductionRequest = (VMMDevGetHeightReductionRequest*)pRequestHeader;
1106 /* forward the call */
1107 pRequestHeader->rc = pThis->pDrv->pfnGetHeightReduction(pThis->pDrv,
1108 &heightReductionRequest->heightReduction);
1109 }
1110 break;
1111 }
1112
1113 /*
1114 * Acknowledge VMMDev events
1115 */
1116 case VMMDevReq_AcknowledgeEvents:
1117 {
1118 if (pRequestHeader->size != sizeof(VMMDevEvents))
1119 {
1120 AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
1121 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1122 }
1123 else
1124 {
1125 if (VBOX_GUEST_ADDITIONS_VERSION_1_03 (pThis))
1126 {
1127 vmmdevSetIRQ_Legacy_EMT (pThis);
1128 }
1129 else
1130 {
1131 VMMDevEvents *pAckRequest;
1132
1133 if (pThis->fNewGuestFilterMask)
1134 {
1135 pThis->fNewGuestFilterMask = false;
1136 pThis->u32GuestFilterMask = pThis->u32NewGuestFilterMask;
1137 }
1138
1139 pAckRequest = (VMMDevEvents *)pRequestHeader;
1140 pAckRequest->events =
1141 pThis->u32HostEventFlags & pThis->u32GuestFilterMask;
1142
1143 pThis->u32HostEventFlags &= ~pThis->u32GuestFilterMask;
1144 pThis->pVMMDevRAMR3->V.V1_04.fHaveEvents = false;
1145 PDMDevHlpPCISetIrqNoWait (pThis->pDevIns, 0, 0);
1146 }
1147 pRequestHeader->rc = VINF_SUCCESS;
1148 }
1149 break;
1150 }
1151
1152 /*
1153 * Change guest filter mask
1154 */
1155 case VMMDevReq_CtlGuestFilterMask:
1156 {
1157 if (pRequestHeader->size != sizeof(VMMDevCtlGuestFilterMask))
1158 {
1159 AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
1160 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1161 }
1162 else
1163 {
1164 VMMDevCtlGuestFilterMask *pCtlMaskRequest;
1165
1166 pCtlMaskRequest = (VMMDevCtlGuestFilterMask *)pRequestHeader;
1167 LogRelFlowFunc(("VMMDevCtlGuestFilterMask: or mask: 0x%x, not mask: 0x%x\n",
1168 pCtlMaskRequest->u32OrMask,
1169 pCtlMaskRequest->u32NotMask));
1170 /* HGCM event notification is enabled by the VMMDev device
1171 * automatically when any HGCM command is issued. The guest
1172 * cannot disable these notifications.
1173 */
1174 VMMDevCtlSetGuestFilterMask (pThis,
1175 pCtlMaskRequest->u32OrMask,
1176 pCtlMaskRequest->u32NotMask & ~VMMDEV_EVENT_HGCM);
1177 pRequestHeader->rc = VINF_SUCCESS;
1178
1179 }
1180 break;
1181 }
1182
1183#ifdef VBOX_WITH_HGCM
1184 /*
1185 * Process HGCM request
1186 */
1187 case VMMDevReq_HGCMConnect:
1188 {
1189 if (pRequestHeader->size < sizeof(VMMDevHGCMConnect))
1190 {
1191 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
1192 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1193 }
1194 else if (!pThis->pHGCMDrv)
1195 {
1196 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
1197 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1198 }
1199 else
1200 {
1201 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)pRequestHeader;
1202
1203 Log(("VMMDevReq_HGCMConnect\n"));
1204
1205 pRequestHeader->rc = vmmdevHGCMConnect (pThis, pHGCMConnect, (RTGCPHYS)u32);
1206 }
1207 break;
1208 }
1209
1210 case VMMDevReq_HGCMDisconnect:
1211 {
1212 if (pRequestHeader->size < sizeof(VMMDevHGCMDisconnect))
1213 {
1214 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
1215 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1216 }
1217 else if (!pThis->pHGCMDrv)
1218 {
1219 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
1220 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1221 }
1222 else
1223 {
1224 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)pRequestHeader;
1225
1226 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
1227 pRequestHeader->rc = vmmdevHGCMDisconnect (pThis, pHGCMDisconnect, (RTGCPHYS)u32);
1228 }
1229 break;
1230 }
1231
1232#ifdef VBOX_WITH_64_BITS_GUESTS
1233 case VMMDevReq_HGCMCall32:
1234 case VMMDevReq_HGCMCall64:
1235#else
1236 case VMMDevReq_HGCMCall:
1237#endif /* VBOX_WITH_64_BITS_GUESTS */
1238 {
1239 if (pRequestHeader->size < sizeof(VMMDevHGCMCall))
1240 {
1241 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
1242 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1243 }
1244 else if (!pThis->pHGCMDrv)
1245 {
1246 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
1247 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1248 }
1249 else
1250 {
1251 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pRequestHeader;
1252
1253 Log2(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
1254 Log2(("%.*Rhxd\n", pRequestHeader->size, pRequestHeader));
1255
1256#ifdef VBOX_WITH_64_BITS_GUESTS
1257 bool f64Bits = (pRequestHeader->requestType == VMMDevReq_HGCMCall64);
1258#else
1259 bool f64Bits = false;
1260#endif /* VBOX_WITH_64_BITS_GUESTS */
1261
1262 pRequestHeader->rc = vmmdevHGCMCall (pThis, pHGCMCall, requestHeader.size, (RTGCPHYS)u32, f64Bits);
1263 }
1264 break;
1265 }
1266#endif /* VBOX_WITH_HGCM */
1267
1268 case VMMDevReq_HGCMCancel:
1269 {
1270 if (pRequestHeader->size < sizeof(VMMDevHGCMCancel))
1271 {
1272 AssertMsgFailed(("VMMDevReq_HGCMCancel structure has invalid size!\n"));
1273 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1274 }
1275 else if (!pThis->pHGCMDrv)
1276 {
1277 Log(("VMMDevReq_HGCMCancel HGCM Connector is NULL!\n"));
1278 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1279 }
1280 else
1281 {
1282 VMMDevHGCMCancel *pHGCMCancel = (VMMDevHGCMCancel *)pRequestHeader;
1283
1284 Log(("VMMDevReq_VMMDevHGCMCancel\n"));
1285 pRequestHeader->rc = vmmdevHGCMCancel (pThis, pHGCMCancel, (RTGCPHYS)u32);
1286 }
1287 break;
1288 }
1289
1290 case VMMDevReq_HGCMCancel2:
1291 {
1292 if (pRequestHeader->size != sizeof(VMMDevHGCMCancel2))
1293 {
1294 AssertMsgFailed(("VMMDevReq_HGCMCancel structure has invalid size!\n"));
1295 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1296 }
1297 else if (!pThis->pHGCMDrv)
1298 {
1299 Log(("VMMDevReq_HGCMCancel HGCM Connector is NULL!\n"));
1300 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1301 }
1302 else
1303 {
1304 VMMDevHGCMCancel2 *pHGCMCancel2 = (VMMDevHGCMCancel2 *)pRequestHeader;
1305
1306 Log(("VMMDevReq_VMMDevHGCMCancel\n"));
1307 pRequestHeader->rc = vmmdevHGCMCancel2 (pThis, pHGCMCancel2->physReqToCancel);
1308 }
1309 break;
1310 }
1311
1312 case VMMDevReq_VideoAccelEnable:
1313 {
1314 if (pRequestHeader->size < sizeof(VMMDevVideoAccelEnable))
1315 {
1316 Log(("VMMDevReq_VideoAccelEnable request size too small!!!\n"));
1317 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1318 }
1319 else if (!pThis->pDrv)
1320 {
1321 Log(("VMMDevReq_VideoAccelEnable Connector is NULL!!!\n"));
1322 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1323 }
1324 else
1325 {
1326 VMMDevVideoAccelEnable *ptr = (VMMDevVideoAccelEnable *)pRequestHeader;
1327
1328 if (ptr->cbRingBuffer != VBVA_RING_BUFFER_SIZE)
1329 {
1330 /* The guest driver seems compiled with another headers. */
1331 Log(("VMMDevReq_VideoAccelEnable guest ring buffer size %d, should be %d!!!\n", ptr->cbRingBuffer, VBVA_RING_BUFFER_SIZE));
1332 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1333 }
1334 else
1335 {
1336 /* The request is correct. */
1337 ptr->fu32Status |= VBVA_F_STATUS_ACCEPTED;
1338
1339 LogFlow(("VMMDevReq_VideoAccelEnable ptr->u32Enable = %d\n", ptr->u32Enable));
1340
1341 pRequestHeader->rc = ptr->u32Enable?
1342 pThis->pDrv->pfnVideoAccelEnable (pThis->pDrv, true, &pThis->pVMMDevRAMR3->vbvaMemory):
1343 pThis->pDrv->pfnVideoAccelEnable (pThis->pDrv, false, NULL);
1344
1345 if ( ptr->u32Enable
1346 && RT_SUCCESS (pRequestHeader->rc))
1347 {
1348 ptr->fu32Status |= VBVA_F_STATUS_ENABLED;
1349
1350 /* Remember that guest successfully enabled acceleration.
1351 * We need to reestablish it on restoring the VM from saved state.
1352 */
1353 pThis->u32VideoAccelEnabled = 1;
1354 }
1355 else
1356 {
1357 /* The acceleration was not enabled. Remember that. */
1358 pThis->u32VideoAccelEnabled = 0;
1359 }
1360 }
1361 }
1362 break;
1363 }
1364
1365 case VMMDevReq_VideoAccelFlush:
1366 {
1367 if (pRequestHeader->size < sizeof(VMMDevVideoAccelFlush))
1368 {
1369 AssertMsgFailed(("VMMDevReq_VideoAccelFlush request size too small.\n"));
1370 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1371 }
1372 else if (!pThis->pDrv)
1373 {
1374 Log(("VMMDevReq_VideoAccelFlush Connector is NULL!\n"));
1375 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1376 }
1377 else
1378 {
1379 pThis->pDrv->pfnVideoAccelFlush (pThis->pDrv);
1380
1381 pRequestHeader->rc = VINF_SUCCESS;
1382 }
1383 break;
1384 }
1385
1386 case VMMDevReq_VideoSetVisibleRegion:
1387 {
1388 if (pRequestHeader->size < sizeof(VMMDevVideoSetVisibleRegion))
1389 {
1390 Log(("VMMDevReq_VideoSetVisibleRegion request size too small!!!\n"));
1391 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1392 }
1393 else if (!pThis->pDrv)
1394 {
1395 Log(("VMMDevReq_VideoSetVisibleRegion Connector is NULL!!!\n"));
1396 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1397 }
1398 else
1399 {
1400 VMMDevVideoSetVisibleRegion *ptr = (VMMDevVideoSetVisibleRegion *)pRequestHeader;
1401
1402 if (!ptr->cRect)
1403 {
1404 Log(("VMMDevReq_VideoSetVisibleRegion no rectangles!!!\n"));
1405 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1406 }
1407 else
1408 if (pRequestHeader->size != sizeof(VMMDevVideoSetVisibleRegion) + (ptr->cRect-1)*sizeof(RTRECT))
1409 {
1410 Log(("VMMDevReq_VideoSetVisibleRegion request size too small!!!\n"));
1411 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1412 }
1413 else
1414 {
1415 Log(("VMMDevReq_VideoSetVisibleRegion %d rectangles\n", ptr->cRect));
1416 /* forward the call */
1417 pRequestHeader->rc = pThis->pDrv->pfnSetVisibleRegion(pThis->pDrv, ptr->cRect, &ptr->Rect);
1418 }
1419 }
1420 break;
1421 }
1422
1423 case VMMDevReq_GetSeamlessChangeRequest:
1424 {
1425 if (pRequestHeader->size != sizeof(VMMDevSeamlessChangeRequest))
1426 {
1427 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1428 }
1429 else
1430 {
1431 VMMDevSeamlessChangeRequest *seamlessChangeRequest = (VMMDevSeamlessChangeRequest*)pRequestHeader;
1432 /* just pass on the information */
1433 Log(("VMMDev: returning seamless change request mode=%d\n", pThis->fSeamlessEnabled));
1434 if (pThis->fSeamlessEnabled)
1435 seamlessChangeRequest->mode = VMMDev_Seamless_Visible_Region;
1436 else
1437 seamlessChangeRequest->mode = VMMDev_Seamless_Disabled;
1438
1439 if (seamlessChangeRequest->eventAck == VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
1440 {
1441 /* Remember which mode the client has queried. */
1442 pThis->fLastSeamlessEnabled = pThis->fSeamlessEnabled;
1443 }
1444
1445 pRequestHeader->rc = VINF_SUCCESS;
1446 }
1447 break;
1448 }
1449
1450 case VMMDevReq_GetVRDPChangeRequest:
1451 {
1452 if (pRequestHeader->size != sizeof(VMMDevVRDPChangeRequest))
1453 {
1454 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1455 }
1456 else
1457 {
1458 VMMDevVRDPChangeRequest *vrdpChangeRequest = (VMMDevVRDPChangeRequest*)pRequestHeader;
1459 /* just pass on the information */
1460 Log(("VMMDev: returning VRDP status %d level %d\n", pThis->fVRDPEnabled, pThis->u32VRDPExperienceLevel));
1461
1462 vrdpChangeRequest->u8VRDPActive = pThis->fVRDPEnabled;
1463 vrdpChangeRequest->u32VRDPExperienceLevel = pThis->u32VRDPExperienceLevel;
1464
1465 pRequestHeader->rc = VINF_SUCCESS;
1466 }
1467 break;
1468 }
1469
1470 case VMMDevReq_GetMemBalloonChangeRequest:
1471 {
1472 Log(("VMMDevReq_GetMemBalloonChangeRequest\n"));
1473 if (pRequestHeader->size != sizeof(VMMDevGetMemBalloonChangeRequest))
1474 {
1475 AssertFailed();
1476 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1477 }
1478 else
1479 {
1480 VMMDevGetMemBalloonChangeRequest *memBalloonChangeRequest = (VMMDevGetMemBalloonChangeRequest*)pRequestHeader;
1481 /* just pass on the information */
1482 Log(("VMMDev: returning memory balloon size =%d\n", pThis->u32MemoryBalloonSize));
1483 memBalloonChangeRequest->cBalloonChunks = pThis->u32MemoryBalloonSize;
1484 memBalloonChangeRequest->cPhysMemChunks = pThis->cbGuestRAM / (uint64_t)_1M;
1485
1486 if (memBalloonChangeRequest->eventAck == VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
1487 {
1488 /* Remember which mode the client has queried. */
1489 pThis->u32LastMemoryBalloonSize = pThis->u32MemoryBalloonSize;
1490 }
1491
1492 pRequestHeader->rc = VINF_SUCCESS;
1493 }
1494 break;
1495 }
1496
1497 case VMMDevReq_ChangeMemBalloon:
1498 {
1499 VMMDevChangeMemBalloon *memBalloonChange = (VMMDevChangeMemBalloon*)pRequestHeader;
1500
1501 Log(("VMMDevReq_ChangeMemBalloon\n"));
1502 if ( pRequestHeader->size < sizeof(VMMDevChangeMemBalloon)
1503 || memBalloonChange->cPages != VMMDEV_MEMORY_BALLOON_CHUNK_PAGES
1504 || pRequestHeader->size != (uint32_t)RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[memBalloonChange->cPages]))
1505 {
1506 AssertFailed();
1507 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1508 }
1509 else
1510 {
1511 pRequestHeader->rc = PGMR3PhysChangeMemBalloon(PDMDevHlpGetVM(pDevIns), !!memBalloonChange->fInflate, memBalloonChange->cPages, memBalloonChange->aPhysPage);
1512 if (memBalloonChange->fInflate)
1513 STAM_REL_U32_INC(&pThis->StatMemBalloonChunks);
1514 else
1515 STAM_REL_U32_DEC(&pThis->StatMemBalloonChunks);
1516 }
1517 break;
1518 }
1519
1520 case VMMDevReq_GetStatisticsChangeRequest:
1521 {
1522 Log(("VMMDevReq_GetStatisticsChangeRequest\n"));
1523 if (pRequestHeader->size != sizeof(VMMDevGetStatisticsChangeRequest))
1524 {
1525 AssertFailed();
1526 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1527 }
1528 else
1529 {
1530 VMMDevGetStatisticsChangeRequest *statIntervalChangeRequest = (VMMDevGetStatisticsChangeRequest*)pRequestHeader;
1531 /* just pass on the information */
1532 Log(("VMMDev: returning statistics interval %d seconds\n", pThis->u32StatIntervalSize));
1533 statIntervalChangeRequest->u32StatInterval = pThis->u32StatIntervalSize;
1534
1535 if (statIntervalChangeRequest->eventAck == VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)
1536 {
1537 /* Remember which mode the client has queried. */
1538 pThis->u32LastStatIntervalSize= pThis->u32StatIntervalSize;
1539 }
1540
1541 pRequestHeader->rc = VINF_SUCCESS;
1542 }
1543 break;
1544 }
1545
1546 case VMMDevReq_ReportGuestStats:
1547 {
1548 Log(("VMMDevReq_ReportGuestStats\n"));
1549 if (pRequestHeader->size != sizeof(VMMDevReportGuestStats))
1550 {
1551 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1552 }
1553 else
1554 {
1555 VMMDevReportGuestStats *stats = (VMMDevReportGuestStats*)pRequestHeader;
1556
1557#ifdef DEBUG
1558 VBoxGuestStatistics *pGuestStats = &stats->guestStats;
1559
1560 Log(("Current statistics:\n"));
1561 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_IDLE)
1562 Log(("CPU%d: CPU Load Idle %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Idle));
1563
1564 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_KERNEL)
1565 Log(("CPU%d: CPU Load Kernel %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Kernel));
1566
1567 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_USER)
1568 Log(("CPU%d: CPU Load User %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_User));
1569
1570 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_THREADS)
1571 Log(("CPU%d: Thread %d\n", pGuestStats->u32CpuId, pGuestStats->u32Threads));
1572
1573 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PROCESSES)
1574 Log(("CPU%d: Processes %d\n", pGuestStats->u32CpuId, pGuestStats->u32Processes));
1575
1576 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_HANDLES)
1577 Log(("CPU%d: Handles %d\n", pGuestStats->u32CpuId, pGuestStats->u32Handles));
1578
1579 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEMORY_LOAD)
1580 Log(("CPU%d: Memory Load %d%%\n", pGuestStats->u32CpuId, pGuestStats->u32MemoryLoad));
1581
1582 /* Note that reported values are in pages; upper layers expect them in megabytes */
1583 Log(("CPU%d: Page size %-4d bytes\n", pGuestStats->u32CpuId, pGuestStats->u32PageSize));
1584 Assert(pGuestStats->u32PageSize == 4096);
1585
1586 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_TOTAL)
1587 Log(("CPU%d: Total physical memory %-4d MB\n", pGuestStats->u32CpuId, (pGuestStats->u32PhysMemTotal + (_1M/_4K)-1) / (_1M/_4K)));
1588
1589 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_AVAIL)
1590 Log(("CPU%d: Free physical memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemAvail / (_1M/_4K)));
1591
1592 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON)
1593 Log(("CPU%d: Memory balloon size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemBalloon / (_1M/_4K)));
1594
1595 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_COMMIT_TOTAL)
1596 Log(("CPU%d: Committed memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemCommitTotal / (_1M/_4K)));
1597
1598 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_TOTAL)
1599 Log(("CPU%d: Total kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelTotal / (_1M/_4K)));
1600
1601 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_PAGED)
1602 Log(("CPU%d: Paged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelPaged / (_1M/_4K)));
1603
1604 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED)
1605 Log(("CPU%d: Nonpaged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelNonPaged / (_1M/_4K)));
1606
1607 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE)
1608 Log(("CPU%d: System cache size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemSystemCache / (_1M/_4K)));
1609
1610 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE)
1611 Log(("CPU%d: Page file size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PageFileSize / (_1M/_4K)));
1612 Log(("Statistics end *******************\n"));
1613#endif
1614
1615 /* forward the call */
1616 pRequestHeader->rc = pThis->pDrv->pfnReportStatistics(pThis->pDrv, &stats->guestStats);
1617 }
1618 break;
1619 }
1620
1621 case VMMDevReq_QueryCredentials:
1622 {
1623 if (pRequestHeader->size != sizeof(VMMDevCredentials))
1624 {
1625 AssertMsgFailed(("VMMDevReq_QueryCredentials request size too small.\n"));
1626 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1627 }
1628 else
1629 {
1630 VMMDevCredentials *credentials = (VMMDevCredentials*)pRequestHeader;
1631
1632 /* let's start by nulling out the data */
1633 memset(credentials->szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1634 memset(credentials->szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1635 memset(credentials->szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1636
1637 /* should we return whether we got credentials for a logon? */
1638 if (credentials->u32Flags & VMMDEV_CREDENTIALS_QUERYPRESENCE)
1639 {
1640 if ( pThis->pCredentials->Logon.szUserName[0]
1641 || pThis->pCredentials->Logon.szPassword[0]
1642 || pThis->pCredentials->Logon.szDomain[0])
1643 {
1644 credentials->u32Flags |= VMMDEV_CREDENTIALS_PRESENT;
1645 }
1646 else
1647 {
1648 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_PRESENT;
1649 }
1650 }
1651
1652 /* does the guest want to read logon credentials? */
1653 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READ)
1654 {
1655 if (pThis->pCredentials->Logon.szUserName[0])
1656 strcpy(credentials->szUserName, pThis->pCredentials->Logon.szUserName);
1657 if (pThis->pCredentials->Logon.szPassword[0])
1658 strcpy(credentials->szPassword, pThis->pCredentials->Logon.szPassword);
1659 if (pThis->pCredentials->Logon.szDomain[0])
1660 strcpy(credentials->szDomain, pThis->pCredentials->Logon.szDomain);
1661 if (!pThis->pCredentials->Logon.fAllowInteractiveLogon)
1662 credentials->u32Flags |= VMMDEV_CREDENTIALS_NOLOCALLOGON;
1663 else
1664 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_NOLOCALLOGON;
1665 }
1666
1667 if (!pThis->fKeepCredentials)
1668 {
1669 /* does the caller want us to destroy the logon credentials? */
1670 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEAR)
1671 {
1672 memset(pThis->pCredentials->Logon.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1673 memset(pThis->pCredentials->Logon.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1674 memset(pThis->pCredentials->Logon.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1675 }
1676 }
1677
1678 /* does the guest want to read credentials for verification? */
1679 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READJUDGE)
1680 {
1681 if (pThis->pCredentials->Judge.szUserName[0])
1682 strcpy(credentials->szUserName, pThis->pCredentials->Judge.szUserName);
1683 if (pThis->pCredentials->Judge.szPassword[0])
1684 strcpy(credentials->szPassword, pThis->pCredentials->Judge.szPassword);
1685 if (pThis->pCredentials->Judge.szDomain[0])
1686 strcpy(credentials->szDomain, pThis->pCredentials->Judge.szDomain);
1687 }
1688
1689 /* does the caller want us to destroy the judgement credentials? */
1690 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEARJUDGE)
1691 {
1692 memset(pThis->pCredentials->Judge.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1693 memset(pThis->pCredentials->Judge.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1694 memset(pThis->pCredentials->Judge.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1695 }
1696
1697 pRequestHeader->rc = VINF_SUCCESS;
1698 }
1699 break;
1700 }
1701
1702 case VMMDevReq_ReportCredentialsJudgement:
1703 {
1704 if (pRequestHeader->size != sizeof(VMMDevCredentials))
1705 {
1706 AssertMsgFailed(("VMMDevReq_ReportCredentialsJudgement request size too small.\n"));
1707 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1708 }
1709 else
1710 {
1711 VMMDevCredentials *credentials = (VMMDevCredentials*)pRequestHeader;
1712
1713 /* what does the guest think about the credentials? (note: the order is important here!) */
1714 if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_DENY)
1715 {
1716 pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_DENY);
1717 }
1718 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT)
1719 {
1720 pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT);
1721 }
1722 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_OK)
1723 {
1724 pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_OK);
1725 }
1726 else
1727 Log(("VMMDevReq_ReportCredentialsJudgement: invalid flags: %d!!!\n", credentials->u32Flags));
1728
1729 pRequestHeader->rc = VINF_SUCCESS;
1730 }
1731 break;
1732 }
1733
1734 /*
1735 * Implemented in 3.1.0.
1736 *
1737 * Note! The ring-0 VBoxGuestLib uses this to check whether
1738 * VMMDevHGCMParmType_PageList is supported.
1739 */
1740 case VMMDevReq_GetHostVersion:
1741 {
1742 AssertMsgBreakStmt(pRequestHeader->size == sizeof(VMMDevReqHostVersion),
1743 ("%#x < %#x\n", pRequestHeader->size, sizeof(VMMDevReqLogString)),
1744 pRequestHeader->rc = VERR_INVALID_PARAMETER);
1745 VMMDevReqHostVersion *pReqHostVer = (VMMDevReqHostVersion*)pRequestHeader;
1746 pReqHostVer->major = RTBldCfgVersionMajor();
1747 pReqHostVer->minor = RTBldCfgVersionMinor();
1748 pReqHostVer->build = RTBldCfgVersionBuild();
1749 pReqHostVer->revision = RTBldCfgRevision();
1750 pReqHostVer->features = VMMDEV_HVF_HGCM_PHYS_PAGE_LIST;
1751 pReqHostVer->header.rc = VINF_SUCCESS;
1752 break;
1753 }
1754
1755 case VMMDevReq_GetCpuHotPlugRequest:
1756 {
1757 VMMDevGetCpuHotPlugRequest *pReqCpuHotPlug = (VMMDevGetCpuHotPlugRequest *)pRequestHeader;
1758
1759 if (pRequestHeader->size != sizeof(VMMDevGetCpuHotPlugRequest))
1760 {
1761 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1762 }
1763 else
1764 {
1765 pReqCpuHotPlug->enmEventType = pThis->enmCpuHotPlugEvent;
1766 pReqCpuHotPlug->idCpuCore = pThis->idCpuCore;
1767 pReqCpuHotPlug->idCpuPackage = pThis->idCpuPackage;
1768 pReqCpuHotPlug->header.rc = VINF_SUCCESS;
1769
1770 /* Clear the event */
1771 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_None;
1772 pThis->idCpuCore = UINT32_MAX;
1773 pThis->idCpuPackage = UINT32_MAX;
1774 }
1775 break;
1776 }
1777
1778 case VMMDevReq_SetCpuHotPlugStatus:
1779 {
1780 VMMDevCpuHotPlugStatusRequest *pReqCpuHotPlugStatus = (VMMDevCpuHotPlugStatusRequest *)pRequestHeader;
1781
1782 if (pRequestHeader->size != sizeof(VMMDevCpuHotPlugStatusRequest))
1783 {
1784 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1785 }
1786 else
1787 {
1788 pRequestHeader->rc = VINF_SUCCESS;
1789
1790 if (pReqCpuHotPlugStatus->enmStatusType == VMMDevCpuStatusType_Disable)
1791 pThis->fCpuHotPlugEventsEnabled = false;
1792 else if (pReqCpuHotPlugStatus->enmStatusType == VMMDevCpuStatusType_Enable)
1793 pThis->fCpuHotPlugEventsEnabled = true;
1794 else
1795 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1796 }
1797 break;
1798 }
1799
1800#ifdef VBOX_WITH_PAGE_SHARING
1801 case VMMDevReq_RegisterSharedModule:
1802 {
1803 VMMDevSharedModuleRegistrationRequest *pReqModule = (VMMDevSharedModuleRegistrationRequest *)pRequestHeader;
1804
1805 if ( pRequestHeader->size < sizeof(VMMDevSharedModuleRegistrationRequest)
1806 || pRequestHeader->size != RT_UOFFSETOF(VMMDevSharedModuleRegistrationRequest, aRegions[pReqModule->cRegions]))
1807 {
1808 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1809 }
1810 else
1811 {
1812 pRequestHeader->rc = PGMR3SharedModuleRegister(PDMDevHlpGetVM(pDevIns), pReqModule->enmGuestOS, pReqModule->szName, pReqModule->szVersion,
1813 pReqModule->GCBaseAddr, pReqModule->cbModule,
1814 pReqModule->cRegions, pReqModule->aRegions);
1815 }
1816 break;
1817 }
1818
1819 case VMMDevReq_UnregisterSharedModule:
1820 {
1821 VMMDevSharedModuleUnregistrationRequest *pReqModule = (VMMDevSharedModuleUnregistrationRequest *)pRequestHeader;
1822
1823 if (pRequestHeader->size != sizeof(VMMDevSharedModuleUnregistrationRequest))
1824 {
1825 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1826 }
1827 else
1828 {
1829 pRequestHeader->rc = PGMR3SharedModuleUnregister(PDMDevHlpGetVM(pDevIns), pReqModule->szName, pReqModule->szVersion,
1830 pReqModule->GCBaseAddr, pReqModule->cbModule);
1831 }
1832 break;
1833 }
1834
1835 case VMMDevReq_CheckSharedModules:
1836 {
1837 VMMDevSharedModuleCheckRequest *pReqModule = (VMMDevSharedModuleCheckRequest *)pRequestHeader;
1838
1839 if (pRequestHeader->size != sizeof(VMMDevSharedModuleCheckRequest))
1840 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1841 else
1842 pRequestHeader->rc = PGMR3SharedModuleCheckAll(PDMDevHlpGetVM(pDevIns));
1843 break;
1844 }
1845
1846 case VMMDevReq_GetPageSharingStatus:
1847 {
1848 VMMDevPageSharingStatusRequest *pReqStatus = (VMMDevPageSharingStatusRequest *)pRequestHeader;
1849
1850 if (pRequestHeader->size != sizeof(VMMDevPageSharingStatusRequest))
1851 {
1852 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1853 }
1854 else
1855 {
1856 pReqStatus->fEnabled = false;
1857 pThis->pDrv->pfnIsPageFusionEnabled(pThis->pDrv, &pReqStatus->fEnabled);
1858 pRequestHeader->rc = VINF_SUCCESS;
1859 }
1860 break;
1861 }
1862
1863 case VMMDevReq_DebugIsPageShared:
1864 {
1865# ifdef DEBUG
1866 VMMDevPageIsSharedRequest *pReq = (VMMDevPageIsSharedRequest *)pRequestHeader;
1867
1868 if (pRequestHeader->size != sizeof(VMMDevPageIsSharedRequest))
1869 {
1870 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1871 }
1872 else
1873 {
1874 pRequestHeader->rc = PGMR3SharedModuleGetPageState(PDMDevHlpGetVM(pDevIns), pReq->GCPtrPage, &pReq->fShared, &pReq->uPageFlags);
1875 }
1876# else
1877 pRequestHeader->rc = VERR_NOT_IMPLEMENTED;
1878# endif
1879 break;
1880 }
1881
1882#endif
1883
1884#ifdef DEBUG
1885 case VMMDevReq_LogString:
1886 {
1887 if (pRequestHeader->size < sizeof(VMMDevReqLogString))
1888 {
1889 AssertMsgFailed(("VMMDevReq_LogString request size too small.\n"));
1890 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1891 }
1892 else
1893 {
1894 VMMDevReqLogString *pReqLogString = (VMMDevReqLogString *)pRequestHeader;
1895 LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR,
1896 ("DEBUG LOG: %s", pReqLogString->szString));
1897 pRequestHeader->rc = VINF_SUCCESS;
1898 }
1899 break;
1900 }
1901#endif
1902
1903 /*
1904 * Get a unique session id for this VM; the id will be different after each start, reset or restore of the VM
1905 * This can be used for restore detection inside the guest.
1906 */
1907 case VMMDevReq_GetSessionId:
1908 {
1909 if (pRequestHeader->size != sizeof(VMMDevReqSessionId))
1910 {
1911 AssertMsgFailed(("VMMDevReq_GetSessionId request size too small.\n"));
1912 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1913 }
1914 else
1915 {
1916 VMMDevReqSessionId *pReq = (VMMDevReqSessionId *)pRequestHeader;
1917 pReq->idSession = pThis->idSession;
1918 pRequestHeader->rc = VINF_SUCCESS;
1919 }
1920 break;
1921 }
1922
1923 default:
1924 {
1925 pRequestHeader->rc = VERR_NOT_IMPLEMENTED;
1926 Log(("VMMDev unknown request type %d\n", pRequestHeader->requestType));
1927 break;
1928 }
1929 }
1930
1931end:
1932 /* Write the result back to guest memory */
1933 if (pRequestHeader)
1934 {
1935 PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)u32, pRequestHeader, pRequestHeader->size);
1936 RTMemFree(pRequestHeader);
1937 }
1938 else
1939 {
1940 /* early error case; write back header only */
1941 PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)u32, &requestHeader, sizeof(requestHeader));
1942 }
1943
1944 PDMCritSectLeave(&pThis->CritSect);
1945 return rcRet;
1946}
1947
1948/**
1949 * Callback function for mapping an PCI I/O region.
1950 *
1951 * @return VBox status code.
1952 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1953 * @param iRegion The region number.
1954 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1955 * I/O port, else it's a physical address.
1956 * This address is *NOT* relative to pci_mem_base like earlier!
1957 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1958 */
1959static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1960{
1961 LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%RGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
1962 VMMDevState *pThis = PCIDEV_2_VMMDEVSTATE(pPciDev);
1963 int rc;
1964
1965 if (iRegion == 1)
1966 {
1967 AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM, VERR_INTERNAL_ERROR);
1968 Assert(pThis->pVMMDevRAMR3 != NULL);
1969 if (GCPhysAddress != NIL_RTGCPHYS)
1970 {
1971 /*
1972 * Map the MMIO2 memory.
1973 */
1974 pThis->GCPhysVMMDevRAM = GCPhysAddress;
1975 Assert(pThis->GCPhysVMMDevRAM == GCPhysAddress);
1976 rc = PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
1977 }
1978 else
1979 {
1980 /*
1981 * It is about to be unmapped, just clean up.
1982 */
1983 pThis->GCPhysVMMDevRAM = NIL_RTGCPHYS32;
1984 rc = VINF_SUCCESS;
1985 }
1986 }
1987 else if (iRegion == 2)
1988 {
1989 AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR);
1990 Assert(pThis->pVMMDevHeapR3 != NULL);
1991 if (GCPhysAddress != NIL_RTGCPHYS)
1992 {
1993 /*
1994 * Map the MMIO2 memory.
1995 */
1996 pThis->GCPhysVMMDevHeap = GCPhysAddress;
1997 Assert(pThis->GCPhysVMMDevHeap == GCPhysAddress);
1998 rc = PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
1999 if (RT_SUCCESS(rc))
2000 rc = PDMDevHlpRegisterVMMDevHeap(pPciDev->pDevIns, GCPhysAddress, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
2001 }
2002 else
2003 {
2004 /*
2005 * It is about to be unmapped, just clean up.
2006 */
2007 PDMDevHlpUnregisterVMMDevHeap(pPciDev->pDevIns, pThis->GCPhysVMMDevHeap);
2008 pThis->GCPhysVMMDevHeap = NIL_RTGCPHYS32;
2009 rc = VINF_SUCCESS;
2010 }
2011 }
2012 else
2013 {
2014 AssertMsgFailed(("%d\n", iRegion));
2015 rc = VERR_INVALID_PARAMETER;
2016 }
2017
2018 return rc;
2019}
2020
2021
2022/**
2023 * Callback function for mapping a PCI I/O region.
2024 *
2025 * @return VBox status code.
2026 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
2027 * @param iRegion The region number.
2028 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
2029 * I/O port, else it's a physical address.
2030 * This address is *NOT* relative to pci_mem_base like earlier!
2031 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
2032 */
2033static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2034{
2035 VMMDevState *pThis = PCIDEV_2_VMMDEVSTATE(pPciDev);
2036 int rc = VINF_SUCCESS;
2037
2038 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2039 Assert(iRegion == 0);
2040 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
2041
2042 /*
2043 * Save the base port address to simplify Port offset calculations.
2044 */
2045 pThis->PortBase = (RTIOPORT)GCPhysAddress;
2046
2047 /*
2048 * Register our port IO handlers.
2049 */
2050 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns,
2051 (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST, 1,
2052 (void*)pThis, vmmdevRequestHandler,
2053 NULL, NULL, NULL, "VMMDev Request Handler");
2054 AssertRC(rc);
2055 return rc;
2056}
2057
2058/**
2059 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2060 */
2061static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2062{
2063 VMMDevState *pThis = RT_FROM_MEMBER(pInterface, VMMDevState, IBase);
2064
2065 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2066 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVMMDEVPORT, &pThis->IPort);
2067#ifdef VBOX_WITH_HGCM
2068 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHGCMPORT, &pThis->IHGCMPort);
2069#endif
2070 /* Currently only for shared folders. */
2071 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->SharedFolders.ILeds);
2072 return NULL;
2073}
2074
2075/**
2076 * Gets the pointer to the status LED of a unit.
2077 *
2078 * @returns VBox status code.
2079 * @param pInterface Pointer to the interface structure containing the called function pointer.
2080 * @param iLUN The unit which status LED we desire.
2081 * @param ppLed Where to store the LED pointer.
2082 */
2083static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
2084{
2085 VMMDevState *pThis = (VMMDevState *)( (uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, SharedFolders.ILeds) );
2086 if (iLUN == 0) /* LUN 0 is shared folders */
2087 {
2088 *ppLed = &pThis->SharedFolders.Led;
2089 return VINF_SUCCESS;
2090 }
2091 return VERR_PDM_LUN_NOT_FOUND;
2092}
2093
2094/* -=-=-=-=-=- IVMMDevPort -=-=-=-=-=- */
2095
2096/** Converts a VMMDev port interface pointer to a VMMDev state pointer. */
2097#define IVMMDEVPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, IPort)) )
2098
2099
2100/**
2101 * Return the current absolute mouse position in pixels
2102 *
2103 * @returns VBox status code
2104 * @param pAbsX Pointer of result value, can be NULL
2105 * @param pAbsY Pointer of result value, can be NULL
2106 */
2107static DECLCALLBACK(int) vmmdevQueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t *pAbsX, uint32_t *pAbsY)
2108{
2109 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2110 AssertCompile(sizeof(pThis->mouseXAbs) == sizeof(*pAbsX));
2111 AssertCompile(sizeof(pThis->mouseYAbs) == sizeof(*pAbsY));
2112 if (pAbsX)
2113 ASMAtomicReadSize(&pThis->mouseXAbs, pAbsX);
2114 if (pAbsY)
2115 ASMAtomicReadSize(&pThis->mouseYAbs, pAbsY);
2116 return VINF_SUCCESS;
2117}
2118
2119/**
2120 * Set the new absolute mouse position in pixels
2121 *
2122 * @returns VBox status code
2123 * @param absX New absolute X position
2124 * @param absY New absolute Y position
2125 */
2126static DECLCALLBACK(int) vmmdevSetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t absX, uint32_t absY)
2127{
2128 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2129 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2130
2131 if ((pThis->mouseXAbs == absX) && (pThis->mouseYAbs == absY))
2132 {
2133 PDMCritSectLeave(&pThis->CritSect);
2134 return VINF_SUCCESS;
2135 }
2136 Log2(("vmmdevSetAbsoluteMouse: settings absolute position to x = %d, y = %d\n", absX, absY));
2137 pThis->mouseXAbs = absX;
2138 pThis->mouseYAbs = absY;
2139 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
2140 PDMCritSectLeave(&pThis->CritSect);
2141 return VINF_SUCCESS;
2142}
2143
2144/**
2145 * Return the current mouse capability flags
2146 *
2147 * @returns VBox status code
2148 * @param pCapabilities Pointer of result value
2149 */
2150static DECLCALLBACK(int) vmmdevQueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pCapabilities)
2151{
2152 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2153 if (!pCapabilities)
2154 return VERR_INVALID_PARAMETER;
2155 *pCapabilities = pThis->mouseCapabilities;
2156 return VINF_SUCCESS;
2157}
2158
2159/**
2160 * Set the current mouse capability flag (host side)
2161 *
2162 * @returns VBox status code
2163 * @param capabilities Capability mask
2164 */
2165static DECLCALLBACK(int) vmmdevSetMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t capabilities)
2166{
2167 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2168 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2169
2170 bool bNotify = ( (capabilities & VMMDEV_MOUSE_NOTIFY_GUEST_MASK)
2171 != (pThis->mouseCapabilities & VMMDEV_MOUSE_NOTIFY_GUEST_MASK));
2172
2173 Log(("vmmdevSetMouseCapabilities: bNotify %d\n", bNotify));
2174
2175 pThis->mouseCapabilities &= ~VMMDEV_MOUSE_HOST_MASK
2176 | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
2177 pThis->mouseCapabilities |= (capabilities & VMMDEV_MOUSE_HOST_MASK);
2178 if (bNotify)
2179 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
2180
2181 PDMCritSectLeave(&pThis->CritSect);
2182 return VINF_SUCCESS;
2183}
2184
2185
2186static DECLCALLBACK(int) vmmdevRequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t xres, uint32_t yres, uint32_t bpp, uint32_t display)
2187{
2188 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2189
2190 if (display >= RT_ELEMENTS(pThis->displayChangeData.aRequests))
2191 {
2192 return VERR_INVALID_PARAMETER;
2193 }
2194
2195 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2196
2197 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[display];
2198
2199 /* Verify that the new resolution is different and that guest does not yet know about it. */
2200 bool fSameResolution = (!xres || (pRequest->lastReadDisplayChangeRequest.xres == xres)) &&
2201 (!yres || (pRequest->lastReadDisplayChangeRequest.yres == yres)) &&
2202 (!bpp || (pRequest->lastReadDisplayChangeRequest.bpp == bpp)) &&
2203 pRequest->lastReadDisplayChangeRequest.display == display;
2204
2205 if (!xres && !yres && !bpp)
2206 {
2207 /* Special case of reset video mode. */
2208 fSameResolution = false;
2209 }
2210
2211 Log3(("vmmdevRequestDisplayChange: same=%d. new: xres=%d, yres=%d, bpp=%d, display=%d. old: xres=%d, yres=%d, bpp=%d, display=%d.\n",
2212 fSameResolution, xres, yres, bpp, display, pRequest->lastReadDisplayChangeRequest.xres, pRequest->lastReadDisplayChangeRequest.yres, pRequest->lastReadDisplayChangeRequest.bpp, pRequest->lastReadDisplayChangeRequest.display));
2213
2214 if (!fSameResolution)
2215 {
2216 LogRel(("VMMDev::SetVideoModeHint: got a video mode hint (%dx%dx%d) at %d\n",
2217 xres, yres, bpp, display));
2218
2219 /* we could validate the information here but hey, the guest can do that as well! */
2220 pRequest->displayChangeRequest.xres = xres;
2221 pRequest->displayChangeRequest.yres = yres;
2222 pRequest->displayChangeRequest.bpp = bpp;
2223 pRequest->displayChangeRequest.display = display;
2224 pRequest->fPending = true;
2225
2226 /* IRQ so the guest knows what's going on */
2227 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
2228 }
2229
2230 PDMCritSectLeave(&pThis->CritSect);
2231 return VINF_SUCCESS;
2232}
2233
2234static DECLCALLBACK(int) vmmdevRequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
2235{
2236 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2237 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2238
2239 /* Verify that the new resolution is different and that guest does not yet know about it. */
2240 bool fSameMode = (pThis->fLastSeamlessEnabled == fEnabled);
2241
2242 Log(("vmmdevRequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
2243
2244 if (!fSameMode)
2245 {
2246 /* we could validate the information here but hey, the guest can do that as well! */
2247 pThis->fSeamlessEnabled = fEnabled;
2248
2249 /* IRQ so the guest knows what's going on */
2250 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
2251 }
2252
2253 PDMCritSectLeave(&pThis->CritSect);
2254 return VINF_SUCCESS;
2255}
2256
2257static DECLCALLBACK(int) vmmdevSetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t ulBalloonSize)
2258{
2259 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2260 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2261
2262 /* Verify that the new resolution is different and that guest does not yet know about it. */
2263 bool fSame = (pThis->u32LastMemoryBalloonSize == ulBalloonSize);
2264
2265 Log(("vmmdevSetMemoryBalloon: old=%d. new=%d\n", pThis->u32LastMemoryBalloonSize, ulBalloonSize));
2266
2267 if (!fSame)
2268 {
2269 /* we could validate the information here but hey, the guest can do that as well! */
2270 pThis->u32MemoryBalloonSize = ulBalloonSize;
2271
2272 /* IRQ so the guest knows what's going on */
2273 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
2274 }
2275
2276 PDMCritSectLeave(&pThis->CritSect);
2277 return VINF_SUCCESS;
2278}
2279
2280static DECLCALLBACK(int) vmmdevVRDPChange(PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t u32VRDPExperienceLevel)
2281{
2282 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2283 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2284
2285 bool fSame = (pThis->fVRDPEnabled == fVRDPEnabled);
2286
2287 Log(("vmmdevVRDPChange: old=%d. new=%d\n", pThis->fVRDPEnabled, fVRDPEnabled));
2288
2289 if (!fSame)
2290 {
2291 pThis->fVRDPEnabled = fVRDPEnabled;
2292 pThis->u32VRDPExperienceLevel = u32VRDPExperienceLevel;
2293
2294 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_VRDP);
2295 }
2296
2297 PDMCritSectLeave(&pThis->CritSect);
2298 return VINF_SUCCESS;
2299}
2300
2301static DECLCALLBACK(int) vmmdevSetStatisticsInterval(PPDMIVMMDEVPORT pInterface, uint32_t ulStatInterval)
2302{
2303 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2304 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2305
2306 /* Verify that the new resolution is different and that guest does not yet know about it. */
2307 bool fSame = (pThis->u32LastStatIntervalSize == ulStatInterval);
2308
2309 Log(("vmmdevSetStatisticsInterval: old=%d. new=%d\n", pThis->u32LastStatIntervalSize, ulStatInterval));
2310
2311 if (!fSame)
2312 {
2313 /* we could validate the information here but hey, the guest can do that as well! */
2314 pThis->u32StatIntervalSize = ulStatInterval;
2315
2316 /* IRQ so the guest knows what's going on */
2317 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
2318 }
2319
2320 PDMCritSectLeave(&pThis->CritSect);
2321 return VINF_SUCCESS;
2322}
2323
2324
2325static DECLCALLBACK(int) vmmdevSetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
2326 const char *pszPassword, const char *pszDomain,
2327 uint32_t u32Flags)
2328{
2329 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2330 int rc = VINF_SUCCESS;
2331
2332 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2333
2334 /* logon mode? */
2335 if (u32Flags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
2336 {
2337 /* memorize the data */
2338 strcpy(pThis->pCredentials->Logon.szUserName, pszUsername);
2339 strcpy(pThis->pCredentials->Logon.szPassword, pszPassword);
2340 strcpy(pThis->pCredentials->Logon.szDomain, pszDomain);
2341 pThis->pCredentials->Logon.fAllowInteractiveLogon = !(u32Flags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
2342 }
2343 /* credentials verification mode? */
2344 else if (u32Flags & VMMDEV_SETCREDENTIALS_JUDGE)
2345 {
2346 /* memorize the data */
2347 strcpy(pThis->pCredentials->Judge.szUserName, pszUsername);
2348 strcpy(pThis->pCredentials->Judge.szPassword, pszPassword);
2349 strcpy(pThis->pCredentials->Judge.szDomain, pszDomain);
2350
2351 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_JUDGE_CREDENTIALS);
2352 }
2353 else
2354 rc = VERR_INVALID_PARAMETER;
2355
2356 PDMCritSectLeave(&pThis->CritSect);
2357 return rc;
2358}
2359
2360/**
2361 * Notification from the Display. Especially useful when
2362 * acceleration is disabled after a video mode change.
2363 *
2364 * @param fEnable Current acceleration status.
2365 */
2366static DECLCALLBACK(void) vmmdevVBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
2367{
2368 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2369
2370 Log(("vmmdevVBVAChange: fEnabled = %d\n", fEnabled));
2371
2372 if (pThis)
2373 {
2374 pThis->u32VideoAccelEnabled = fEnabled;
2375 }
2376 return;
2377}
2378
2379/**
2380 * Notification that a CPU is about to be unplugged from the VM.
2381 * The guest has to eject the CPU.
2382 *
2383 * @returns VBox status code.
2384 * @param idCpu The id of the CPU.
2385 * @param idCpuCore The core id of the CPU to remove.
2386 * @param idCpuPackage The package id of the CPU to remove.
2387 */
2388static DECLCALLBACK(int) vmmdevCpuHotUnplug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
2389{
2390 int rc = VINF_SUCCESS;
2391 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2392
2393 Log(("vmmdevCpuHotUnplug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
2394
2395 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2396
2397 if (pThis->fCpuHotPlugEventsEnabled)
2398 {
2399 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Unplug;
2400 pThis->idCpuCore = idCpuCore;
2401 pThis->idCpuPackage = idCpuPackage;
2402 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_CPU_HOTPLUG);
2403 }
2404 else
2405 rc = VERR_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
2406
2407 PDMCritSectLeave(&pThis->CritSect);
2408 return rc;
2409}
2410
2411/**
2412 * Notification that a CPU was attached to the VM
2413 * The guest may use it now.
2414 *
2415 * @returns VBox status code.
2416 * @param idCpuCore The core id of the CPU to add.
2417 * @param idCpuPackage The package id of the CPU to add.
2418 */
2419static DECLCALLBACK(int) vmmdevCpuHotPlug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
2420{
2421 int rc = VINF_SUCCESS;
2422 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2423
2424 Log(("vmmdevCpuPlug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
2425
2426 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2427
2428 if (pThis->fCpuHotPlugEventsEnabled)
2429 {
2430 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Plug;
2431 pThis->idCpuCore = idCpuCore;
2432 pThis->idCpuPackage = idCpuPackage;
2433 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_CPU_HOTPLUG);
2434 }
2435 else
2436 rc = VERR_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
2437
2438 PDMCritSectLeave(&pThis->CritSect);
2439 return rc;
2440}
2441
2442/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
2443
2444/**
2445 * @copydoc FNSSMDEVLIVEEXEC
2446 */
2447static DECLCALLBACK(int) vmmdevLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
2448{
2449 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
2450
2451 SSMR3PutBool(pSSM, pThis->fGetHostTimeDisabled);
2452 SSMR3PutBool(pSSM, pThis->fBackdoorLogDisabled);
2453 SSMR3PutBool(pSSM, pThis->fKeepCredentials);
2454 SSMR3PutBool(pSSM, pThis->fHeapEnabled);
2455
2456 return VINF_SSM_DONT_CALL_AGAIN;
2457}
2458
2459
2460/**
2461 * @copydoc FNSSMDEVSAVEEXEC
2462 *
2463 */
2464static DECLCALLBACK(int) vmmdevSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2465{
2466 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
2467
2468 vmmdevLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
2469
2470 SSMR3PutU32(pSSM, pThis->hypervisorSize);
2471 SSMR3PutU32(pSSM, pThis->mouseCapabilities);
2472 SSMR3PutU32(pSSM, pThis->mouseXAbs);
2473 SSMR3PutU32(pSSM, pThis->mouseYAbs);
2474
2475 SSMR3PutBool(pSSM, pThis->fNewGuestFilterMask);
2476 SSMR3PutU32(pSSM, pThis->u32NewGuestFilterMask);
2477 SSMR3PutU32(pSSM, pThis->u32GuestFilterMask);
2478 SSMR3PutU32(pSSM, pThis->u32HostEventFlags);
2479 /* The following is not strictly necessary as PGM restors MMIO2, keeping it for historical reasons. */
2480 SSMR3PutMem(pSSM, &pThis->pVMMDevRAMR3->V, sizeof(pThis->pVMMDevRAMR3->V));
2481
2482 SSMR3PutMem(pSSM, &pThis->guestInfo, sizeof (pThis->guestInfo));
2483 SSMR3PutU32(pSSM, pThis->fu32AdditionsOk);
2484 SSMR3PutU32(pSSM, pThis->u32VideoAccelEnabled);
2485 SSMR3PutBool(pSSM, pThis->displayChangeData.fGuestSentChangeEventAck);
2486
2487 SSMR3PutU32(pSSM, pThis->guestCaps);
2488
2489#ifdef VBOX_WITH_HGCM
2490 vmmdevHGCMSaveState(pThis, pSSM);
2491#endif /* VBOX_WITH_HGCM */
2492
2493 SSMR3PutU32(pSSM, pThis->fHostCursorRequested);
2494
2495 return VINF_SUCCESS;
2496}
2497
2498/**
2499 * @copydoc FNSSMDEVLOADEXEC
2500 */
2501static DECLCALLBACK(int) vmmdevLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2502{
2503 /** @todo The code load code is assuming we're always loaded into a freshly
2504 * constructed VM. */
2505 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
2506 int rc;
2507
2508 if ( uVersion > VMMDEV_SAVED_STATE_VERSION
2509 || uVersion < 6)
2510 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2511
2512 /* config */
2513 if (uVersion > VMMDEV_SAVED_STATE_VERSION_VBOX_30)
2514 {
2515 bool f;
2516 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
2517 if (pThis->fGetHostTimeDisabled != f)
2518 LogRel(("VMMDev: Config mismatch - fGetHostTimeDisabled: config=%RTbool saved=%RTbool\n", pThis->fGetHostTimeDisabled, f));
2519
2520 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
2521 if (pThis->fBackdoorLogDisabled != f)
2522 LogRel(("VMMDev: Config mismatch - fBackdoorLogDisabled: config=%RTbool saved=%RTbool\n", pThis->fBackdoorLogDisabled, f));
2523
2524 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
2525 if (pThis->fKeepCredentials != f)
2526 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fKeepCredentials: config=%RTbool saved=%RTbool"),
2527 pThis->fKeepCredentials, f);
2528 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
2529 if (pThis->fHeapEnabled != f)
2530 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fHeapEnabled: config=%RTbool saved=%RTbool"),
2531 pThis->fHeapEnabled, f);
2532 }
2533
2534 if (uPass != SSM_PASS_FINAL)
2535 return VINF_SUCCESS;
2536
2537 /* state */
2538 SSMR3GetU32(pSSM, &pThis->hypervisorSize);
2539 SSMR3GetU32(pSSM, &pThis->mouseCapabilities);
2540 SSMR3GetU32(pSSM, &pThis->mouseXAbs);
2541 SSMR3GetU32(pSSM, &pThis->mouseYAbs);
2542
2543 SSMR3GetBool(pSSM, &pThis->fNewGuestFilterMask);
2544 SSMR3GetU32(pSSM, &pThis->u32NewGuestFilterMask);
2545 SSMR3GetU32(pSSM, &pThis->u32GuestFilterMask);
2546 SSMR3GetU32(pSSM, &pThis->u32HostEventFlags);
2547
2548// SSMR3GetBool(pSSM, &pThis->pVMMDevRAMR3->fHaveEvents);
2549 // here be dragons (probably)
2550 SSMR3GetMem(pSSM, &pThis->pVMMDevRAMR3->V, sizeof (pThis->pVMMDevRAMR3->V));
2551
2552 SSMR3GetMem(pSSM, &pThis->guestInfo, sizeof (pThis->guestInfo));
2553 SSMR3GetU32(pSSM, &pThis->fu32AdditionsOk);
2554 SSMR3GetU32(pSSM, &pThis->u32VideoAccelEnabled);
2555 if (uVersion > 10)
2556 SSMR3GetBool(pSSM, &pThis->displayChangeData.fGuestSentChangeEventAck);
2557
2558 rc = SSMR3GetU32(pSSM, &pThis->guestCaps);
2559
2560 /* Attributes which were temporarily introduced in r30072 */
2561 if (uVersion == 7)
2562 {
2563 uint32_t temp;
2564 SSMR3GetU32(pSSM, &temp);
2565 rc = SSMR3GetU32(pSSM, &temp);
2566 }
2567 AssertRCReturn(rc, rc);
2568
2569#ifdef VBOX_WITH_HGCM
2570 rc = vmmdevHGCMLoadState(pThis, pSSM, uVersion);
2571 AssertRCReturn(rc, rc);
2572#endif /* VBOX_WITH_HGCM */
2573
2574 if (uVersion >= 10)
2575 rc = SSMR3GetU32(pSSM, &pThis->fHostCursorRequested);
2576 AssertRCReturn(rc, rc);
2577
2578 /*
2579 * On a resume, we send the capabilities changed message so
2580 * that listeners can sync their state again
2581 */
2582 Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pThis->mouseCapabilities));
2583 if (pThis->pDrv)
2584 {
2585 pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
2586 if (uVersion >= 10)
2587 pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
2588 /*fVisible=*/!!pThis->fHostCursorRequested,
2589 /*fAlpha=*/false,
2590 /*xHot=*/0, /*yHot=*/0,
2591 /*cx=*/0, /*cy=*/0,
2592 /*pvShape=*/NULL);
2593 }
2594
2595 /* Reestablish the acceleration status. */
2596 if ( pThis->u32VideoAccelEnabled
2597 && pThis->pDrv)
2598 {
2599 pThis->pDrv->pfnVideoAccelEnable (pThis->pDrv, !!pThis->u32VideoAccelEnabled, &pThis->pVMMDevRAMR3->vbvaMemory);
2600 }
2601
2602 if (pThis->fu32AdditionsOk)
2603 {
2604 LogRel(("Guest Additions information report: additionsVersion = 0x%08X, osType = 0x%08X\n",
2605 pThis->guestInfo.additionsVersion,
2606 pThis->guestInfo.osType));
2607 if (pThis->pDrv)
2608 pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
2609 }
2610 if (pThis->pDrv)
2611 pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
2612
2613 return VINF_SUCCESS;
2614}
2615
2616/**
2617 * Load state done callback. Notify guest of restore event.
2618 *
2619 * @returns VBox status code.
2620 * @param pDevIns The device instance.
2621 * @param pSSM The handle to the saved state.
2622 */
2623static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2624{
2625 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
2626
2627#ifdef VBOX_WITH_HGCM
2628 int rc = vmmdevHGCMLoadStateDone(pThis, pSSM);
2629 AssertLogRelRCReturn(rc, rc);
2630#endif /* VBOX_WITH_HGCM */
2631
2632 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_RESTORED);
2633
2634 return VINF_SUCCESS;
2635}
2636
2637/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
2638
2639/**
2640 * (Re-)initializes the MMIO2 data.
2641 *
2642 * @param pThis Pointer to the VMMDev instance data.
2643 */
2644static void vmmdevInitRam(VMMDevState *pThis)
2645{
2646 memset(pThis->pVMMDevRAMR3, 0, sizeof(VMMDevMemory));
2647 pThis->pVMMDevRAMR3->u32Size = sizeof(VMMDevMemory);
2648 pThis->pVMMDevRAMR3->u32Version = VMMDEV_MEMORY_VERSION;
2649}
2650
2651/**
2652 * Reset notification.
2653 *
2654 * @returns VBox status.
2655 * @param pDrvIns The driver instance data.
2656 */
2657static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
2658{
2659 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
2660
2661 /*
2662 * Reset the mouse integration feature bits
2663 */
2664 if (pThis->mouseCapabilities & VMMDEV_MOUSE_GUEST_MASK)
2665 {
2666 pThis->mouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
2667 /* notify the connector */
2668 Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pThis->mouseCapabilities));
2669 pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
2670 }
2671 pThis->fHostCursorRequested = false;
2672
2673 pThis->hypervisorSize = 0;
2674
2675 pThis->u32HostEventFlags = 0;
2676
2677 /* re-initialize the VMMDev memory */
2678 if (pThis->pVMMDevRAMR3)
2679 vmmdevInitRam(pThis);
2680
2681 /* credentials have to go away (by default) */
2682 if (!pThis->fKeepCredentials)
2683 {
2684 memset(pThis->pCredentials->Logon.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2685 memset(pThis->pCredentials->Logon.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2686 memset(pThis->pCredentials->Logon.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2687 }
2688 memset(pThis->pCredentials->Judge.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2689 memset(pThis->pCredentials->Judge.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2690 memset(pThis->pCredentials->Judge.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2691
2692 /* Reset means that additions will report again. */
2693 const bool fVersionChanged = pThis->fu32AdditionsOk
2694 || pThis->guestInfo.additionsVersion
2695 || pThis->guestInfo.osType != VBOXOSTYPE_Unknown;
2696 if (fVersionChanged)
2697 Log(("vmmdevReset: fu32AdditionsOk=%d additionsVersion=%x osType=%#x\n",
2698 pThis->fu32AdditionsOk, pThis->guestInfo.additionsVersion, pThis->guestInfo.osType));
2699 pThis->fu32AdditionsOk = false;
2700 memset (&pThis->guestInfo, 0, sizeof (pThis->guestInfo));
2701
2702 /* clear pending display change request. */
2703 for (unsigned i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
2704 {
2705 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[i];
2706 memset (&pRequest->lastReadDisplayChangeRequest, 0, sizeof (pRequest->lastReadDisplayChangeRequest));
2707 }
2708 pThis->displayChangeData.iCurrentMonitor = 0;
2709 pThis->displayChangeData.fGuestSentChangeEventAck = false;
2710
2711 /* disable seamless mode */
2712 pThis->fLastSeamlessEnabled = false;
2713
2714 /* disabled memory ballooning */
2715 pThis->u32LastMemoryBalloonSize = 0;
2716
2717 /* disabled statistics updating */
2718 pThis->u32LastStatIntervalSize = 0;
2719
2720 /* Clear the "HGCM event enabled" flag so the event can be automatically reenabled. */
2721 pThis->u32HGCMEnabled = 0;
2722
2723 /*
2724 * Clear the event variables.
2725 *
2726 * Note: The pThis->u32HostEventFlags is not cleared.
2727 * It is designed that way so host events do not
2728 * depend on guest resets.
2729 */
2730 pThis->u32GuestFilterMask = 0;
2731 pThis->u32NewGuestFilterMask = 0;
2732 pThis->fNewGuestFilterMask = 0;
2733
2734 /* This is the default, as Windows and OS/2 guests take this for granted. (Actually, neither does...) */
2735 /** @todo change this when we next bump the interface version */
2736 const bool fCapsChanged = pThis->guestCaps != VMMDEV_GUEST_SUPPORTS_GRAPHICS;
2737 if (fCapsChanged)
2738 Log(("vmmdevReset: fCapsChanged=%#x -> %#x\n", pThis->guestCaps, VMMDEV_GUEST_SUPPORTS_GRAPHICS));
2739 pThis->guestCaps = VMMDEV_GUEST_SUPPORTS_GRAPHICS; /** @todo r=bird: why? I cannot see this being done at construction?*/
2740
2741 /*
2742 * Call the update functions as required.
2743 */
2744 if (fVersionChanged)
2745 pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
2746 if (fCapsChanged)
2747 pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
2748
2749 /* Generate a unique session id for this VM; it will be changed for each start, reset or restore.
2750 * This can be used for restore detection inside the guest.
2751 */
2752 pThis->idSession = ASMReadTSC();
2753}
2754
2755
2756/**
2757 * @interface_method_impl{PDMDEVREG,pfnRelocate}
2758 */
2759static DECLCALLBACK(void) vmmdevRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2760{
2761 NOREF(pDevIns);
2762 NOREF(offDelta);
2763}
2764
2765
2766/**
2767 * @interface_method_impl{PDMDEVREG,pfnDestruct}
2768 */
2769static DECLCALLBACK(int) vmmdevDestroy(PPDMDEVINS pDevIns)
2770{
2771 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2772 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
2773
2774 /*
2775 * Wipe and free the credentials.
2776 */
2777 if (pThis->pCredentials)
2778 {
2779 RTMemWipeThoroughly(pThis->pCredentials, sizeof(*pThis->pCredentials), 10);
2780 RTMemFree(pThis->pCredentials);
2781 pThis->pCredentials = NULL;
2782 }
2783
2784 return VINF_SUCCESS;
2785}
2786
2787
2788/**
2789 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2790 */
2791static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2792{
2793 int rc;
2794 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
2795
2796 Assert(iInstance == 0);
2797 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2798
2799 /*
2800 * Initialize data (most of it anyway).
2801 */
2802 /* Save PDM device instance data for future reference. */
2803 pThis->pDevIns = pDevIns;
2804
2805 /* PCI vendor, just a free bogus value */
2806 pThis->dev.config[0x00] = 0xee;
2807 pThis->dev.config[0x01] = 0x80;
2808 /* device ID */
2809 pThis->dev.config[0x02] = 0xfe;
2810 pThis->dev.config[0x03] = 0xca;
2811 /* class sub code (other type of system peripheral) */
2812 pThis->dev.config[0x0a] = 0x80;
2813 /* class base code (base system peripheral) */
2814 pThis->dev.config[0x0b] = 0x08;
2815 /* header type */
2816 pThis->dev.config[0x0e] = 0x00;
2817 /* interrupt on pin 0 */
2818 pThis->dev.config[0x3d] = 0x01;
2819
2820 /*
2821 * Interfaces
2822 */
2823 /* IBase */
2824 pThis->IBase.pfnQueryInterface = vmmdevPortQueryInterface;
2825
2826 /* VMMDev port */
2827 pThis->IPort.pfnQueryAbsoluteMouse = vmmdevQueryAbsoluteMouse;
2828 pThis->IPort.pfnSetAbsoluteMouse = vmmdevSetAbsoluteMouse;
2829 pThis->IPort.pfnQueryMouseCapabilities = vmmdevQueryMouseCapabilities;
2830 pThis->IPort.pfnSetMouseCapabilities = vmmdevSetMouseCapabilities;
2831 pThis->IPort.pfnRequestDisplayChange = vmmdevRequestDisplayChange;
2832 pThis->IPort.pfnSetCredentials = vmmdevSetCredentials;
2833 pThis->IPort.pfnVBVAChange = vmmdevVBVAChange;
2834 pThis->IPort.pfnRequestSeamlessChange = vmmdevRequestSeamlessChange;
2835 pThis->IPort.pfnSetMemoryBalloon = vmmdevSetMemoryBalloon;
2836 pThis->IPort.pfnSetStatisticsInterval = vmmdevSetStatisticsInterval;
2837 pThis->IPort.pfnVRDPChange = vmmdevVRDPChange;
2838 pThis->IPort.pfnCpuHotUnplug = vmmdevCpuHotUnplug;
2839 pThis->IPort.pfnCpuHotPlug = vmmdevCpuHotPlug;
2840
2841 /* Shared folder LED */
2842 pThis->SharedFolders.Led.u32Magic = PDMLED_MAGIC;
2843 pThis->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
2844
2845#ifdef VBOX_WITH_HGCM
2846 /* HGCM port */
2847 pThis->IHGCMPort.pfnCompleted = hgcmCompleted;
2848#endif
2849
2850 pThis->pCredentials = (VMMDEVCREDS *)RTMemAllocZ(sizeof(*pThis->pCredentials));
2851 if (!pThis->pCredentials)
2852 return VERR_NO_MEMORY;
2853
2854
2855 /*
2856 * Validate and read the configuration.
2857 */
2858 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
2859 "GetHostTimeDisabled|"
2860 "BackdoorLogDisabled|"
2861 "KeepCredentials|"
2862 "HeapEnabled|"
2863 "RamSize|"
2864 "TestingEnabled"
2865 ,
2866 "");
2867
2868 rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbGuestRAM);
2869 if (RT_FAILURE(rc))
2870 return PDMDEV_SET_ERROR(pDevIns, rc,
2871 N_("Configuration error: Failed querying \"RamSize\" as a 64-bit unsigned integer"));
2872
2873 rc = CFGMR3QueryBoolDef(pCfg, "GetHostTimeDisabled", &pThis->fGetHostTimeDisabled, false);
2874 if (RT_FAILURE(rc))
2875 return PDMDEV_SET_ERROR(pDevIns, rc,
2876 N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
2877
2878 rc = CFGMR3QueryBoolDef(pCfg, "BackdoorLogDisabled", &pThis->fBackdoorLogDisabled, false);
2879 if (RT_FAILURE(rc))
2880 return PDMDEV_SET_ERROR(pDevIns, rc,
2881 N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
2882
2883 rc = CFGMR3QueryBoolDef(pCfg, "KeepCredentials", &pThis->fKeepCredentials, false);
2884 if (RT_FAILURE(rc))
2885 return PDMDEV_SET_ERROR(pDevIns, rc,
2886 N_("Configuration error: Failed querying \"KeepCredentials\" as a boolean"));
2887
2888 rc = CFGMR3QueryBoolDef(pCfg, "HeapEnabled", &pThis->fHeapEnabled, true);
2889 if (RT_FAILURE(rc))
2890 return PDMDEV_SET_ERROR(pDevIns, rc,
2891 N_("Configuration error: Failed querying \"HeapEnabled\" as a boolean"));
2892
2893 rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &pThis->fRZEnabled, true);
2894 if (RT_FAILURE(rc))
2895 return PDMDEV_SET_ERROR(pDevIns, rc,
2896 N_("Configuration error: Failed querying \"RZEnabled\" as a boolean"));
2897
2898#ifndef VBOX_WITHOUT_TESTING_FEATURES
2899 rc = CFGMR3QueryBoolDef(pCfg, "TestingEnabled", &pThis->fTestingEnabled, false);
2900 if (RT_FAILURE(rc))
2901 return PDMDEV_SET_ERROR(pDevIns, rc,
2902 N_("Configuration error: Failed querying \"TestingEnabled\" as a boolean"));
2903 /** @todo image-to-load-filename? */
2904#endif
2905
2906 /*
2907 * Create the critical section for the device.
2908 */
2909 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "VMMDev");
2910 AssertRCReturn(rc, rc);
2911 /* Later: pDevIns->pCritSectR3 = &pThis->CritSect; */
2912
2913 /*
2914 * Register the backdoor logging port
2915 */
2916 rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog, NULL, NULL, NULL, "VMMDev backdoor logging");
2917 AssertRCReturn(rc, rc);
2918
2919#ifdef TIMESYNC_BACKDOOR
2920 /*
2921 * Alternative timesync source (temporary!)
2922 */
2923 rc = PDMDevHlpIOPortRegister(pDevIns, 0x505, 1, NULL, vmmdevTimesyncBackdoorWrite, vmmdevTimesyncBackdoorRead, NULL, NULL, "VMMDev timesync backdoor");
2924 AssertRCReturn(rc, rc);
2925#endif
2926
2927 /*
2928 * Allocate and initialize the MMIO2 memory.
2929 */
2930 rc = PDMDevHlpMMIO2Register(pDevIns, 1 /*iRegion*/, VMMDEV_RAM_SIZE, 0 /*fFlags*/, (void **)&pThis->pVMMDevRAMR3, "VMMDev");
2931 if (RT_FAILURE(rc))
2932 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2933 N_("Failed to allocate %u bytes of memory for the VMM device"), VMMDEV_RAM_SIZE);
2934 vmmdevInitRam(pThis);
2935
2936 if (pThis->fHeapEnabled)
2937 {
2938 rc = PDMDevHlpMMIO2Register(pDevIns, 2 /*iRegion*/, VMMDEV_HEAP_SIZE, 0 /*fFlags*/, (void **)&pThis->pVMMDevHeapR3, "VMMDev Heap");
2939 if (RT_FAILURE(rc))
2940 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2941 N_("Failed to allocate %u bytes of memory for the VMM device heap"), PAGE_SIZE);
2942 }
2943
2944 /*
2945 * Register the PCI device.
2946 */
2947 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
2948 if (RT_FAILURE(rc))
2949 return rc;
2950 if (pThis->dev.devfn == 32 || iInstance != 0)
2951 Log(("!!WARNING!!: pThis->dev.devfn=%d (ignore if testcase or no started by Main)\n", pThis->dev.devfn));
2952 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
2953 if (RT_FAILURE(rc))
2954 return rc;
2955 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, vmmdevIORAMRegionMap);
2956 if (RT_FAILURE(rc))
2957 return rc;
2958 if (pThis->fHeapEnabled)
2959 {
2960 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, VMMDEV_HEAP_SIZE, PCI_ADDRESS_SPACE_MEM_PREFETCH, vmmdevIORAMRegionMap);
2961 if (RT_FAILURE(rc))
2962 return rc;
2963 }
2964
2965#ifndef VBOX_WITHOUT_TESTING_FEATURES
2966 /*
2967 * Initialize testing.
2968 */
2969 rc = vmmdevTestingInitialize(pDevIns);
2970 if (RT_FAILURE(rc))
2971 return rc;
2972#endif
2973
2974 /*
2975 * Get the corresponding connector interface
2976 */
2977 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "VMM Driver Port");
2978 if (RT_SUCCESS(rc))
2979 {
2980 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIVMMDEVCONNECTOR);
2981 AssertMsgReturn(pThis->pDrv, ("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
2982#ifdef VBOX_WITH_HGCM
2983 pThis->pHGCMDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHGCMCONNECTOR);
2984 if (!pThis->pHGCMDrv)
2985 {
2986 Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Rrc\n", rc));
2987 /* this is not actually an error, just means that there is no support for HGCM */
2988 }
2989#endif
2990 /* Query the initial balloon size. */
2991 AssertPtr(pThis->pDrv->pfnQueryBalloonSize);
2992 rc = pThis->pDrv->pfnQueryBalloonSize(pThis->pDrv, &pThis->u32MemoryBalloonSize);
2993 AssertRC(rc);
2994
2995 Log(("Initial balloon size %x\n", pThis->u32MemoryBalloonSize));
2996 }
2997 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2998 {
2999 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
3000 rc = VINF_SUCCESS;
3001 }
3002 else
3003 AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Rrc\n", rc), rc);
3004
3005 /*
3006 * Attach status driver for shared folders (optional).
3007 */
3008 PPDMIBASE pBase;
3009 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
3010 if (RT_SUCCESS(rc))
3011 pThis->SharedFolders.pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
3012 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
3013 {
3014 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
3015 return rc;
3016 }
3017
3018 /*
3019 * Register saved state and init the HGCM CmdList critsect.
3020 */
3021 rc = PDMDevHlpSSMRegisterEx(pDevIns, VMMDEV_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
3022 NULL, vmmdevLiveExec, NULL,
3023 NULL, vmmdevSaveExec, NULL,
3024 NULL, vmmdevLoadExec, vmmdevLoadStateDone);
3025 AssertRCReturn(rc, rc);
3026
3027#ifdef VBOX_WITH_HGCM
3028 pThis->pHGCMCmdList = NULL;
3029 rc = RTCritSectInit(&pThis->critsectHGCMCmdList);
3030 AssertRCReturn(rc, rc);
3031 pThis->u32HGCMEnabled = 0;
3032#endif /* VBOX_WITH_HGCM */
3033
3034 /* In this version of VirtualBox the GUI checks whether "needs host cursor"
3035 * changes. */
3036 pThis->mouseCapabilities |= VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
3037
3038 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMemBalloonChunks, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Memory balloon size", "/Devices/VMMDev/BalloonChunks");
3039
3040 /* Generate a unique session id for this VM; it will be changed for each start, reset or restore.
3041 * This can be used for restore detection inside the guest.
3042 */
3043 pThis->idSession = ASMReadTSC();
3044 return rc;
3045}
3046
3047/**
3048 * The device registration structure.
3049 */
3050extern "C" const PDMDEVREG g_DeviceVMMDev =
3051{
3052 /* u32Version */
3053 PDM_DEVREG_VERSION,
3054 /* szName */
3055 "VMMDev",
3056 /* szRCMod */
3057 "VBoxDDGC.gc",
3058 /* szR0Mod */
3059 "VBoxDDR0.r0",
3060 /* pszDescription */
3061 "VirtualBox VMM Device\n",
3062 /* fFlags */
3063 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
3064 /* fClass */
3065 PDM_DEVREG_CLASS_VMM_DEV,
3066 /* cMaxInstances */
3067 1,
3068 /* cbInstance */
3069 sizeof(VMMDevState),
3070 /* pfnConstruct */
3071 vmmdevConstruct,
3072 /* pfnDestruct */
3073 NULL,
3074 /* pfnRelocate */
3075 vmmdevRelocate,
3076 /* pfnIOCtl */
3077 NULL,
3078 /* pfnPowerOn */
3079 NULL,
3080 /* pfnReset */
3081 vmmdevReset,
3082 /* pfnSuspend */
3083 NULL,
3084 /* pfnResume */
3085 NULL,
3086 /* pfnAttach */
3087 NULL,
3088 /* pfnDetach */
3089 NULL,
3090 /* pfnQueryInterface. */
3091 NULL,
3092 /* pfnInitComplete */
3093 NULL,
3094 /* pfnPowerOff */
3095 NULL,
3096 /* pfnSoftReset */
3097 NULL,
3098 /* u32VersionEnd */
3099 PDM_DEVREG_VERSION
3100};
3101#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
3102
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