VirtualBox

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

Last change on this file since 39892 was 39892, checked in by vboxsync, 13 years ago

VMMDev: Allow some more function pointers to be NULL in PDMIVMMDEVCONNECTOR.

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

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