VirtualBox

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

Last change on this file since 32619 was 32616, checked in by vboxsync, 14 years ago

VMMDev: return code.

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