VirtualBox

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

Last change on this file since 32303 was 32209, checked in by vboxsync, 14 years ago

VMMDev.cpp: Implemented VMMDevPowerState_SaveState - untested

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

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