VirtualBox

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

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

VMM,Devices: Automatically use a per-device lock instead of the giant IOM lock. With exception of the PIC, APIC, IOAPIC and PCI buses which are all using the PDM crit sect, there should be no calls between devices. So, this change should be relatively safe.

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