VirtualBox

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

Last change on this file since 44721 was 44721, checked in by vboxsync, 12 years ago

VMMDev: Removed pointless pThis check in vmmdevIPort_VBVAChange. (The caller is calling this method thru the method table pInterface points to, we just do some pointer arithmetic to calculate the pThis pointer, so it won't be NULL.)

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