VirtualBox

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

Last change on this file since 31686 was 31524, checked in by vboxsync, 14 years ago

VMMDev: understandable comment.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 119.1 KB
Line 
1/* $Id: VMMDev.cpp 31524 2010-08-10 11:47:25Z 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 end; /** @todo shouldn't (/ no need to) write back.*/
415 }
416
417 /* check the version of the header structure */
418 if (requestHeader.version != VMMDEV_REQUEST_HEADER_VERSION)
419 {
420 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader.version, VMMDEV_REQUEST_HEADER_VERSION));
421 rcRet = VINF_SUCCESS;
422 goto end; /** @todo shouldn't (/ no need to) write back.*/
423 }
424
425 Log2(("VMMDev request issued: %d\n", requestHeader.requestType));
426
427 /* 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 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 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 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 /** @todo no API for that yet */
883 pRequestHeader->rc = VERR_NOT_IMPLEMENTED;
884 break;
885 }
886
887 default:
888 AssertMsgFailed(("VMMDev invalid power state request: %d\n", powerStateRequest->powerState));
889 pRequestHeader->rc = VERR_INVALID_PARAMETER;
890 break;
891 }
892 }
893 break;
894 }
895
896 /*
897 * Get display change request
898 */
899 case VMMDevReq_GetDisplayChangeRequest:
900 {
901 if (pRequestHeader->size != sizeof(VMMDevDisplayChangeRequest))
902 {
903 /* Assert only if the size also not equal to a previous version size to prevent
904 * assertion with old additions.
905 */
906 AssertMsg(pRequestHeader->size == sizeof(VMMDevDisplayChangeRequest) - sizeof (uint32_t),
907 ("VMMDev display change request structure has invalid size!\n"));
908 pRequestHeader->rc = VERR_INVALID_PARAMETER;
909 }
910 else
911 {
912 VMMDevDisplayChangeRequest *displayChangeRequest = (VMMDevDisplayChangeRequest*)pRequestHeader;
913
914 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[0];
915
916 if (displayChangeRequest->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
917 {
918 /* Current request has been read at least once. */
919 pRequest->fPending = false;
920
921 /* Check if there are more pending requests. */
922 for (unsigned i = 1; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
923 {
924 if (pThis->displayChangeData.aRequests[i].fPending)
925 {
926 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
927 break;
928 }
929 }
930
931 /* Remember which resolution the client has queried, subsequent reads
932 * will return the same values. */
933 pRequest->lastReadDisplayChangeRequest = pRequest->displayChangeRequest;
934 pThis->displayChangeData.fGuestSentChangeEventAck = true;
935 }
936
937 if (pThis->displayChangeData.fGuestSentChangeEventAck)
938 {
939 displayChangeRequest->xres = pRequest->lastReadDisplayChangeRequest.xres;
940 displayChangeRequest->yres = pRequest->lastReadDisplayChangeRequest.yres;
941 displayChangeRequest->bpp = pRequest->lastReadDisplayChangeRequest.bpp;
942 }
943 else
944 {
945 /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
946 * read the last valid video mode hint. This happens when the guest X server
947 * determines the initial mode. */
948 displayChangeRequest->xres = pRequest->displayChangeRequest.xres;
949 displayChangeRequest->yres = pRequest->displayChangeRequest.yres;
950 displayChangeRequest->bpp = pRequest->displayChangeRequest.bpp;
951 }
952 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d\n",
953 displayChangeRequest->xres, displayChangeRequest->yres, displayChangeRequest->bpp));
954
955 pRequestHeader->rc = VINF_SUCCESS;
956 }
957 break;
958 }
959
960 case VMMDevReq_GetDisplayChangeRequest2:
961 {
962 if (pRequestHeader->size != sizeof(VMMDevDisplayChangeRequest2))
963 {
964 pRequestHeader->rc = VERR_INVALID_PARAMETER;
965 }
966 else
967 {
968 VMMDevDisplayChangeRequest2 *displayChangeRequest = (VMMDevDisplayChangeRequest2*)pRequestHeader;
969
970 DISPLAYCHANGEREQUEST *pRequest = NULL;
971
972 if (displayChangeRequest->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
973 {
974 /* Select a pending request to report. */
975 unsigned i;
976 for (i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
977 {
978 if (pThis->displayChangeData.aRequests[i].fPending)
979 {
980 pRequest = &pThis->displayChangeData.aRequests[i];
981 /* Remember which request should be reported. */
982 pThis->displayChangeData.iCurrentMonitor = i;
983 Log3(("VMMDev: will report pending request for %d\n",
984 i));
985 break;
986 }
987 }
988
989 /* Check if there are more pending requests. */
990 i++;
991 for (; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
992 {
993 if (pThis->displayChangeData.aRequests[i].fPending)
994 {
995 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
996 Log3(("VMMDev: another pending at %d\n",
997 i));
998 break;
999 }
1000 }
1001
1002 if (pRequest)
1003 {
1004 /* Current request has been read at least once. */
1005 pRequest->fPending = false;
1006
1007 /* Remember which resolution the client has queried, subsequent reads
1008 * will return the same values. */
1009 pRequest->lastReadDisplayChangeRequest = pRequest->displayChangeRequest;
1010 pThis->displayChangeData.fGuestSentChangeEventAck = true;
1011 }
1012 else
1013 {
1014 Log3(("VMMDev: no pending request!!!\n"));
1015 }
1016 }
1017
1018 if (!pRequest)
1019 {
1020 Log3(("VMMDev: default to %d\n",
1021 pThis->displayChangeData.iCurrentMonitor));
1022 pRequest = &pThis->displayChangeData.aRequests[pThis->displayChangeData.iCurrentMonitor];
1023 }
1024
1025 if (pThis->displayChangeData.fGuestSentChangeEventAck)
1026 {
1027 displayChangeRequest->xres = pRequest->lastReadDisplayChangeRequest.xres;
1028 displayChangeRequest->yres = pRequest->lastReadDisplayChangeRequest.yres;
1029 displayChangeRequest->bpp = pRequest->lastReadDisplayChangeRequest.bpp;
1030 displayChangeRequest->display = pRequest->lastReadDisplayChangeRequest.display;
1031 }
1032 else
1033 {
1034 /* This is not a response to a VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST, just
1035 * read the last valid video mode hint. This happens when the guest X server
1036 * determines the initial video mode. */
1037 displayChangeRequest->xres = pRequest->displayChangeRequest.xres;
1038 displayChangeRequest->yres = pRequest->displayChangeRequest.yres;
1039 displayChangeRequest->bpp = pRequest->displayChangeRequest.bpp;
1040 displayChangeRequest->display = pRequest->displayChangeRequest.display;
1041 }
1042 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d at %d\n",
1043 displayChangeRequest->xres, displayChangeRequest->yres, displayChangeRequest->bpp, displayChangeRequest->display));
1044
1045 pRequestHeader->rc = VINF_SUCCESS;
1046 }
1047 break;
1048 }
1049
1050 /*
1051 * Query whether the given video mode is supported
1052 */
1053 case VMMDevReq_VideoModeSupported:
1054 {
1055 if (pRequestHeader->size != sizeof(VMMDevVideoModeSupportedRequest))
1056 {
1057 AssertMsgFailed(("VMMDev video mode supported request structure has invalid size!\n"));
1058 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1059 }
1060 else
1061 {
1062 VMMDevVideoModeSupportedRequest *videoModeSupportedRequest = (VMMDevVideoModeSupportedRequest*)pRequestHeader;
1063 /* forward the call */
1064 pRequestHeader->rc = pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
1065 0, /* primary screen. */
1066 videoModeSupportedRequest->width,
1067 videoModeSupportedRequest->height,
1068 videoModeSupportedRequest->bpp,
1069 &videoModeSupportedRequest->fSupported);
1070 }
1071 break;
1072 }
1073
1074 /*
1075 * Query whether the given video mode is supported for a specific display
1076 */
1077 case VMMDevReq_VideoModeSupported2:
1078 {
1079 if (pRequestHeader->size != sizeof(VMMDevVideoModeSupportedRequest2))
1080 {
1081 AssertMsgFailed(("VMMDev video mode supported request 2 structure has invalid size!\n"));
1082 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1083 }
1084 else
1085 {
1086 VMMDevVideoModeSupportedRequest2 *videoModeSupportedRequest2 = (VMMDevVideoModeSupportedRequest2*)pRequestHeader;
1087 /* forward the call */
1088 pRequestHeader->rc = pThis->pDrv->pfnVideoModeSupported(pThis->pDrv,
1089 videoModeSupportedRequest2->display,
1090 videoModeSupportedRequest2->width,
1091 videoModeSupportedRequest2->height,
1092 videoModeSupportedRequest2->bpp,
1093 &videoModeSupportedRequest2->fSupported);
1094 }
1095 break;
1096 }
1097
1098 /*
1099 * Query the height reduction in pixels
1100 */
1101 case VMMDevReq_GetHeightReduction:
1102 {
1103 if (pRequestHeader->size != sizeof(VMMDevGetHeightReductionRequest))
1104 {
1105 AssertMsgFailed(("VMMDev height reduction request structure has invalid size!\n"));
1106 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1107 }
1108 else
1109 {
1110 VMMDevGetHeightReductionRequest *heightReductionRequest = (VMMDevGetHeightReductionRequest*)pRequestHeader;
1111 /* forward the call */
1112 pRequestHeader->rc = pThis->pDrv->pfnGetHeightReduction(pThis->pDrv,
1113 &heightReductionRequest->heightReduction);
1114 }
1115 break;
1116 }
1117
1118 /*
1119 * Acknowledge VMMDev events
1120 */
1121 case VMMDevReq_AcknowledgeEvents:
1122 {
1123 if (pRequestHeader->size != sizeof(VMMDevEvents))
1124 {
1125 AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
1126 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1127 }
1128 else
1129 {
1130 if (VBOX_GUEST_INTERFACE_VERSION_1_03 (pThis))
1131 {
1132 vmmdevSetIRQ_Legacy_EMT (pThis);
1133 }
1134 else
1135 {
1136 VMMDevEvents *pAckRequest;
1137
1138 if (pThis->fNewGuestFilterMask)
1139 {
1140 pThis->fNewGuestFilterMask = false;
1141 pThis->u32GuestFilterMask = pThis->u32NewGuestFilterMask;
1142 }
1143
1144 pAckRequest = (VMMDevEvents *)pRequestHeader;
1145 pAckRequest->events =
1146 pThis->u32HostEventFlags & pThis->u32GuestFilterMask;
1147
1148 pThis->u32HostEventFlags &= ~pThis->u32GuestFilterMask;
1149 pThis->pVMMDevRAMR3->V.V1_04.fHaveEvents = false;
1150 PDMDevHlpPCISetIrqNoWait (pThis->pDevIns, 0, 0);
1151 }
1152 pRequestHeader->rc = VINF_SUCCESS;
1153 }
1154 break;
1155 }
1156
1157 /*
1158 * Change guest filter mask
1159 */
1160 case VMMDevReq_CtlGuestFilterMask:
1161 {
1162 if (pRequestHeader->size != sizeof(VMMDevCtlGuestFilterMask))
1163 {
1164 AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
1165 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1166 }
1167 else
1168 {
1169 VMMDevCtlGuestFilterMask *pCtlMaskRequest;
1170
1171 pCtlMaskRequest = (VMMDevCtlGuestFilterMask *)pRequestHeader;
1172 LogRelFlowFunc(("VMMDevCtlGuestFilterMask: or mask: 0x%x, not mask: 0x%x\n",
1173 pCtlMaskRequest->u32OrMask,
1174 pCtlMaskRequest->u32NotMask));
1175 /* HGCM event notification is enabled by the VMMDev device
1176 * automatically when any HGCM command is issued. The guest
1177 * cannot disable these notifications.
1178 */
1179 VMMDevCtlSetGuestFilterMask (pThis,
1180 pCtlMaskRequest->u32OrMask,
1181 pCtlMaskRequest->u32NotMask & ~VMMDEV_EVENT_HGCM);
1182 pRequestHeader->rc = VINF_SUCCESS;
1183
1184 }
1185 break;
1186 }
1187
1188#ifdef VBOX_WITH_HGCM
1189 /*
1190 * Process HGCM request
1191 */
1192 case VMMDevReq_HGCMConnect:
1193 {
1194 if (pRequestHeader->size < sizeof(VMMDevHGCMConnect))
1195 {
1196 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
1197 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1198 }
1199 else if (!pThis->pHGCMDrv)
1200 {
1201 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
1202 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1203 }
1204 else
1205 {
1206 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)pRequestHeader;
1207
1208 Log(("VMMDevReq_HGCMConnect\n"));
1209
1210 pRequestHeader->rc = vmmdevHGCMConnect (pThis, pHGCMConnect, (RTGCPHYS)u32);
1211 }
1212 break;
1213 }
1214
1215 case VMMDevReq_HGCMDisconnect:
1216 {
1217 if (pRequestHeader->size < sizeof(VMMDevHGCMDisconnect))
1218 {
1219 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
1220 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1221 }
1222 else if (!pThis->pHGCMDrv)
1223 {
1224 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
1225 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1226 }
1227 else
1228 {
1229 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)pRequestHeader;
1230
1231 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
1232 pRequestHeader->rc = vmmdevHGCMDisconnect (pThis, pHGCMDisconnect, (RTGCPHYS)u32);
1233 }
1234 break;
1235 }
1236
1237#ifdef VBOX_WITH_64_BITS_GUESTS
1238 case VMMDevReq_HGCMCall32:
1239 case VMMDevReq_HGCMCall64:
1240#else
1241 case VMMDevReq_HGCMCall:
1242#endif /* VBOX_WITH_64_BITS_GUESTS */
1243 {
1244 if (pRequestHeader->size < sizeof(VMMDevHGCMCall))
1245 {
1246 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
1247 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1248 }
1249 else if (!pThis->pHGCMDrv)
1250 {
1251 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
1252 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1253 }
1254 else
1255 {
1256 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pRequestHeader;
1257
1258 Log2(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
1259 Log2(("%.*Rhxd\n", pRequestHeader->size, pRequestHeader));
1260
1261#ifdef VBOX_WITH_64_BITS_GUESTS
1262 bool f64Bits = (pRequestHeader->requestType == VMMDevReq_HGCMCall64);
1263#else
1264 bool f64Bits = false;
1265#endif /* VBOX_WITH_64_BITS_GUESTS */
1266
1267 pRequestHeader->rc = vmmdevHGCMCall (pThis, pHGCMCall, requestHeader.size, (RTGCPHYS)u32, f64Bits);
1268 }
1269 break;
1270 }
1271#endif /* VBOX_WITH_HGCM */
1272
1273 case VMMDevReq_HGCMCancel:
1274 {
1275 if (pRequestHeader->size < sizeof(VMMDevHGCMCancel))
1276 {
1277 AssertMsgFailed(("VMMDevReq_HGCMCancel structure has invalid size!\n"));
1278 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1279 }
1280 else if (!pThis->pHGCMDrv)
1281 {
1282 Log(("VMMDevReq_HGCMCancel HGCM Connector is NULL!\n"));
1283 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1284 }
1285 else
1286 {
1287 VMMDevHGCMCancel *pHGCMCancel = (VMMDevHGCMCancel *)pRequestHeader;
1288
1289 Log(("VMMDevReq_VMMDevHGCMCancel\n"));
1290 pRequestHeader->rc = vmmdevHGCMCancel (pThis, pHGCMCancel, (RTGCPHYS)u32);
1291 }
1292 break;
1293 }
1294
1295 case VMMDevReq_HGCMCancel2:
1296 {
1297 if (pRequestHeader->size != sizeof(VMMDevHGCMCancel2))
1298 {
1299 AssertMsgFailed(("VMMDevReq_HGCMCancel structure has invalid size!\n"));
1300 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1301 }
1302 else if (!pThis->pHGCMDrv)
1303 {
1304 Log(("VMMDevReq_HGCMCancel HGCM Connector is NULL!\n"));
1305 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1306 }
1307 else
1308 {
1309 VMMDevHGCMCancel2 *pHGCMCancel2 = (VMMDevHGCMCancel2 *)pRequestHeader;
1310
1311 Log(("VMMDevReq_VMMDevHGCMCancel\n"));
1312 pRequestHeader->rc = vmmdevHGCMCancel2 (pThis, pHGCMCancel2->physReqToCancel);
1313 }
1314 break;
1315 }
1316
1317 case VMMDevReq_VideoAccelEnable:
1318 {
1319 if (pRequestHeader->size < sizeof(VMMDevVideoAccelEnable))
1320 {
1321 Log(("VMMDevReq_VideoAccelEnable request size too small!!!\n"));
1322 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1323 }
1324 else if (!pThis->pDrv)
1325 {
1326 Log(("VMMDevReq_VideoAccelEnable Connector is NULL!!!\n"));
1327 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1328 }
1329 else
1330 {
1331 VMMDevVideoAccelEnable *ptr = (VMMDevVideoAccelEnable *)pRequestHeader;
1332
1333 if (ptr->cbRingBuffer != VBVA_RING_BUFFER_SIZE)
1334 {
1335 /* The guest driver seems compiled with another headers. */
1336 Log(("VMMDevReq_VideoAccelEnable guest ring buffer size %d, should be %d!!!\n", ptr->cbRingBuffer, VBVA_RING_BUFFER_SIZE));
1337 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1338 }
1339 else
1340 {
1341 /* The request is correct. */
1342 ptr->fu32Status |= VBVA_F_STATUS_ACCEPTED;
1343
1344 LogFlow(("VMMDevReq_VideoAccelEnable ptr->u32Enable = %d\n", ptr->u32Enable));
1345
1346 pRequestHeader->rc = ptr->u32Enable?
1347 pThis->pDrv->pfnVideoAccelEnable (pThis->pDrv, true, &pThis->pVMMDevRAMR3->vbvaMemory):
1348 pThis->pDrv->pfnVideoAccelEnable (pThis->pDrv, false, NULL);
1349
1350 if ( ptr->u32Enable
1351 && RT_SUCCESS (pRequestHeader->rc))
1352 {
1353 ptr->fu32Status |= VBVA_F_STATUS_ENABLED;
1354
1355 /* Remember that guest successfully enabled acceleration.
1356 * We need to reestablish it on restoring the VM from saved state.
1357 */
1358 pThis->u32VideoAccelEnabled = 1;
1359 }
1360 else
1361 {
1362 /* The acceleration was not enabled. Remember that. */
1363 pThis->u32VideoAccelEnabled = 0;
1364 }
1365 }
1366 }
1367 break;
1368 }
1369
1370 case VMMDevReq_VideoAccelFlush:
1371 {
1372 if (pRequestHeader->size < sizeof(VMMDevVideoAccelFlush))
1373 {
1374 AssertMsgFailed(("VMMDevReq_VideoAccelFlush request size too small.\n"));
1375 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1376 }
1377 else if (!pThis->pDrv)
1378 {
1379 Log(("VMMDevReq_VideoAccelFlush Connector is NULL!\n"));
1380 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1381 }
1382 else
1383 {
1384 pThis->pDrv->pfnVideoAccelFlush (pThis->pDrv);
1385
1386 pRequestHeader->rc = VINF_SUCCESS;
1387 }
1388 break;
1389 }
1390
1391 case VMMDevReq_VideoSetVisibleRegion:
1392 {
1393 if (pRequestHeader->size < sizeof(VMMDevVideoSetVisibleRegion))
1394 {
1395 Log(("VMMDevReq_VideoSetVisibleRegion request size too small!!!\n"));
1396 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1397 }
1398 else if (!pThis->pDrv)
1399 {
1400 Log(("VMMDevReq_VideoSetVisibleRegion Connector is NULL!!!\n"));
1401 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1402 }
1403 else
1404 {
1405 VMMDevVideoSetVisibleRegion *ptr = (VMMDevVideoSetVisibleRegion *)pRequestHeader;
1406
1407 if (!ptr->cRect)
1408 {
1409 Log(("VMMDevReq_VideoSetVisibleRegion no rectangles!!!\n"));
1410 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1411 }
1412 else
1413 if (pRequestHeader->size != sizeof(VMMDevVideoSetVisibleRegion) + (ptr->cRect-1)*sizeof(RTRECT))
1414 {
1415 Log(("VMMDevReq_VideoSetVisibleRegion request size too small!!!\n"));
1416 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1417 }
1418 else
1419 {
1420 Log(("VMMDevReq_VideoSetVisibleRegion %d rectangles\n", ptr->cRect));
1421 /* forward the call */
1422 pRequestHeader->rc = pThis->pDrv->pfnSetVisibleRegion(pThis->pDrv, ptr->cRect, &ptr->Rect);
1423 }
1424 }
1425 break;
1426 }
1427
1428 case VMMDevReq_GetSeamlessChangeRequest:
1429 {
1430 if (pRequestHeader->size != sizeof(VMMDevSeamlessChangeRequest))
1431 {
1432 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1433 }
1434 else
1435 {
1436 VMMDevSeamlessChangeRequest *seamlessChangeRequest = (VMMDevSeamlessChangeRequest*)pRequestHeader;
1437 /* just pass on the information */
1438 Log(("VMMDev: returning seamless change request mode=%d\n", pThis->fSeamlessEnabled));
1439 if (pThis->fSeamlessEnabled)
1440 seamlessChangeRequest->mode = VMMDev_Seamless_Visible_Region;
1441 else
1442 seamlessChangeRequest->mode = VMMDev_Seamless_Disabled;
1443
1444 if (seamlessChangeRequest->eventAck == VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
1445 {
1446 /* Remember which mode the client has queried. */
1447 pThis->fLastSeamlessEnabled = pThis->fSeamlessEnabled;
1448 }
1449
1450 pRequestHeader->rc = VINF_SUCCESS;
1451 }
1452 break;
1453 }
1454
1455 case VMMDevReq_GetVRDPChangeRequest:
1456 {
1457 if (pRequestHeader->size != sizeof(VMMDevVRDPChangeRequest))
1458 {
1459 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1460 }
1461 else
1462 {
1463 VMMDevVRDPChangeRequest *vrdpChangeRequest = (VMMDevVRDPChangeRequest*)pRequestHeader;
1464 /* just pass on the information */
1465 Log(("VMMDev: returning VRDP status %d level %d\n", pThis->fVRDPEnabled, pThis->u32VRDPExperienceLevel));
1466
1467 vrdpChangeRequest->u8VRDPActive = pThis->fVRDPEnabled;
1468 vrdpChangeRequest->u32VRDPExperienceLevel = pThis->u32VRDPExperienceLevel;
1469
1470 pRequestHeader->rc = VINF_SUCCESS;
1471 }
1472 break;
1473 }
1474
1475 case VMMDevReq_GetMemBalloonChangeRequest:
1476 {
1477 Log(("VMMDevReq_GetMemBalloonChangeRequest\n"));
1478 if (pRequestHeader->size != sizeof(VMMDevGetMemBalloonChangeRequest))
1479 {
1480 AssertFailed();
1481 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1482 }
1483 else
1484 {
1485 VMMDevGetMemBalloonChangeRequest *memBalloonChangeRequest = (VMMDevGetMemBalloonChangeRequest*)pRequestHeader;
1486 /* just pass on the information */
1487 Log(("VMMDev: returning memory balloon size =%d\n", pThis->u32MemoryBalloonSize));
1488 memBalloonChangeRequest->cBalloonChunks = pThis->u32MemoryBalloonSize;
1489 memBalloonChangeRequest->cPhysMemChunks = pThis->cbGuestRAM / (uint64_t)_1M;
1490
1491 if (memBalloonChangeRequest->eventAck == VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
1492 {
1493 /* Remember which mode the client has queried. */
1494 pThis->u32LastMemoryBalloonSize = pThis->u32MemoryBalloonSize;
1495 }
1496
1497 pRequestHeader->rc = VINF_SUCCESS;
1498 }
1499 break;
1500 }
1501
1502 case VMMDevReq_ChangeMemBalloon:
1503 {
1504 VMMDevChangeMemBalloon *memBalloonChange = (VMMDevChangeMemBalloon*)pRequestHeader;
1505
1506 Log(("VMMDevReq_ChangeMemBalloon\n"));
1507 if ( pRequestHeader->size < sizeof(VMMDevChangeMemBalloon)
1508 || memBalloonChange->cPages != VMMDEV_MEMORY_BALLOON_CHUNK_PAGES
1509 || pRequestHeader->size != (uint32_t)RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[memBalloonChange->cPages]))
1510 {
1511 AssertFailed();
1512 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1513 }
1514 else
1515 {
1516 pRequestHeader->rc = PGMR3PhysChangeMemBalloon(PDMDevHlpGetVM(pDevIns), !!memBalloonChange->fInflate, memBalloonChange->cPages, memBalloonChange->aPhysPage);
1517 if (memBalloonChange->fInflate)
1518 STAM_REL_U32_INC(&pThis->StatMemBalloonChunks);
1519 else
1520 STAM_REL_U32_DEC(&pThis->StatMemBalloonChunks);
1521 }
1522 break;
1523 }
1524
1525 case VMMDevReq_GetStatisticsChangeRequest:
1526 {
1527 Log(("VMMDevReq_GetStatisticsChangeRequest\n"));
1528 if (pRequestHeader->size != sizeof(VMMDevGetStatisticsChangeRequest))
1529 {
1530 AssertFailed();
1531 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1532 }
1533 else
1534 {
1535 VMMDevGetStatisticsChangeRequest *statIntervalChangeRequest = (VMMDevGetStatisticsChangeRequest*)pRequestHeader;
1536 /* just pass on the information */
1537 Log(("VMMDev: returning statistics interval %d seconds\n", pThis->u32StatIntervalSize));
1538 statIntervalChangeRequest->u32StatInterval = pThis->u32StatIntervalSize;
1539
1540 if (statIntervalChangeRequest->eventAck == VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)
1541 {
1542 /* Remember which mode the client has queried. */
1543 pThis->u32LastStatIntervalSize= pThis->u32StatIntervalSize;
1544 }
1545
1546 pRequestHeader->rc = VINF_SUCCESS;
1547 }
1548 break;
1549 }
1550
1551 case VMMDevReq_ReportGuestStats:
1552 {
1553 Log(("VMMDevReq_ReportGuestStats\n"));
1554 if (pRequestHeader->size != sizeof(VMMDevReportGuestStats))
1555 {
1556 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1557 }
1558 else
1559 {
1560 VMMDevReportGuestStats *stats = (VMMDevReportGuestStats*)pRequestHeader;
1561
1562#ifdef DEBUG
1563 VBoxGuestStatistics *pGuestStats = &stats->guestStats;
1564
1565 Log(("Current statistics:\n"));
1566 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_IDLE)
1567 Log(("CPU%d: CPU Load Idle %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Idle));
1568
1569 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_KERNEL)
1570 Log(("CPU%d: CPU Load Kernel %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Kernel));
1571
1572 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_USER)
1573 Log(("CPU%d: CPU Load User %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_User));
1574
1575 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_THREADS)
1576 Log(("CPU%d: Thread %d\n", pGuestStats->u32CpuId, pGuestStats->u32Threads));
1577
1578 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PROCESSES)
1579 Log(("CPU%d: Processes %d\n", pGuestStats->u32CpuId, pGuestStats->u32Processes));
1580
1581 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_HANDLES)
1582 Log(("CPU%d: Handles %d\n", pGuestStats->u32CpuId, pGuestStats->u32Handles));
1583
1584 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEMORY_LOAD)
1585 Log(("CPU%d: Memory Load %d%%\n", pGuestStats->u32CpuId, pGuestStats->u32MemoryLoad));
1586
1587 /* Note that reported values are in pages; upper layers expect them in megabytes */
1588 Log(("CPU%d: Page size %-4d bytes\n", pGuestStats->u32CpuId, pGuestStats->u32PageSize));
1589 Assert(pGuestStats->u32PageSize == 4096);
1590
1591 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_TOTAL)
1592 Log(("CPU%d: Total physical memory %-4d MB\n", pGuestStats->u32CpuId, (pGuestStats->u32PhysMemTotal + (_1M/_4K)-1) / (_1M/_4K)));
1593
1594 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_AVAIL)
1595 Log(("CPU%d: Free physical memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemAvail / (_1M/_4K)));
1596
1597 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON)
1598 Log(("CPU%d: Memory balloon size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemBalloon / (_1M/_4K)));
1599
1600 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_COMMIT_TOTAL)
1601 Log(("CPU%d: Committed memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemCommitTotal / (_1M/_4K)));
1602
1603 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_TOTAL)
1604 Log(("CPU%d: Total kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelTotal / (_1M/_4K)));
1605
1606 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_PAGED)
1607 Log(("CPU%d: Paged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelPaged / (_1M/_4K)));
1608
1609 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED)
1610 Log(("CPU%d: Nonpaged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelNonPaged / (_1M/_4K)));
1611
1612 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE)
1613 Log(("CPU%d: System cache size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemSystemCache / (_1M/_4K)));
1614
1615 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE)
1616 Log(("CPU%d: Page file size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PageFileSize / (_1M/_4K)));
1617 Log(("Statistics end *******************\n"));
1618#endif
1619
1620 /* forward the call */
1621 pRequestHeader->rc = pThis->pDrv->pfnReportStatistics(pThis->pDrv, &stats->guestStats);
1622 }
1623 break;
1624 }
1625
1626 case VMMDevReq_QueryCredentials:
1627 {
1628 if (pRequestHeader->size != sizeof(VMMDevCredentials))
1629 {
1630 AssertMsgFailed(("VMMDevReq_QueryCredentials request size too small.\n"));
1631 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1632 }
1633 else
1634 {
1635 VMMDevCredentials *credentials = (VMMDevCredentials*)pRequestHeader;
1636
1637 /* let's start by nulling out the data */
1638 memset(credentials->szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1639 memset(credentials->szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1640 memset(credentials->szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1641
1642 /* should we return whether we got credentials for a logon? */
1643 if (credentials->u32Flags & VMMDEV_CREDENTIALS_QUERYPRESENCE)
1644 {
1645 if ( pThis->pCredentials->Logon.szUserName[0]
1646 || pThis->pCredentials->Logon.szPassword[0]
1647 || pThis->pCredentials->Logon.szDomain[0])
1648 {
1649 credentials->u32Flags |= VMMDEV_CREDENTIALS_PRESENT;
1650 }
1651 else
1652 {
1653 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_PRESENT;
1654 }
1655 }
1656
1657 /* does the guest want to read logon credentials? */
1658 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READ)
1659 {
1660 if (pThis->pCredentials->Logon.szUserName[0])
1661 strcpy(credentials->szUserName, pThis->pCredentials->Logon.szUserName);
1662 if (pThis->pCredentials->Logon.szPassword[0])
1663 strcpy(credentials->szPassword, pThis->pCredentials->Logon.szPassword);
1664 if (pThis->pCredentials->Logon.szDomain[0])
1665 strcpy(credentials->szDomain, pThis->pCredentials->Logon.szDomain);
1666 if (!pThis->pCredentials->Logon.fAllowInteractiveLogon)
1667 credentials->u32Flags |= VMMDEV_CREDENTIALS_NOLOCALLOGON;
1668 else
1669 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_NOLOCALLOGON;
1670 }
1671
1672 if (!pThis->fKeepCredentials)
1673 {
1674 /* does the caller want us to destroy the logon credentials? */
1675 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEAR)
1676 {
1677 memset(pThis->pCredentials->Logon.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1678 memset(pThis->pCredentials->Logon.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1679 memset(pThis->pCredentials->Logon.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1680 }
1681 }
1682
1683 /* does the guest want to read credentials for verification? */
1684 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READJUDGE)
1685 {
1686 if (pThis->pCredentials->Judge.szUserName[0])
1687 strcpy(credentials->szUserName, pThis->pCredentials->Judge.szUserName);
1688 if (pThis->pCredentials->Judge.szPassword[0])
1689 strcpy(credentials->szPassword, pThis->pCredentials->Judge.szPassword);
1690 if (pThis->pCredentials->Judge.szDomain[0])
1691 strcpy(credentials->szDomain, pThis->pCredentials->Judge.szDomain);
1692 }
1693
1694 /* does the caller want us to destroy the judgement credentials? */
1695 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEARJUDGE)
1696 {
1697 memset(pThis->pCredentials->Judge.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1698 memset(pThis->pCredentials->Judge.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1699 memset(pThis->pCredentials->Judge.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
1700 }
1701
1702 pRequestHeader->rc = VINF_SUCCESS;
1703 }
1704 break;
1705 }
1706
1707 case VMMDevReq_ReportCredentialsJudgement:
1708 {
1709 if (pRequestHeader->size != sizeof(VMMDevCredentials))
1710 {
1711 AssertMsgFailed(("VMMDevReq_ReportCredentialsJudgement request size too small.\n"));
1712 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1713 }
1714 else
1715 {
1716 VMMDevCredentials *credentials = (VMMDevCredentials*)pRequestHeader;
1717
1718 /* what does the guest think about the credentials? (note: the order is important here!) */
1719 if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_DENY)
1720 {
1721 pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_DENY);
1722 }
1723 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT)
1724 {
1725 pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT);
1726 }
1727 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_OK)
1728 {
1729 pThis->pDrv->pfnSetCredentialsJudgementResult(pThis->pDrv, VMMDEV_CREDENTIALS_JUDGE_OK);
1730 }
1731 else
1732 Log(("VMMDevReq_ReportCredentialsJudgement: invalid flags: %d!!!\n", credentials->u32Flags));
1733
1734 pRequestHeader->rc = VINF_SUCCESS;
1735 }
1736 break;
1737 }
1738
1739 /*
1740 * Implemented in 3.1.0.
1741 *
1742 * Note! The ring-0 VBoxGuestLib uses this to check whether
1743 * VMMDevHGCMParmType_PageList is supported.
1744 */
1745 case VMMDevReq_GetHostVersion:
1746 {
1747 AssertMsgBreakStmt(pRequestHeader->size == sizeof(VMMDevReqHostVersion),
1748 ("%#x < %#x\n", pRequestHeader->size, sizeof(VMMDevReqLogString)),
1749 pRequestHeader->rc = VERR_INVALID_PARAMETER);
1750 VMMDevReqHostVersion *pReqHostVer = (VMMDevReqHostVersion*)pRequestHeader;
1751 pReqHostVer->major = RTBldCfgVersionMajor();
1752 pReqHostVer->minor = RTBldCfgVersionMinor();
1753 pReqHostVer->build = RTBldCfgVersionBuild();
1754 pReqHostVer->revision = RTBldCfgRevision();
1755 pReqHostVer->features = VMMDEV_HVF_HGCM_PHYS_PAGE_LIST;
1756 pReqHostVer->header.rc = VINF_SUCCESS;
1757 break;
1758 }
1759
1760 case VMMDevReq_GetCpuHotPlugRequest:
1761 {
1762 VMMDevGetCpuHotPlugRequest *pReqCpuHotPlug = (VMMDevGetCpuHotPlugRequest *)pRequestHeader;
1763
1764 if (pRequestHeader->size != sizeof(VMMDevGetCpuHotPlugRequest))
1765 {
1766 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1767 }
1768 else
1769 {
1770 pReqCpuHotPlug->enmEventType = pThis->enmCpuHotPlugEvent;
1771 pReqCpuHotPlug->idCpuCore = pThis->idCpuCore;
1772 pReqCpuHotPlug->idCpuPackage = pThis->idCpuPackage;
1773 pReqCpuHotPlug->header.rc = VINF_SUCCESS;
1774
1775 /* Clear the event */
1776 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_None;
1777 pThis->idCpuCore = UINT32_MAX;
1778 pThis->idCpuPackage = UINT32_MAX;
1779 }
1780 break;
1781 }
1782
1783 case VMMDevReq_SetCpuHotPlugStatus:
1784 {
1785 VMMDevCpuHotPlugStatusRequest *pReqCpuHotPlugStatus = (VMMDevCpuHotPlugStatusRequest *)pRequestHeader;
1786
1787 if (pRequestHeader->size != sizeof(VMMDevCpuHotPlugStatusRequest))
1788 {
1789 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1790 }
1791 else
1792 {
1793 pRequestHeader->rc = VINF_SUCCESS;
1794
1795 if (pReqCpuHotPlugStatus->enmStatusType == VMMDevCpuStatusType_Disable)
1796 pThis->fCpuHotPlugEventsEnabled = false;
1797 else if (pReqCpuHotPlugStatus->enmStatusType == VMMDevCpuStatusType_Enable)
1798 pThis->fCpuHotPlugEventsEnabled = true;
1799 else
1800 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1801 }
1802 break;
1803 }
1804
1805#ifdef VBOX_WITH_PAGE_SHARING
1806 case VMMDevReq_RegisterSharedModule:
1807 {
1808 VMMDevSharedModuleRegistrationRequest *pReqModule = (VMMDevSharedModuleRegistrationRequest *)pRequestHeader;
1809
1810 if ( pRequestHeader->size < sizeof(VMMDevSharedModuleRegistrationRequest)
1811 || pRequestHeader->size != RT_UOFFSETOF(VMMDevSharedModuleRegistrationRequest, aRegions[pReqModule->cRegions]))
1812 {
1813 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1814 }
1815 else
1816 {
1817 pRequestHeader->rc = PGMR3SharedModuleRegister(PDMDevHlpGetVM(pDevIns), pReqModule->enmGuestOS, pReqModule->szName, pReqModule->szVersion,
1818 pReqModule->GCBaseAddr, pReqModule->cbModule,
1819 pReqModule->cRegions, pReqModule->aRegions);
1820 }
1821 break;
1822 }
1823
1824 case VMMDevReq_UnregisterSharedModule:
1825 {
1826 VMMDevSharedModuleUnregistrationRequest *pReqModule = (VMMDevSharedModuleUnregistrationRequest *)pRequestHeader;
1827
1828 if (pRequestHeader->size != sizeof(VMMDevSharedModuleUnregistrationRequest))
1829 {
1830 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1831 }
1832 else
1833 {
1834 pRequestHeader->rc = PGMR3SharedModuleUnregister(PDMDevHlpGetVM(pDevIns), pReqModule->szName, pReqModule->szVersion,
1835 pReqModule->GCBaseAddr, pReqModule->cbModule);
1836 }
1837 break;
1838 }
1839
1840 case VMMDevReq_CheckSharedModules:
1841 {
1842 VMMDevSharedModuleCheckRequest *pReqModule = (VMMDevSharedModuleCheckRequest *)pRequestHeader;
1843
1844 if (pRequestHeader->size != sizeof(VMMDevSharedModuleCheckRequest))
1845 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1846 else
1847 pRequestHeader->rc = PGMR3SharedModuleCheckAll(PDMDevHlpGetVM(pDevIns));
1848 break;
1849 }
1850
1851 case VMMDevReq_GetPageSharingStatus:
1852 {
1853 VMMDevPageSharingStatusRequest *pReqStatus = (VMMDevPageSharingStatusRequest *)pRequestHeader;
1854
1855 if (pRequestHeader->size != sizeof(VMMDevPageSharingStatusRequest))
1856 {
1857 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1858 }
1859 else
1860 {
1861 pReqStatus->fEnabled = false;
1862 pThis->pDrv->pfnIsPageFusionEnabled(pThis->pDrv, &pReqStatus->fEnabled);
1863 pRequestHeader->rc = VINF_SUCCESS;
1864 }
1865 break;
1866 }
1867
1868 case VMMDevReq_DebugIsPageShared:
1869 {
1870# ifdef DEBUG
1871 VMMDevPageIsSharedRequest *pReq = (VMMDevPageIsSharedRequest *)pRequestHeader;
1872
1873 if (pRequestHeader->size != sizeof(VMMDevPageIsSharedRequest))
1874 {
1875 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1876 }
1877 else
1878 {
1879 pRequestHeader->rc = PGMR3SharedModuleGetPageState(PDMDevHlpGetVM(pDevIns), pReq->GCPtrPage, &pReq->fShared, &pReq->uPageFlags);
1880 }
1881# else
1882 pRequestHeader->rc = VERR_NOT_IMPLEMENTED;
1883# endif
1884 break;
1885 }
1886
1887#endif
1888
1889#ifdef DEBUG
1890 case VMMDevReq_LogString:
1891 {
1892 if (pRequestHeader->size < sizeof(VMMDevReqLogString))
1893 {
1894 AssertMsgFailed(("VMMDevReq_LogString request size too small.\n"));
1895 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1896 }
1897 else
1898 {
1899 VMMDevReqLogString *pReqLogString = (VMMDevReqLogString *)pRequestHeader;
1900 LogIt(LOG_INSTANCE, RTLOGGRPFLAGS_LEVEL_1, LOG_GROUP_DEV_VMM_BACKDOOR,
1901 ("DEBUG LOG: %s", pReqLogString->szString));
1902 pRequestHeader->rc = VINF_SUCCESS;
1903 }
1904 break;
1905 }
1906#endif
1907
1908 /*
1909 * Get a unique session id for this VM; the id will be different after each start, reset or restore of the VM
1910 * This can be used for restore detection inside the guest.
1911 */
1912 case VMMDevReq_GetSessionId:
1913 {
1914 if (pRequestHeader->size != sizeof(VMMDevReqSessionId))
1915 {
1916 AssertMsgFailed(("VMMDevReq_GetSessionId request size too small.\n"));
1917 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1918 }
1919 else
1920 {
1921 VMMDevReqSessionId *pReq = (VMMDevReqSessionId *)pRequestHeader;
1922 pReq->idSession = pThis->idSession;
1923 pRequestHeader->rc = VINF_SUCCESS;
1924 }
1925 break;
1926 }
1927
1928 default:
1929 {
1930 pRequestHeader->rc = VERR_NOT_IMPLEMENTED;
1931 Log(("VMMDev unknown request type %d\n", pRequestHeader->requestType));
1932 break;
1933 }
1934 }
1935
1936end:
1937 /* Write the result back to guest memory */
1938 if (pRequestHeader)
1939 {
1940 PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)u32, pRequestHeader, pRequestHeader->size);
1941 RTMemFree(pRequestHeader);
1942 }
1943 else
1944 {
1945 /* early error case; write back header only */
1946 PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)u32, &requestHeader, sizeof(requestHeader));
1947 }
1948
1949 PDMCritSectLeave(&pThis->CritSect);
1950 return rcRet;
1951}
1952
1953/**
1954 * Callback function for mapping an PCI I/O region.
1955 *
1956 * @return VBox status code.
1957 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1958 * @param iRegion The region number.
1959 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1960 * I/O port, else it's a physical address.
1961 * This address is *NOT* relative to pci_mem_base like earlier!
1962 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1963 */
1964static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1965{
1966 LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%RGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
1967 VMMDevState *pThis = PCIDEV_2_VMMDEVSTATE(pPciDev);
1968 int rc;
1969
1970 if (iRegion == 1)
1971 {
1972 AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM, VERR_INTERNAL_ERROR);
1973 Assert(pThis->pVMMDevRAMR3 != NULL);
1974 if (GCPhysAddress != NIL_RTGCPHYS)
1975 {
1976 /*
1977 * Map the MMIO2 memory.
1978 */
1979 pThis->GCPhysVMMDevRAM = GCPhysAddress;
1980 Assert(pThis->GCPhysVMMDevRAM == GCPhysAddress);
1981 rc = PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
1982 }
1983 else
1984 {
1985 /*
1986 * It is about to be unmapped, just clean up.
1987 */
1988 pThis->GCPhysVMMDevRAM = NIL_RTGCPHYS32;
1989 rc = VINF_SUCCESS;
1990 }
1991 }
1992 else if (iRegion == 2)
1993 {
1994 AssertReturn(enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH, VERR_INTERNAL_ERROR);
1995 Assert(pThis->pVMMDevHeapR3 != NULL);
1996 if (GCPhysAddress != NIL_RTGCPHYS)
1997 {
1998 /*
1999 * Map the MMIO2 memory.
2000 */
2001 pThis->GCPhysVMMDevHeap = GCPhysAddress;
2002 Assert(pThis->GCPhysVMMDevHeap == GCPhysAddress);
2003 rc = PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
2004 if (RT_SUCCESS(rc))
2005 rc = PDMDevHlpRegisterVMMDevHeap(pPciDev->pDevIns, GCPhysAddress, pThis->pVMMDevHeapR3, VMMDEV_HEAP_SIZE);
2006 }
2007 else
2008 {
2009 /*
2010 * It is about to be unmapped, just clean up.
2011 */
2012 PDMDevHlpUnregisterVMMDevHeap(pPciDev->pDevIns, pThis->GCPhysVMMDevHeap);
2013 pThis->GCPhysVMMDevHeap = NIL_RTGCPHYS32;
2014 rc = VINF_SUCCESS;
2015 }
2016 }
2017 else
2018 {
2019 AssertMsgFailed(("%d\n", iRegion));
2020 rc = VERR_INVALID_PARAMETER;
2021 }
2022
2023 return rc;
2024}
2025
2026
2027/**
2028 * Callback function for mapping a PCI I/O region.
2029 *
2030 * @return VBox status code.
2031 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
2032 * @param iRegion The region number.
2033 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
2034 * I/O port, else it's a physical address.
2035 * This address is *NOT* relative to pci_mem_base like earlier!
2036 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
2037 */
2038static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
2039{
2040 VMMDevState *pThis = PCIDEV_2_VMMDEVSTATE(pPciDev);
2041 int rc = VINF_SUCCESS;
2042
2043 Assert(enmType == PCI_ADDRESS_SPACE_IO);
2044 Assert(iRegion == 0);
2045 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
2046
2047 /*
2048 * Save the base port address to simplify Port offset calculations.
2049 */
2050 pThis->PortBase = (RTIOPORT)GCPhysAddress;
2051
2052 /*
2053 * Register our port IO handlers.
2054 */
2055 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns,
2056 (RTIOPORT)GCPhysAddress + VMMDEV_PORT_OFF_REQUEST, 1,
2057 (void*)pThis, vmmdevRequestHandler,
2058 NULL, NULL, NULL, "VMMDev Request Handler");
2059 AssertRC(rc);
2060 return rc;
2061}
2062
2063/**
2064 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
2065 */
2066static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, const char *pszIID)
2067{
2068 VMMDevState *pThis = RT_FROM_MEMBER(pInterface, VMMDevState, IBase);
2069
2070 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThis->IBase);
2071 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVMMDEVPORT, &pThis->IPort);
2072#ifdef VBOX_WITH_HGCM
2073 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHGCMPORT, &pThis->IHGCMPort);
2074#endif
2075 /* Currently only for shared folders. */
2076 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS, &pThis->SharedFolders.ILeds);
2077 return NULL;
2078}
2079
2080/**
2081 * Gets the pointer to the status LED of a unit.
2082 *
2083 * @returns VBox status code.
2084 * @param pInterface Pointer to the interface structure containing the called function pointer.
2085 * @param iLUN The unit which status LED we desire.
2086 * @param ppLed Where to store the LED pointer.
2087 */
2088static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
2089{
2090 VMMDevState *pThis = (VMMDevState *)( (uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, SharedFolders.ILeds) );
2091 if (iLUN == 0) /* LUN 0 is shared folders */
2092 {
2093 *ppLed = &pThis->SharedFolders.Led;
2094 return VINF_SUCCESS;
2095 }
2096 return VERR_PDM_LUN_NOT_FOUND;
2097}
2098
2099/* -=-=-=-=-=- IVMMDevPort -=-=-=-=-=- */
2100
2101/** Converts a VMMDev port interface pointer to a VMMDev state pointer. */
2102#define IVMMDEVPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, IPort)) )
2103
2104
2105/**
2106 * Return the current absolute mouse position in pixels
2107 *
2108 * @returns VBox status code
2109 * @param pAbsX Pointer of result value, can be NULL
2110 * @param pAbsY Pointer of result value, can be NULL
2111 */
2112static DECLCALLBACK(int) vmmdevQueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t *pAbsX, uint32_t *pAbsY)
2113{
2114 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2115 AssertCompile(sizeof(pThis->mouseXAbs) == sizeof(*pAbsX));
2116 AssertCompile(sizeof(pThis->mouseYAbs) == sizeof(*pAbsY));
2117 if (pAbsX)
2118 ASMAtomicReadSize(&pThis->mouseXAbs, pAbsX);
2119 if (pAbsY)
2120 ASMAtomicReadSize(&pThis->mouseYAbs, pAbsY);
2121 return VINF_SUCCESS;
2122}
2123
2124/**
2125 * Set the new absolute mouse position in pixels
2126 *
2127 * @returns VBox status code
2128 * @param absX New absolute X position
2129 * @param absY New absolute Y position
2130 */
2131static DECLCALLBACK(int) vmmdevSetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t absX, uint32_t absY)
2132{
2133 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2134 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2135
2136 if ((pThis->mouseXAbs == absX) && (pThis->mouseYAbs == absY))
2137 {
2138 PDMCritSectLeave(&pThis->CritSect);
2139 return VINF_SUCCESS;
2140 }
2141 Log2(("vmmdevSetAbsoluteMouse: settings absolute position to x = %d, y = %d\n", absX, absY));
2142 pThis->mouseXAbs = absX;
2143 pThis->mouseYAbs = absY;
2144 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_MOUSE_POSITION_CHANGED);
2145 PDMCritSectLeave(&pThis->CritSect);
2146 return VINF_SUCCESS;
2147}
2148
2149/**
2150 * Return the current mouse capability flags
2151 *
2152 * @returns VBox status code
2153 * @param pCapabilities Pointer of result value
2154 */
2155static DECLCALLBACK(int) vmmdevQueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pCapabilities)
2156{
2157 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2158 if (!pCapabilities)
2159 return VERR_INVALID_PARAMETER;
2160 *pCapabilities = pThis->mouseCapabilities;
2161 return VINF_SUCCESS;
2162}
2163
2164/**
2165 * Set the current mouse capability flag (host side)
2166 *
2167 * @returns VBox status code
2168 * @param capabilities Capability mask
2169 */
2170static DECLCALLBACK(int) vmmdevSetMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t capabilities)
2171{
2172 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2173 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2174
2175 bool bNotify = ( (capabilities & VMMDEV_MOUSE_NOTIFY_GUEST_MASK)
2176 != (pThis->mouseCapabilities & VMMDEV_MOUSE_NOTIFY_GUEST_MASK));
2177
2178 Log(("vmmdevSetMouseCapabilities: bNotify %d\n", bNotify));
2179
2180 pThis->mouseCapabilities &= ~VMMDEV_MOUSE_HOST_MASK
2181 | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
2182 pThis->mouseCapabilities |= (capabilities & VMMDEV_MOUSE_HOST_MASK);
2183 if (bNotify)
2184 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
2185
2186 PDMCritSectLeave(&pThis->CritSect);
2187 return VINF_SUCCESS;
2188}
2189
2190
2191static DECLCALLBACK(int) vmmdevRequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t xres, uint32_t yres, uint32_t bpp, uint32_t display)
2192{
2193 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2194
2195 if (display >= RT_ELEMENTS(pThis->displayChangeData.aRequests))
2196 {
2197 return VERR_INVALID_PARAMETER;
2198 }
2199
2200 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2201
2202 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[display];
2203
2204 /* Verify that the new resolution is different and that guest does not yet know about it. */
2205 bool fSameResolution = (!xres || (pRequest->lastReadDisplayChangeRequest.xres == xres)) &&
2206 (!yres || (pRequest->lastReadDisplayChangeRequest.yres == yres)) &&
2207 (!bpp || (pRequest->lastReadDisplayChangeRequest.bpp == bpp)) &&
2208 pRequest->lastReadDisplayChangeRequest.display == display;
2209
2210 if (!xres && !yres && !bpp)
2211 {
2212 /* Special case of reset video mode. */
2213 fSameResolution = false;
2214 }
2215
2216 Log3(("vmmdevRequestDisplayChange: same=%d. new: xres=%d, yres=%d, bpp=%d, display=%d. old: xres=%d, yres=%d, bpp=%d, display=%d.\n",
2217 fSameResolution, xres, yres, bpp, display, pRequest->lastReadDisplayChangeRequest.xres, pRequest->lastReadDisplayChangeRequest.yres, pRequest->lastReadDisplayChangeRequest.bpp, pRequest->lastReadDisplayChangeRequest.display));
2218
2219 if (!fSameResolution)
2220 {
2221 LogRel(("VMMDev::SetVideoModeHint: got a video mode hint (%dx%dx%d) at %d\n",
2222 xres, yres, bpp, display));
2223
2224 /* we could validate the information here but hey, the guest can do that as well! */
2225 pRequest->displayChangeRequest.xres = xres;
2226 pRequest->displayChangeRequest.yres = yres;
2227 pRequest->displayChangeRequest.bpp = bpp;
2228 pRequest->displayChangeRequest.display = display;
2229 pRequest->fPending = true;
2230
2231 /* IRQ so the guest knows what's going on */
2232 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
2233 }
2234
2235 PDMCritSectLeave(&pThis->CritSect);
2236 return VINF_SUCCESS;
2237}
2238
2239static DECLCALLBACK(int) vmmdevRequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
2240{
2241 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2242 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2243
2244 /* Verify that the new resolution is different and that guest does not yet know about it. */
2245 bool fSameMode = (pThis->fLastSeamlessEnabled == fEnabled);
2246
2247 Log(("vmmdevRequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
2248
2249 if (!fSameMode)
2250 {
2251 /* we could validate the information here but hey, the guest can do that as well! */
2252 pThis->fSeamlessEnabled = fEnabled;
2253
2254 /* IRQ so the guest knows what's going on */
2255 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
2256 }
2257
2258 PDMCritSectLeave(&pThis->CritSect);
2259 return VINF_SUCCESS;
2260}
2261
2262static DECLCALLBACK(int) vmmdevSetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t ulBalloonSize)
2263{
2264 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2265 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2266
2267 /* Verify that the new resolution is different and that guest does not yet know about it. */
2268 bool fSame = (pThis->u32LastMemoryBalloonSize == ulBalloonSize);
2269
2270 Log(("vmmdevSetMemoryBalloon: old=%d. new=%d\n", pThis->u32LastMemoryBalloonSize, ulBalloonSize));
2271
2272 if (!fSame)
2273 {
2274 /* we could validate the information here but hey, the guest can do that as well! */
2275 pThis->u32MemoryBalloonSize = ulBalloonSize;
2276
2277 /* IRQ so the guest knows what's going on */
2278 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
2279 }
2280
2281 PDMCritSectLeave(&pThis->CritSect);
2282 return VINF_SUCCESS;
2283}
2284
2285static DECLCALLBACK(int) vmmdevVRDPChange(PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t u32VRDPExperienceLevel)
2286{
2287 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2288 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2289
2290 bool fSame = (pThis->fVRDPEnabled == fVRDPEnabled);
2291
2292 Log(("vmmdevVRDPChange: old=%d. new=%d\n", pThis->fVRDPEnabled, fVRDPEnabled));
2293
2294 if (!fSame)
2295 {
2296 pThis->fVRDPEnabled = fVRDPEnabled;
2297 pThis->u32VRDPExperienceLevel = u32VRDPExperienceLevel;
2298
2299 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_VRDP);
2300 }
2301
2302 PDMCritSectLeave(&pThis->CritSect);
2303 return VINF_SUCCESS;
2304}
2305
2306static DECLCALLBACK(int) vmmdevSetStatisticsInterval(PPDMIVMMDEVPORT pInterface, uint32_t ulStatInterval)
2307{
2308 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2309 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2310
2311 /* Verify that the new resolution is different and that guest does not yet know about it. */
2312 bool fSame = (pThis->u32LastStatIntervalSize == ulStatInterval);
2313
2314 Log(("vmmdevSetStatisticsInterval: old=%d. new=%d\n", pThis->u32LastStatIntervalSize, ulStatInterval));
2315
2316 if (!fSame)
2317 {
2318 /* we could validate the information here but hey, the guest can do that as well! */
2319 pThis->u32StatIntervalSize = ulStatInterval;
2320
2321 /* IRQ so the guest knows what's going on */
2322 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
2323 }
2324
2325 PDMCritSectLeave(&pThis->CritSect);
2326 return VINF_SUCCESS;
2327}
2328
2329
2330static DECLCALLBACK(int) vmmdevSetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
2331 const char *pszPassword, const char *pszDomain,
2332 uint32_t u32Flags)
2333{
2334 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2335 int rc = VINF_SUCCESS;
2336
2337 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2338
2339 /* logon mode? */
2340 if (u32Flags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
2341 {
2342 /* memorize the data */
2343 strcpy(pThis->pCredentials->Logon.szUserName, pszUsername);
2344 strcpy(pThis->pCredentials->Logon.szPassword, pszPassword);
2345 strcpy(pThis->pCredentials->Logon.szDomain, pszDomain);
2346 pThis->pCredentials->Logon.fAllowInteractiveLogon = !(u32Flags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
2347 }
2348 /* credentials verification mode? */
2349 else if (u32Flags & VMMDEV_SETCREDENTIALS_JUDGE)
2350 {
2351 /* memorize the data */
2352 strcpy(pThis->pCredentials->Judge.szUserName, pszUsername);
2353 strcpy(pThis->pCredentials->Judge.szPassword, pszPassword);
2354 strcpy(pThis->pCredentials->Judge.szDomain, pszDomain);
2355
2356 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_JUDGE_CREDENTIALS);
2357 }
2358 else
2359 rc = VERR_INVALID_PARAMETER;
2360
2361 PDMCritSectLeave(&pThis->CritSect);
2362 return rc;
2363}
2364
2365/**
2366 * Notification from the Display. Especially useful when
2367 * acceleration is disabled after a video mode change.
2368 *
2369 * @param fEnable Current acceleration status.
2370 */
2371static DECLCALLBACK(void) vmmdevVBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
2372{
2373 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2374
2375 Log(("vmmdevVBVAChange: fEnabled = %d\n", fEnabled));
2376
2377 if (pThis)
2378 {
2379 pThis->u32VideoAccelEnabled = fEnabled;
2380 }
2381 return;
2382}
2383
2384/**
2385 * Notification that a CPU is about to be unplugged from the VM.
2386 * The guest has to eject the CPU.
2387 *
2388 * @returns VBox status code.
2389 * @param idCpu The id of the CPU.
2390 * @param idCpuCore The core id of the CPU to remove.
2391 * @param idCpuPackage The package id of the CPU to remove.
2392 */
2393static DECLCALLBACK(int) vmmdevCpuHotUnplug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
2394{
2395 int rc = VINF_SUCCESS;
2396 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2397
2398 Log(("vmmdevCpuHotUnplug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
2399
2400 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2401
2402 if (pThis->fCpuHotPlugEventsEnabled)
2403 {
2404 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Unplug;
2405 pThis->idCpuCore = idCpuCore;
2406 pThis->idCpuPackage = idCpuPackage;
2407 VMMDevNotifyGuest (pThis, VMMDEV_EVENT_CPU_HOTPLUG);
2408 }
2409 else
2410 rc = VERR_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
2411
2412 PDMCritSectLeave(&pThis->CritSect);
2413 return rc;
2414}
2415
2416/**
2417 * Notification that a CPU was attached to the VM
2418 * The guest may use it now.
2419 *
2420 * @returns VBox status code.
2421 * @param idCpuCore The core id of the CPU to add.
2422 * @param idCpuPackage The package id of the CPU to add.
2423 */
2424static DECLCALLBACK(int) vmmdevCpuHotPlug(PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)
2425{
2426 int rc = VINF_SUCCESS;
2427 VMMDevState *pThis = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
2428
2429 Log(("vmmdevCpuPlug: idCpuCore=%u idCpuPackage=%u\n", idCpuCore, idCpuPackage));
2430
2431 PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
2432
2433 if (pThis->fCpuHotPlugEventsEnabled)
2434 {
2435 pThis->enmCpuHotPlugEvent = VMMDevCpuEventType_Plug;
2436 pThis->idCpuCore = idCpuCore;
2437 pThis->idCpuPackage = idCpuPackage;
2438 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_CPU_HOTPLUG);
2439 }
2440 else
2441 rc = VERR_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST;
2442
2443 PDMCritSectLeave(&pThis->CritSect);
2444 return rc;
2445}
2446
2447/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
2448
2449/**
2450 * @copydoc FNSSMDEVLIVEEXEC
2451 */
2452static DECLCALLBACK(int) vmmdevLiveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)
2453{
2454 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
2455
2456 SSMR3PutBool(pSSM, pThis->fGetHostTimeDisabled);
2457 SSMR3PutBool(pSSM, pThis->fBackdoorLogDisabled);
2458 SSMR3PutBool(pSSM, pThis->fKeepCredentials);
2459 SSMR3PutBool(pSSM, pThis->fHeapEnabled);
2460
2461 return VINF_SSM_DONT_CALL_AGAIN;
2462}
2463
2464
2465/**
2466 * @copydoc FNSSMDEVSAVEEXEC
2467 *
2468 */
2469static DECLCALLBACK(int) vmmdevSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2470{
2471 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
2472
2473 vmmdevLiveExec(pDevIns, pSSM, SSM_PASS_FINAL);
2474
2475 SSMR3PutU32(pSSM, pThis->hypervisorSize);
2476 SSMR3PutU32(pSSM, pThis->mouseCapabilities);
2477 SSMR3PutU32(pSSM, pThis->mouseXAbs);
2478 SSMR3PutU32(pSSM, pThis->mouseYAbs);
2479
2480 SSMR3PutBool(pSSM, pThis->fNewGuestFilterMask);
2481 SSMR3PutU32(pSSM, pThis->u32NewGuestFilterMask);
2482 SSMR3PutU32(pSSM, pThis->u32GuestFilterMask);
2483 SSMR3PutU32(pSSM, pThis->u32HostEventFlags);
2484 /* The following is not strictly necessary as PGM restors MMIO2, keeping it for historical reasons. */
2485 SSMR3PutMem(pSSM, &pThis->pVMMDevRAMR3->V, sizeof(pThis->pVMMDevRAMR3->V));
2486
2487 SSMR3PutMem(pSSM, &pThis->guestInfo, sizeof (pThis->guestInfo));
2488 SSMR3PutU32(pSSM, pThis->fu32AdditionsOk);
2489 SSMR3PutU32(pSSM, pThis->u32VideoAccelEnabled);
2490 SSMR3PutBool(pSSM, pThis->displayChangeData.fGuestSentChangeEventAck);
2491
2492 SSMR3PutU32(pSSM, pThis->guestCaps);
2493
2494#ifdef VBOX_WITH_HGCM
2495 vmmdevHGCMSaveState(pThis, pSSM);
2496#endif /* VBOX_WITH_HGCM */
2497
2498 SSMR3PutU32(pSSM, pThis->fHostCursorRequested);
2499
2500 return VINF_SUCCESS;
2501}
2502
2503/**
2504 * @copydoc FNSSMDEVLOADEXEC
2505 */
2506static DECLCALLBACK(int) vmmdevLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2507{
2508 /** @todo The code load code is assuming we're always loaded into a freshly
2509 * constructed VM. */
2510 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
2511 int rc;
2512
2513 if ( uVersion > VMMDEV_SAVED_STATE_VERSION
2514 || uVersion < 6)
2515 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2516
2517 /* config */
2518 if (uVersion > VMMDEV_SAVED_STATE_VERSION_VBOX_30)
2519 {
2520 bool f;
2521 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
2522 if (pThis->fGetHostTimeDisabled != f)
2523 LogRel(("VMMDev: Config mismatch - fGetHostTimeDisabled: config=%RTbool saved=%RTbool\n", pThis->fGetHostTimeDisabled, f));
2524
2525 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
2526 if (pThis->fBackdoorLogDisabled != f)
2527 LogRel(("VMMDev: Config mismatch - fBackdoorLogDisabled: config=%RTbool saved=%RTbool\n", pThis->fBackdoorLogDisabled, f));
2528
2529 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
2530 if (pThis->fKeepCredentials != f)
2531 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fKeepCredentials: config=%RTbool saved=%RTbool"),
2532 pThis->fKeepCredentials, f);
2533 rc = SSMR3GetBool(pSSM, &f); AssertRCReturn(rc, rc);
2534 if (pThis->fHeapEnabled != f)
2535 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Config mismatch - fHeapEnabled: config=%RTbool saved=%RTbool"),
2536 pThis->fHeapEnabled, f);
2537 }
2538
2539 if (uPass != SSM_PASS_FINAL)
2540 return VINF_SUCCESS;
2541
2542 /* state */
2543 SSMR3GetU32(pSSM, &pThis->hypervisorSize);
2544 SSMR3GetU32(pSSM, &pThis->mouseCapabilities);
2545 SSMR3GetU32(pSSM, &pThis->mouseXAbs);
2546 SSMR3GetU32(pSSM, &pThis->mouseYAbs);
2547
2548 SSMR3GetBool(pSSM, &pThis->fNewGuestFilterMask);
2549 SSMR3GetU32(pSSM, &pThis->u32NewGuestFilterMask);
2550 SSMR3GetU32(pSSM, &pThis->u32GuestFilterMask);
2551 SSMR3GetU32(pSSM, &pThis->u32HostEventFlags);
2552
2553// SSMR3GetBool(pSSM, &pThis->pVMMDevRAMR3->fHaveEvents);
2554 // here be dragons (probably)
2555 SSMR3GetMem(pSSM, &pThis->pVMMDevRAMR3->V, sizeof (pThis->pVMMDevRAMR3->V));
2556
2557 SSMR3GetMem(pSSM, &pThis->guestInfo, sizeof (pThis->guestInfo));
2558 SSMR3GetU32(pSSM, &pThis->fu32AdditionsOk);
2559 SSMR3GetU32(pSSM, &pThis->u32VideoAccelEnabled);
2560 if (uVersion > 10)
2561 SSMR3GetBool(pSSM, &pThis->displayChangeData.fGuestSentChangeEventAck);
2562
2563 rc = SSMR3GetU32(pSSM, &pThis->guestCaps);
2564
2565 /* Attributes which were temporarily introduced in r30072 */
2566 if (uVersion == 7)
2567 {
2568 uint32_t temp;
2569 SSMR3GetU32(pSSM, &temp);
2570 rc = SSMR3GetU32(pSSM, &temp);
2571 }
2572 AssertRCReturn(rc, rc);
2573
2574#ifdef VBOX_WITH_HGCM
2575 rc = vmmdevHGCMLoadState(pThis, pSSM, uVersion);
2576 AssertRCReturn(rc, rc);
2577#endif /* VBOX_WITH_HGCM */
2578
2579 if (uVersion >= 10)
2580 rc = SSMR3GetU32(pSSM, &pThis->fHostCursorRequested);
2581 AssertRCReturn(rc, rc);
2582
2583 /*
2584 * On a resume, we send the capabilities changed message so
2585 * that listeners can sync their state again
2586 */
2587 Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pThis->mouseCapabilities));
2588 if (pThis->pDrv)
2589 {
2590 pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
2591 if (uVersion >= 10)
2592 pThis->pDrv->pfnUpdatePointerShape(pThis->pDrv,
2593 /*fVisible=*/!!pThis->fHostCursorRequested,
2594 /*fAlpha=*/false,
2595 /*xHot=*/0, /*yHot=*/0,
2596 /*cx=*/0, /*cy=*/0,
2597 /*pvShape=*/NULL);
2598 }
2599
2600 /* Reestablish the acceleration status. */
2601 if ( pThis->u32VideoAccelEnabled
2602 && pThis->pDrv)
2603 {
2604 pThis->pDrv->pfnVideoAccelEnable (pThis->pDrv, !!pThis->u32VideoAccelEnabled, &pThis->pVMMDevRAMR3->vbvaMemory);
2605 }
2606
2607 if (pThis->fu32AdditionsOk)
2608 {
2609 LogRel(("Guest Additions information report: additionsVersion = 0x%08X, osType = 0x%08X\n",
2610 pThis->guestInfo.interfaceVersion,
2611 pThis->guestInfo.osType));
2612 if (pThis->pDrv)
2613 pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
2614 }
2615 if (pThis->pDrv)
2616 pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
2617
2618 return VINF_SUCCESS;
2619}
2620
2621/**
2622 * Load state done callback. Notify guest of restore event.
2623 *
2624 * @returns VBox status code.
2625 * @param pDevIns The device instance.
2626 * @param pSSM The handle to the saved state.
2627 */
2628static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2629{
2630 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
2631
2632#ifdef VBOX_WITH_HGCM
2633 int rc = vmmdevHGCMLoadStateDone(pThis, pSSM);
2634 AssertLogRelRCReturn(rc, rc);
2635#endif /* VBOX_WITH_HGCM */
2636
2637 VMMDevNotifyGuest(pThis, VMMDEV_EVENT_RESTORED);
2638
2639 return VINF_SUCCESS;
2640}
2641
2642/* -=-=-=-=- PDMDEVREG -=-=-=-=- */
2643
2644/**
2645 * (Re-)initializes the MMIO2 data.
2646 *
2647 * @param pThis Pointer to the VMMDev instance data.
2648 */
2649static void vmmdevInitRam(VMMDevState *pThis)
2650{
2651 memset(pThis->pVMMDevRAMR3, 0, sizeof(VMMDevMemory));
2652 pThis->pVMMDevRAMR3->u32Size = sizeof(VMMDevMemory);
2653 pThis->pVMMDevRAMR3->u32Version = VMMDEV_MEMORY_VERSION;
2654}
2655
2656/**
2657 * Reset notification.
2658 *
2659 * @returns VBox status.
2660 * @param pDrvIns The driver instance data.
2661 */
2662static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
2663{
2664 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState*);
2665
2666 /*
2667 * Reset the mouse integration feature bits
2668 */
2669 if (pThis->mouseCapabilities & VMMDEV_MOUSE_GUEST_MASK)
2670 {
2671 pThis->mouseCapabilities &= ~VMMDEV_MOUSE_GUEST_MASK;
2672 /* notify the connector */
2673 Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pThis->mouseCapabilities));
2674 pThis->pDrv->pfnUpdateMouseCapabilities(pThis->pDrv, pThis->mouseCapabilities);
2675 }
2676 pThis->fHostCursorRequested = false;
2677
2678 pThis->hypervisorSize = 0;
2679
2680 pThis->u32HostEventFlags = 0;
2681
2682 /* re-initialize the VMMDev memory */
2683 if (pThis->pVMMDevRAMR3)
2684 vmmdevInitRam(pThis);
2685
2686 /* credentials have to go away (by default) */
2687 if (!pThis->fKeepCredentials)
2688 {
2689 memset(pThis->pCredentials->Logon.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2690 memset(pThis->pCredentials->Logon.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2691 memset(pThis->pCredentials->Logon.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2692 }
2693 memset(pThis->pCredentials->Judge.szUserName, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2694 memset(pThis->pCredentials->Judge.szPassword, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2695 memset(pThis->pCredentials->Judge.szDomain, '\0', VMMDEV_CREDENTIALS_SZ_SIZE);
2696
2697 /* Reset means that additions will report again. */
2698 const bool fVersionChanged = pThis->fu32AdditionsOk
2699 || pThis->guestInfo.interfaceVersion
2700 || pThis->guestInfo.osType != VBOXOSTYPE_Unknown;
2701 if (fVersionChanged)
2702 Log(("vmmdevReset: fu32AdditionsOk=%d additionsVersion=%x osType=%#x\n",
2703 pThis->fu32AdditionsOk, pThis->guestInfo.interfaceVersion, pThis->guestInfo.osType));
2704 pThis->fu32AdditionsOk = false;
2705 memset (&pThis->guestInfo, 0, sizeof (pThis->guestInfo));
2706
2707 /* clear pending display change request. */
2708 for (unsigned i = 0; i < RT_ELEMENTS(pThis->displayChangeData.aRequests); i++)
2709 {
2710 DISPLAYCHANGEREQUEST *pRequest = &pThis->displayChangeData.aRequests[i];
2711 memset (&pRequest->lastReadDisplayChangeRequest, 0, sizeof (pRequest->lastReadDisplayChangeRequest));
2712 }
2713 pThis->displayChangeData.iCurrentMonitor = 0;
2714 pThis->displayChangeData.fGuestSentChangeEventAck = false;
2715
2716 /* disable seamless mode */
2717 pThis->fLastSeamlessEnabled = false;
2718
2719 /* disabled memory ballooning */
2720 pThis->u32LastMemoryBalloonSize = 0;
2721
2722 /* disabled statistics updating */
2723 pThis->u32LastStatIntervalSize = 0;
2724
2725 /* Clear the "HGCM event enabled" flag so the event can be automatically reenabled. */
2726 pThis->u32HGCMEnabled = 0;
2727
2728 /*
2729 * Clear the event variables.
2730 *
2731 * Note: The pThis->u32HostEventFlags is not cleared.
2732 * It is designed that way so host events do not
2733 * depend on guest resets.
2734 */
2735 pThis->u32GuestFilterMask = 0;
2736 pThis->u32NewGuestFilterMask = 0;
2737 pThis->fNewGuestFilterMask = 0;
2738
2739 /* This is the default, as Windows and OS/2 guests take this for granted. (Actually, neither does...) */
2740 /** @todo change this when we next bump the interface version */
2741 const bool fCapsChanged = pThis->guestCaps != VMMDEV_GUEST_SUPPORTS_GRAPHICS;
2742 if (fCapsChanged)
2743 Log(("vmmdevReset: fCapsChanged=%#x -> %#x\n", pThis->guestCaps, VMMDEV_GUEST_SUPPORTS_GRAPHICS));
2744 pThis->guestCaps = VMMDEV_GUEST_SUPPORTS_GRAPHICS; /** @todo r=bird: why? I cannot see this being done at construction?*/
2745
2746 /*
2747 * Call the update functions as required.
2748 */
2749 if (fVersionChanged)
2750 pThis->pDrv->pfnUpdateGuestInfo(pThis->pDrv, &pThis->guestInfo);
2751 if (fCapsChanged)
2752 pThis->pDrv->pfnUpdateGuestCapabilities(pThis->pDrv, pThis->guestCaps);
2753
2754 /* Generate a unique session id for this VM; it will be changed for each start, reset or restore.
2755 * This can be used for restore detection inside the guest.
2756 */
2757 pThis->idSession = ASMReadTSC();
2758}
2759
2760
2761/**
2762 * @interface_method_impl{PDMDEVREG,pfnRelocate}
2763 */
2764static DECLCALLBACK(void) vmmdevRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2765{
2766 NOREF(pDevIns);
2767 NOREF(offDelta);
2768}
2769
2770
2771/**
2772 * @interface_method_impl{PDMDEVREG,pfnDestruct}
2773 */
2774static DECLCALLBACK(int) vmmdevDestroy(PPDMDEVINS pDevIns)
2775{
2776 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2777 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
2778
2779 /*
2780 * Wipe and free the credentials.
2781 */
2782 if (pThis->pCredentials)
2783 {
2784 RTMemWipeThoroughly(pThis->pCredentials, sizeof(*pThis->pCredentials), 10);
2785 RTMemFree(pThis->pCredentials);
2786 pThis->pCredentials = NULL;
2787 }
2788
2789 return VINF_SUCCESS;
2790}
2791
2792
2793/**
2794 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2795 */
2796static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2797{
2798 int rc;
2799 VMMDevState *pThis = PDMINS_2_DATA(pDevIns, VMMDevState *);
2800
2801 Assert(iInstance == 0);
2802 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2803
2804 /*
2805 * Initialize data (most of it anyway).
2806 */
2807 /* Save PDM device instance data for future reference. */
2808 pThis->pDevIns = pDevIns;
2809
2810 /* PCI vendor, just a free bogus value */
2811 pThis->dev.config[0x00] = 0xee;
2812 pThis->dev.config[0x01] = 0x80;
2813 /* device ID */
2814 pThis->dev.config[0x02] = 0xfe;
2815 pThis->dev.config[0x03] = 0xca;
2816 /* class sub code (other type of system peripheral) */
2817 pThis->dev.config[0x0a] = 0x80;
2818 /* class base code (base system peripheral) */
2819 pThis->dev.config[0x0b] = 0x08;
2820 /* header type */
2821 pThis->dev.config[0x0e] = 0x00;
2822 /* interrupt on pin 0 */
2823 pThis->dev.config[0x3d] = 0x01;
2824
2825 /*
2826 * Interfaces
2827 */
2828 /* IBase */
2829 pThis->IBase.pfnQueryInterface = vmmdevPortQueryInterface;
2830
2831 /* VMMDev port */
2832 pThis->IPort.pfnQueryAbsoluteMouse = vmmdevQueryAbsoluteMouse;
2833 pThis->IPort.pfnSetAbsoluteMouse = vmmdevSetAbsoluteMouse;
2834 pThis->IPort.pfnQueryMouseCapabilities = vmmdevQueryMouseCapabilities;
2835 pThis->IPort.pfnSetMouseCapabilities = vmmdevSetMouseCapabilities;
2836 pThis->IPort.pfnRequestDisplayChange = vmmdevRequestDisplayChange;
2837 pThis->IPort.pfnSetCredentials = vmmdevSetCredentials;
2838 pThis->IPort.pfnVBVAChange = vmmdevVBVAChange;
2839 pThis->IPort.pfnRequestSeamlessChange = vmmdevRequestSeamlessChange;
2840 pThis->IPort.pfnSetMemoryBalloon = vmmdevSetMemoryBalloon;
2841 pThis->IPort.pfnSetStatisticsInterval = vmmdevSetStatisticsInterval;
2842 pThis->IPort.pfnVRDPChange = vmmdevVRDPChange;
2843 pThis->IPort.pfnCpuHotUnplug = vmmdevCpuHotUnplug;
2844 pThis->IPort.pfnCpuHotPlug = vmmdevCpuHotPlug;
2845
2846 /* Shared folder LED */
2847 pThis->SharedFolders.Led.u32Magic = PDMLED_MAGIC;
2848 pThis->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
2849
2850#ifdef VBOX_WITH_HGCM
2851 /* HGCM port */
2852 pThis->IHGCMPort.pfnCompleted = hgcmCompleted;
2853#endif
2854
2855 pThis->pCredentials = (VMMDEVCREDS *)RTMemAllocZ(sizeof(*pThis->pCredentials));
2856 if (!pThis->pCredentials)
2857 return VERR_NO_MEMORY;
2858
2859
2860 /*
2861 * Validate and read the configuration.
2862 */
2863 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns,
2864 "GetHostTimeDisabled|"
2865 "BackdoorLogDisabled|"
2866 "KeepCredentials|"
2867 "HeapEnabled|"
2868 "RamSize|"
2869 "TestingEnabled"
2870 ,
2871 "");
2872
2873 rc = CFGMR3QueryU64(pCfg, "RamSize", &pThis->cbGuestRAM);
2874 if (RT_FAILURE(rc))
2875 return PDMDEV_SET_ERROR(pDevIns, rc,
2876 N_("Configuration error: Failed querying \"RamSize\" as a 64-bit unsigned integer"));
2877
2878 rc = CFGMR3QueryBoolDef(pCfg, "GetHostTimeDisabled", &pThis->fGetHostTimeDisabled, false);
2879 if (RT_FAILURE(rc))
2880 return PDMDEV_SET_ERROR(pDevIns, rc,
2881 N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
2882
2883 rc = CFGMR3QueryBoolDef(pCfg, "BackdoorLogDisabled", &pThis->fBackdoorLogDisabled, false);
2884 if (RT_FAILURE(rc))
2885 return PDMDEV_SET_ERROR(pDevIns, rc,
2886 N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
2887
2888 rc = CFGMR3QueryBoolDef(pCfg, "KeepCredentials", &pThis->fKeepCredentials, false);
2889 if (RT_FAILURE(rc))
2890 return PDMDEV_SET_ERROR(pDevIns, rc,
2891 N_("Configuration error: Failed querying \"KeepCredentials\" as a boolean"));
2892
2893 rc = CFGMR3QueryBoolDef(pCfg, "HeapEnabled", &pThis->fHeapEnabled, true);
2894 if (RT_FAILURE(rc))
2895 return PDMDEV_SET_ERROR(pDevIns, rc,
2896 N_("Configuration error: Failed querying \"HeapEnabled\" as a boolean"));
2897
2898 rc = CFGMR3QueryBoolDef(pCfg, "RZEnabled", &pThis->fRZEnabled, true);
2899 if (RT_FAILURE(rc))
2900 return PDMDEV_SET_ERROR(pDevIns, rc,
2901 N_("Configuration error: Failed querying \"RZEnabled\" as a boolean"));
2902
2903#ifndef VBOX_WITHOUT_TESTING_FEATURES
2904 rc = CFGMR3QueryBoolDef(pCfg, "TestingEnabled", &pThis->fTestingEnabled, false);
2905 if (RT_FAILURE(rc))
2906 return PDMDEV_SET_ERROR(pDevIns, rc,
2907 N_("Configuration error: Failed querying \"TestingEnabled\" as a boolean"));
2908 /** @todo image-to-load-filename? */
2909#endif
2910
2911 /*
2912 * Create the critical section for the device.
2913 */
2914 rc = PDMDevHlpCritSectInit(pDevIns, &pThis->CritSect, RT_SRC_POS, "VMMDev");
2915 AssertRCReturn(rc, rc);
2916 /* Later: pDevIns->pCritSectR3 = &pThis->CritSect; */
2917
2918 /*
2919 * Register the backdoor logging port
2920 */
2921 rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog, NULL, NULL, NULL, "VMMDev backdoor logging");
2922 AssertRCReturn(rc, rc);
2923
2924#ifdef TIMESYNC_BACKDOOR
2925 /*
2926 * Alternative timesync source (temporary!)
2927 */
2928 rc = PDMDevHlpIOPortRegister(pDevIns, 0x505, 1, NULL, vmmdevTimesyncBackdoorWrite, vmmdevTimesyncBackdoorRead, NULL, NULL, "VMMDev timesync backdoor");
2929 AssertRCReturn(rc, rc);
2930#endif
2931
2932 /*
2933 * Allocate and initialize the MMIO2 memory.
2934 */
2935 rc = PDMDevHlpMMIO2Register(pDevIns, 1 /*iRegion*/, VMMDEV_RAM_SIZE, 0 /*fFlags*/, (void **)&pThis->pVMMDevRAMR3, "VMMDev");
2936 if (RT_FAILURE(rc))
2937 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2938 N_("Failed to allocate %u bytes of memory for the VMM device"), VMMDEV_RAM_SIZE);
2939 vmmdevInitRam(pThis);
2940
2941 if (pThis->fHeapEnabled)
2942 {
2943 rc = PDMDevHlpMMIO2Register(pDevIns, 2 /*iRegion*/, VMMDEV_HEAP_SIZE, 0 /*fFlags*/, (void **)&pThis->pVMMDevHeapR3, "VMMDev Heap");
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 heap"), PAGE_SIZE);
2947 }
2948
2949 /*
2950 * Register the PCI device.
2951 */
2952 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->dev);
2953 if (RT_FAILURE(rc))
2954 return rc;
2955 if (pThis->dev.devfn == 32 || iInstance != 0)
2956 Log(("!!WARNING!!: pThis->dev.devfn=%d (ignore if testcase or no started by Main)\n", pThis->dev.devfn));
2957 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
2958 if (RT_FAILURE(rc))
2959 return rc;
2960 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, vmmdevIORAMRegionMap);
2961 if (RT_FAILURE(rc))
2962 return rc;
2963 if (pThis->fHeapEnabled)
2964 {
2965 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 2, VMMDEV_HEAP_SIZE, PCI_ADDRESS_SPACE_MEM_PREFETCH, vmmdevIORAMRegionMap);
2966 if (RT_FAILURE(rc))
2967 return rc;
2968 }
2969
2970#ifndef VBOX_WITHOUT_TESTING_FEATURES
2971 /*
2972 * Initialize testing.
2973 */
2974 rc = vmmdevTestingInitialize(pDevIns);
2975 if (RT_FAILURE(rc))
2976 return rc;
2977#endif
2978
2979 /*
2980 * Get the corresponding connector interface
2981 */
2982 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "VMM Driver Port");
2983 if (RT_SUCCESS(rc))
2984 {
2985 pThis->pDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIVMMDEVCONNECTOR);
2986 AssertMsgReturn(pThis->pDrv, ("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
2987#ifdef VBOX_WITH_HGCM
2988 pThis->pHGCMDrv = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMIHGCMCONNECTOR);
2989 if (!pThis->pHGCMDrv)
2990 {
2991 Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Rrc\n", rc));
2992 /* this is not actually an error, just means that there is no support for HGCM */
2993 }
2994#endif
2995 /* Query the initial balloon size. */
2996 AssertPtr(pThis->pDrv->pfnQueryBalloonSize);
2997 rc = pThis->pDrv->pfnQueryBalloonSize(pThis->pDrv, &pThis->u32MemoryBalloonSize);
2998 AssertRC(rc);
2999
3000 Log(("Initial balloon size %x\n", pThis->u32MemoryBalloonSize));
3001 }
3002 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
3003 {
3004 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pReg->szName, pDevIns->iInstance));
3005 rc = VINF_SUCCESS;
3006 }
3007 else
3008 AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Rrc\n", rc), rc);
3009
3010 /*
3011 * Attach status driver for shared folders (optional).
3012 */
3013 PPDMIBASE pBase;
3014 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pThis->IBase, &pBase, "Status Port");
3015 if (RT_SUCCESS(rc))
3016 pThis->SharedFolders.pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS);
3017 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
3018 {
3019 AssertMsgFailed(("Failed to attach to status driver. rc=%Rrc\n", rc));
3020 return rc;
3021 }
3022
3023 /*
3024 * Register saved state and init the HGCM CmdList critsect.
3025 */
3026 rc = PDMDevHlpSSMRegisterEx(pDevIns, VMMDEV_SAVED_STATE_VERSION, sizeof(*pThis), NULL,
3027 NULL, vmmdevLiveExec, NULL,
3028 NULL, vmmdevSaveExec, NULL,
3029 NULL, vmmdevLoadExec, vmmdevLoadStateDone);
3030 AssertRCReturn(rc, rc);
3031
3032#ifdef VBOX_WITH_HGCM
3033 pThis->pHGCMCmdList = NULL;
3034 rc = RTCritSectInit(&pThis->critsectHGCMCmdList);
3035 AssertRCReturn(rc, rc);
3036 pThis->u32HGCMEnabled = 0;
3037#endif /* VBOX_WITH_HGCM */
3038
3039 /* In this version of VirtualBox the GUI checks whether "needs host cursor"
3040 * changes. */
3041 pThis->mouseCapabilities |= VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR;
3042
3043 PDMDevHlpSTAMRegisterF(pDevIns, &pThis->StatMemBalloonChunks, STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT, "Memory balloon size", "/Devices/VMMDev/BalloonChunks");
3044
3045 /* Generate a unique session id for this VM; it will be changed for each start, reset or restore.
3046 * This can be used for restore detection inside the guest.
3047 */
3048 pThis->idSession = ASMReadTSC();
3049 return rc;
3050}
3051
3052/**
3053 * The device registration structure.
3054 */
3055extern "C" const PDMDEVREG g_DeviceVMMDev =
3056{
3057 /* u32Version */
3058 PDM_DEVREG_VERSION,
3059 /* szName */
3060 "VMMDev",
3061 /* szRCMod */
3062 "VBoxDDGC.gc",
3063 /* szR0Mod */
3064 "VBoxDDR0.r0",
3065 /* pszDescription */
3066 "VirtualBox VMM Device\n",
3067 /* fFlags */
3068 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
3069 /* fClass */
3070 PDM_DEVREG_CLASS_VMM_DEV,
3071 /* cMaxInstances */
3072 1,
3073 /* cbInstance */
3074 sizeof(VMMDevState),
3075 /* pfnConstruct */
3076 vmmdevConstruct,
3077 /* pfnDestruct */
3078 NULL,
3079 /* pfnRelocate */
3080 vmmdevRelocate,
3081 /* pfnIOCtl */
3082 NULL,
3083 /* pfnPowerOn */
3084 NULL,
3085 /* pfnReset */
3086 vmmdevReset,
3087 /* pfnSuspend */
3088 NULL,
3089 /* pfnResume */
3090 NULL,
3091 /* pfnAttach */
3092 NULL,
3093 /* pfnDetach */
3094 NULL,
3095 /* pfnQueryInterface. */
3096 NULL,
3097 /* pfnInitComplete */
3098 NULL,
3099 /* pfnPowerOff */
3100 NULL,
3101 /* pfnSoftReset */
3102 NULL,
3103 /* u32VersionEnd */
3104 PDM_DEVREG_VERSION
3105};
3106#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
3107
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