VirtualBox

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

Last change on this file since 8689 was 8689, checked in by vboxsync, 17 years ago

Tell main that we've cleared the guestInfo during reset otherwise the GUI will end up showing the wrong session info for a while.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 91.1 KB
Line 
1/* $Id: VBoxDev.cpp 8689 2008-05-07 22:10:24Z vboxsync $ */
2/** @file
3 * VMMDev - Guest <-> VMM/Host communication device.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/* #define LOG_ENABLED */
23
24/* Enable dev_vmm Log3 statements to get IRQ-related logging. */
25
26#define LOG_GROUP LOG_GROUP_DEV_VMM
27#include <VBox/log.h>
28
29#include <VBox/VBoxDev.h>
30#include <VBox/VBoxGuest.h>
31#include <VBox/param.h>
32#include <VBox/mm.h>
33#include <VBox/pgm.h>
34#include <VBox/err.h>
35#include <VBox/vm.h> /* for VM_IS_EMT */
36
37#include <iprt/assert.h>
38#include <iprt/string.h>
39#include <iprt/time.h>
40#ifndef IN_GC
41#include <iprt/mem.h>
42#endif
43
44#include "VMMDevState.h"
45
46#ifdef VBOX_HGCM
47#include "VMMDevHGCM.h"
48#endif
49
50#define PCIDEV_2_VMMDEVSTATE(pPciDev) ( (VMMDevState *)(pPciDev) )
51#define VMMDEVSTATE_2_DEVINS(pVMMDevState) ( (pVMMDevState)->pDevIns )
52
53#define VBOX_GUEST_ADDITIONS_VERSION_1_03(s) \
54 ((RT_HIWORD ((s)->guestInfo.additionsVersion) == 1) && \
55 (RT_LOWORD ((s)->guestInfo.additionsVersion) == 3))
56
57#define VBOX_GUEST_ADDITIONS_VERSION_OK(additionsVersion) \
58 (RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
59 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION))
60
61#define VBOX_GUEST_ADDITIONS_VERSION_OLD(additionsVersion) \
62 ((RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION) \
63 || ((RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
64 && RT_LOWORD(additionsVersion) <= RT_LOWORD(VMMDEV_VERSION))
65
66#define VBOX_GUEST_ADDITIONS_VERSION_TOO_OLD(additionsVersion) \
67 (RT_HIWORD(additionsVersion) < RT_HIWORD(VMMDEV_VERSION))
68
69#define VBOX_GUEST_ADDITIONS_VERSION_NEW(additionsVersion) \
70 ((RT_HIWORD(additionsVersion) > RT_HIWORD(VMMDEV_VERSION) \
71 || ((RT_HIWORD(additionsVersion) == RT_HIWORD(VMMDEV_VERSION) \
72 && RT_LOWORD(additionsVersion) > RT_LOWORD(VMMDEV_VERSION))
73
74#ifndef VBOX_DEVICE_STRUCT_TESTCASE
75
76/* Whenever host wants to inform guest about something
77 * an IRQ notification will be raised.
78 *
79 * VMMDev PDM interface will contain the guest notification method.
80 *
81 * There is a 32 bit event mask which will be read
82 * by guest on an interrupt. A non zero bit in the mask
83 * means that the specific event occured and requires
84 * processing on guest side.
85 *
86 * After reading the event mask guest must issue a
87 * generic request AcknowlegdeEvents.
88 *
89 * IRQ line is set to 1 (request) if there are unprocessed
90 * events, that is the event mask is not zero.
91 *
92 * After receiving an interrupt and checking event mask,
93 * the guest must process events using the event specific
94 * mechanism.
95 *
96 * That is if mouse capabilities were changed,
97 * guest will use VMMDev_GetMouseStatus generic request.
98 *
99 * Event mask is only a set of flags indicating that guest
100 * must proceed with a procedure.
101 *
102 * Unsupported events are therefore ignored.
103 * The guest additions must inform host which events they
104 * want to receive, to avoid unnecessary IRQ processing.
105 * By default no events are signalled to guest.
106 *
107 * This seems to be fast method. It requires
108 * only one context switch for an event processing.
109 *
110 */
111
112static void vmmdevSetIRQ_Legacy_EMT (VMMDevState *pVMMDevState)
113{
114 if (!pVMMDevState->fu32AdditionsOk)
115 {
116 Log(("vmmdevSetIRQ: IRQ is not generated, guest has not yet reported to us.\n"));
117 return;
118 }
119
120 uint32_t u32IRQLevel = 0;
121
122 /* Filter unsupported events */
123 uint32_t u32EventFlags =
124 pVMMDevState->u32HostEventFlags
125 & pVMMDevState->pVMMDevRAMHC->V.V1_03.u32GuestEventMask;
126
127 Log(("vmmdevSetIRQ: u32EventFlags = 0x%08X, "
128 "pVMMDevState->u32HostEventFlags = 0x%08X, "
129 "pVMMDevState->pVMMDevRAMHC->u32GuestEventMask = 0x%08X\n",
130 u32EventFlags,
131 pVMMDevState->u32HostEventFlags,
132 pVMMDevState->pVMMDevRAMHC->V.V1_03.u32GuestEventMask));
133
134 /* Move event flags to VMMDev RAM */
135 pVMMDevState->pVMMDevRAMHC->V.V1_03.u32HostEvents = u32EventFlags;
136
137 if (u32EventFlags)
138 {
139 /* Clear host flags which will be delivered to guest. */
140 pVMMDevState->u32HostEventFlags &= ~u32EventFlags;
141 Log(("vmmdevSetIRQ: pVMMDevState->u32HostEventFlags = 0x%08X\n",
142 pVMMDevState->u32HostEventFlags));
143 u32IRQLevel = 1;
144 }
145
146 /* Set IRQ level for pin 0 */
147 /** @todo make IRQ pin configurable, at least a symbolic constant */
148 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
149 PDMDevHlpPCISetIrqNoWait(pDevIns, 0, u32IRQLevel);
150 Log(("vmmdevSetIRQ: IRQ set %d\n", u32IRQLevel));
151}
152
153static void vmmdevMaybeSetIRQ_EMT (VMMDevState *pVMMDevState)
154{
155 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS (pVMMDevState);
156
157 Log3(("vmmdevMaybeSetIRQ_EMT: u32HostEventFlags = 0x%08X, u32GuestFilterMask = 0x%08X.\n",
158 pVMMDevState->u32HostEventFlags, pVMMDevState->u32GuestFilterMask));
159
160 if (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask)
161 {
162 pVMMDevState->pVMMDevRAMHC->V.V1_04.fHaveEvents = true;
163 PDMDevHlpPCISetIrqNoWait (pDevIns, 0, 1);
164 Log3(("vmmdevMaybeSetIRQ_EMT: IRQ set.\n"));
165 }
166}
167
168static void vmmdevNotifyGuest_EMT (VMMDevState *pVMMDevState, uint32_t u32EventMask)
169{
170 Log3(("VMMDevNotifyGuest_EMT: u32EventMask = 0x%08X.\n", u32EventMask));
171
172 if (VBOX_GUEST_ADDITIONS_VERSION_1_03 (pVMMDevState))
173 {
174 Log3(("VMMDevNotifyGuest_EMT: Old additions detected.\n"));
175
176 pVMMDevState->u32HostEventFlags |= u32EventMask;
177 vmmdevSetIRQ_Legacy_EMT (pVMMDevState);
178 }
179 else
180 {
181 Log3(("VMMDevNotifyGuest_EMT: New additions detected.\n"));
182
183 if (!pVMMDevState->fu32AdditionsOk)
184 {
185 pVMMDevState->u32HostEventFlags |= u32EventMask;
186 Log(("vmmdevNotifyGuest_EMT: IRQ is not generated, guest has not yet reported to us.\n"));
187 return;
188 }
189
190 const bool fHadEvents =
191 (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask) != 0;
192
193 Log3(("VMMDevNotifyGuest_EMT: fHadEvents = %d, u32HostEventFlags = 0x%08X, u32GuestFilterMask = 0x%08X.\n",
194 fHadEvents, pVMMDevState->u32HostEventFlags, pVMMDevState->u32GuestFilterMask));
195
196 pVMMDevState->u32HostEventFlags |= u32EventMask;
197
198 if (!fHadEvents)
199 vmmdevMaybeSetIRQ_EMT (pVMMDevState);
200 }
201}
202
203static void vmmdevCtlGuestFilterMask_EMT (VMMDevState *pVMMDevState,
204 uint32_t u32OrMask,
205 uint32_t u32NotMask)
206{
207 const bool fHadEvents =
208 (pVMMDevState->u32HostEventFlags & pVMMDevState->u32GuestFilterMask) != 0;
209
210 Log(("vmmdevCtlGuestFilterMask_EMT: u32OrMask = 0x%08X, u32NotMask = 0x%08X, fHadEvents = %d.\n", u32OrMask, u32NotMask, fHadEvents));
211 if (fHadEvents)
212 {
213 if (!pVMMDevState->fNewGuestFilterMask)
214 pVMMDevState->u32NewGuestFilterMask = pVMMDevState->u32GuestFilterMask;
215
216 pVMMDevState->u32NewGuestFilterMask |= u32OrMask;
217 pVMMDevState->u32NewGuestFilterMask &= ~u32NotMask;
218 pVMMDevState->fNewGuestFilterMask = true;
219 }
220 else
221 {
222 pVMMDevState->u32GuestFilterMask |= u32OrMask;
223 pVMMDevState->u32GuestFilterMask &= ~u32NotMask;
224 vmmdevMaybeSetIRQ_EMT (pVMMDevState);
225 }
226}
227
228void VMMDevCtlSetGuestFilterMask (VMMDevState *pVMMDevState,
229 uint32_t u32OrMask,
230 uint32_t u32NotMask)
231{
232 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
233 PVM pVM = PDMDevHlpGetVM(pDevIns);
234
235 Log(("VMMDevCtlSetGuestFilterMask: u32OrMask = 0x%08X, u32NotMask = 0x%08X.\n", u32OrMask, u32NotMask));
236
237 if (VM_IS_EMT(pVM))
238 {
239 vmmdevCtlGuestFilterMask_EMT (pVMMDevState, u32OrMask, u32NotMask);
240 }
241 else
242 {
243 int rc;
244 PVMREQ pReq;
245
246 rc = VMR3ReqCallVoid (pVM, &pReq, RT_INDEFINITE_WAIT,
247 (PFNRT) vmmdevCtlGuestFilterMask_EMT,
248 3, pVMMDevState, u32OrMask, u32NotMask);
249 AssertReleaseRC (rc);
250 VMR3ReqFree (pReq);
251 }
252}
253
254void VMMDevNotifyGuest (VMMDevState *pVMMDevState, uint32_t u32EventMask)
255{
256 PPDMDEVINS pDevIns = VMMDEVSTATE_2_DEVINS(pVMMDevState);
257 PVM pVM = PDMDevHlpGetVM(pDevIns);
258 int rc;
259 PVMREQ pReq;
260
261 Log3(("VMMDevNotifyGuest: u32EventMask = 0x%08X.\n", u32EventMask));
262
263 rc = VMR3ReqCallVoid (pVM, &pReq, RT_INDEFINITE_WAIT,
264 (PFNRT) vmmdevNotifyGuest_EMT,
265 2, pVMMDevState, u32EventMask);
266 AssertReleaseRC (rc);
267 VMR3ReqFree (pReq);
268}
269
270/**
271 * Port I/O Handler for OUT operations.
272 *
273 * @returns VBox status code.
274 *
275 * @param pDevIns The device instance.
276 * @param pvUser User argument - ignored.
277 * @param uPort Port number used for the IN operation.
278 * @param u32 The value to output.
279 * @param cb The value size in bytes.
280 */
281#undef LOG_GROUP
282#define LOG_GROUP LOG_GROUP_DEV_VMM_BACKDOOR
283
284static DECLCALLBACK(int) vmmdevBackdoorLog(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
285{
286 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
287
288 if (!pData->fBackdoorLogDisabled && cb == 1 && Port == RTLOG_DEBUG_PORT)
289 {
290
291 /* The raw version. */
292 switch (u32)
293 {
294 case '\r': Log2(("vmmdev: <return>\n")); break;
295 case '\n': Log2(("vmmdev: <newline>\n")); break;
296 case '\t': Log2(("vmmdev: <tab>\n")); break;
297 default: Log2(("vmmdev: %c (%02x)\n", u32, u32)); break;
298 }
299
300 /* The readable, buffered version. */
301 if (u32 == '\n' || u32 == '\r')
302 {
303 pData->szMsg[pData->iMsg] = '\0';
304 if (pData->iMsg)
305 LogRel(("Guest Log: %s\n", pData->szMsg));
306 pData->iMsg = 0;
307 }
308 else
309 {
310 if (pData->iMsg >= sizeof(pData->szMsg)-1)
311 {
312 pData->szMsg[pData->iMsg] = '\0';
313 LogRel(("Guest Log: %s\n", pData->szMsg));
314 pData->iMsg = 0;
315 }
316 pData->szMsg[pData->iMsg] = (char )u32;
317 pData->szMsg[++pData->iMsg] = '\0';
318 }
319 }
320 return VINF_SUCCESS;
321}
322#undef LOG_GROUP
323#define LOG_GROUP LOG_GROUP_DEV_VMM
324
325#ifdef TIMESYNC_BACKDOOR
326/**
327 * Port I/O Handler for OUT operations.
328 *
329 * @returns VBox status code.
330 *
331 * @param pDevIns The device instance.
332 * @param pvUser User argument - ignored.
333 * @param uPort Port number used for the IN operation.
334 * @param u32 The value to output.
335 * @param cb The value size in bytes.
336 */
337static DECLCALLBACK(int) vmmdevTimesyncBackdoorWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
338{
339 NOREF(pvUser);
340 if (cb == 4)
341 {
342 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
343 switch (u32)
344 {
345 case 0:
346 pData->fTimesyncBackdoorLo = false;
347 break;
348 case 1:
349 pData->fTimesyncBackdoorLo = true;
350 }
351 return VINF_SUCCESS;
352
353 }
354 return VINF_SUCCESS;
355}
356
357/**
358 * Port I/O Handler for backdoor timesync IN operations.
359 *
360 * @returns VBox status code.
361 *
362 * @param pDevIns The device instance.
363 * @param pvUser User argument - ignored.
364 * @param uPort Port number used for the IN operation.
365 * @param pu32 Where to store the result.
366 * @param cb Number of bytes read.
367 */
368static DECLCALLBACK(int) vmmdevTimesyncBackdoorRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
369{
370 int rc;
371 NOREF(pvUser);
372 if (cb == 4)
373 {
374 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
375 RTTIMESPEC now;
376
377 if (pData->fTimesyncBackdoorLo)
378 {
379 *pu32 = (uint32_t)(pData->hostTime & (uint64_t)0xFFFFFFFF);
380 }
381 else
382 {
383 pData->hostTime = RTTimeSpecGetMilli(PDMDevHlpUTCNow(pDevIns, &now));
384 *pu32 = (uint32_t)(pData->hostTime >> 32);
385 }
386 rc = VINF_SUCCESS;
387 }
388 else
389 rc = VERR_IOM_IOPORT_UNUSED;
390 return rc;
391}
392#endif /* TIMESYNC_BACKDOOR */
393
394/**
395 * Port I/O Handler for the generic request interface
396 * @see FNIOMIOPORTOUT for details.
397 */
398static DECLCALLBACK(int) vmmdevRequestHandler(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
399{
400 VMMDevState *pData = (VMMDevState*)pvUser;
401 int rcRet = VINF_SUCCESS;
402
403 /*
404 * The caller has passed the guest context physical address
405 * of the request structure. Copy the request packet.
406 */
407 VMMDevRequestHeader requestHeader = {0};
408 VMMDevRequestHeader *pRequestHeader = NULL;
409
410 PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)u32, &requestHeader, sizeof(requestHeader));
411
412 /* the structure size must be greater or equal to the header size */
413 if (requestHeader.size < sizeof(VMMDevRequestHeader))
414 {
415 Log(("VMMDev request header size too small! size = %d\n", requestHeader.size));
416 rcRet = VINF_SUCCESS;
417 goto end;
418 }
419
420 /* check the version of the header structure */
421 if (requestHeader.version != VMMDEV_REQUEST_HEADER_VERSION)
422 {
423 Log(("VMMDev: guest header version (0x%08X) differs from ours (0x%08X)\n", requestHeader.version, VMMDEV_REQUEST_HEADER_VERSION));
424 rcRet = VINF_SUCCESS;
425 goto end;
426 }
427
428 Log2(("VMMDev request issued: %d\n", requestHeader.requestType));
429
430 if ( requestHeader.requestType != VMMDevReq_ReportGuestInfo
431 && !pData->fu32AdditionsOk)
432 {
433 Log(("VMMDev: guest has not yet reported to us. Refusing operation.\n"));
434 requestHeader.rc = VERR_NOT_SUPPORTED;
435 rcRet = VINF_SUCCESS;
436 goto end;
437 }
438
439 /* Check upper limit */
440 if (requestHeader.size > VMMDEV_MAX_VMMDEVREQ_SIZE)
441 {
442 LogRel(("VMMDev: request packet too big (%x). Refusing operation.\n", requestHeader.size));
443 requestHeader.rc = VERR_NOT_SUPPORTED;
444 rcRet = VINF_SUCCESS;
445 goto end;
446 }
447
448 /* Read the entire request packet */
449 pRequestHeader = (VMMDevRequestHeader *)RTMemAlloc(requestHeader.size);
450 if (!pRequestHeader)
451 {
452 Log(("VMMDev: RTMemAlloc failed!\n"));
453 rcRet = VINF_SUCCESS;
454 requestHeader.rc = VERR_NO_MEMORY;
455 goto end;
456 }
457 PDMDevHlpPhysRead(pDevIns, (RTGCPHYS)u32, pRequestHeader, requestHeader.size);
458
459 /* which request was sent? */
460 switch (pRequestHeader->requestType)
461 {
462 /*
463 * Guest wants to give up a timeslice
464 */
465 case VMMDevReq_Idle:
466 {
467 /* just return to EMT telling it that we want to halt */
468 rcRet = VINF_EM_HALT;
469 break;
470 }
471
472 /*
473 * Guest is reporting its information
474 */
475 case VMMDevReq_ReportGuestInfo:
476 {
477 if (pRequestHeader->size < sizeof(VMMDevReportGuestInfo))
478 {
479 AssertMsgFailed(("VMMDev guest information structure has invalid size!\n"));
480 pRequestHeader->rc = VERR_INVALID_PARAMETER;
481 }
482 else
483 {
484 VMMDevReportGuestInfo *guestInfo = (VMMDevReportGuestInfo*)pRequestHeader;
485
486 if (memcmp (&pData->guestInfo, &guestInfo->guestInfo, sizeof (guestInfo->guestInfo)) != 0)
487 {
488 /* make a copy of supplied information */
489 pData->guestInfo = guestInfo->guestInfo;
490
491 /* Check additions version */
492 pData->fu32AdditionsOk = VBOX_GUEST_ADDITIONS_VERSION_OK(pData->guestInfo.additionsVersion);
493
494 LogRel(("Guest Additions information report: additionsVersion = 0x%08X osType = 0x%08X\n",
495 pData->guestInfo.additionsVersion,
496 pData->guestInfo.osType));
497 pData->pDrv->pfnUpdateGuestVersion(pData->pDrv, &pData->guestInfo);
498 }
499
500 if (pData->fu32AdditionsOk)
501 {
502 pRequestHeader->rc = VINF_SUCCESS;
503 }
504 else
505 {
506 pRequestHeader->rc = VERR_VERSION_MISMATCH;
507 }
508 }
509 break;
510 }
511
512 /* Report guest capabilities */
513 case VMMDevReq_ReportGuestCapabilities:
514 {
515 if (pRequestHeader->size != sizeof(VMMDevReqGuestCapabilities))
516 {
517 AssertMsgFailed(("VMMDev guest caps structure has invalid size!\n"));
518 pRequestHeader->rc = VERR_INVALID_PARAMETER;
519 }
520 else
521 {
522 VMMDevReqGuestCapabilities *guestCaps = (VMMDevReqGuestCapabilities*)pRequestHeader;
523
524 /* Enable this automatically for guests using the old
525 request to report their capabilities. */
526 /** @todo change this when we next bump the interface version */
527 guestCaps->caps |= VMMDEV_GUEST_SUPPORTS_GRAPHICS;
528 if (pData->guestCaps != guestCaps->caps)
529 {
530 /* make a copy of supplied information */
531 pData->guestCaps = guestCaps->caps;
532
533 LogRel(("Guest Additions capability report: (0x%x) "
534 "seamless: %s, "
535 "hostWindowMapping: %s, "
536 "graphics: %s\n",
537 guestCaps->caps,
538 guestCaps->caps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
539 guestCaps->caps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no",
540 guestCaps->caps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? "yes" : "no"));
541
542 pData->pDrv->pfnUpdateGuestCapabilities(pData->pDrv, guestCaps->caps);
543 }
544 pRequestHeader->rc = VINF_SUCCESS;
545 }
546 break;
547 }
548
549 /* Change guest capabilities */
550 case VMMDevReq_SetGuestCapabilities:
551 {
552 if (pRequestHeader->size != sizeof(VMMDevReqGuestCapabilities2))
553 {
554 AssertMsgFailed(("VMMDev guest caps structure has invalid size!\n"));
555 pRequestHeader->rc = VERR_INVALID_PARAMETER;
556 }
557 else
558 {
559 VMMDevReqGuestCapabilities2 *guestCaps = (VMMDevReqGuestCapabilities2*)pRequestHeader;
560
561 pData->guestCaps |= guestCaps->u32OrMask;
562 pData->guestCaps &= ~guestCaps->u32NotMask;
563
564 LogRel(("Guest Additions capability report: (0x%x) "
565 "seamless: %s, "
566 "hostWindowMapping: %s, "
567 "graphics: %s\n",
568 pData->guestCaps,
569 pData->guestCaps & VMMDEV_GUEST_SUPPORTS_SEAMLESS ? "yes" : "no",
570 pData->guestCaps & VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING ? "yes" : "no",
571 pData->guestCaps & VMMDEV_GUEST_SUPPORTS_GRAPHICS ? "yes" : "no"));
572
573 pData->pDrv->pfnUpdateGuestCapabilities(pData->pDrv, pData->guestCaps);
574 pRequestHeader->rc = VINF_SUCCESS;
575 }
576 break;
577 }
578
579 /*
580 * Retrieve mouse information
581 */
582 case VMMDevReq_GetMouseStatus:
583 {
584 if (pRequestHeader->size != sizeof(VMMDevReqMouseStatus))
585 {
586 AssertMsgFailed(("VMMDev mouse status structure has invalid size!\n"));
587 pRequestHeader->rc = VERR_INVALID_PARAMETER;
588 }
589 else
590 {
591 VMMDevReqMouseStatus *mouseStatus = (VMMDevReqMouseStatus*)pRequestHeader;
592 mouseStatus->mouseFeatures = 0;
593 if (pData->mouseCapabilities & VMMDEV_MOUSEHOSTWANTSABS)
594 {
595 mouseStatus->mouseFeatures |= VBOXGUEST_MOUSE_HOST_CAN_ABSOLUTE;
596 }
597 if (pData->mouseCapabilities & VMMDEV_MOUSEGUESTWANTSABS)
598 {
599 mouseStatus->mouseFeatures |= VBOXGUEST_MOUSE_GUEST_CAN_ABSOLUTE;
600 }
601 if (pData->mouseCapabilities & VMMDEV_MOUSEHOSTCANNOTHWPOINTER)
602 {
603 mouseStatus->mouseFeatures |= VBOXGUEST_MOUSE_HOST_CANNOT_HWPOINTER;
604 }
605 mouseStatus->pointerXPos = pData->mouseXAbs;
606 mouseStatus->pointerYPos = pData->mouseYAbs;
607 Log2(("returning mouse status: features = %d, absX = %d, absY = %d\n", mouseStatus->mouseFeatures,
608 mouseStatus->pointerXPos, mouseStatus->pointerYPos));
609 pRequestHeader->rc = VINF_SUCCESS;
610 }
611 break;
612 }
613
614 /*
615 * Set mouse information
616 */
617 case VMMDevReq_SetMouseStatus:
618 {
619 if (pRequestHeader->size != sizeof(VMMDevReqMouseStatus))
620 {
621 AssertMsgFailed(("VMMDev mouse status structure has invalid size %d (%#x) version=%d!\n",
622 pRequestHeader->size, pRequestHeader->size, pRequestHeader->size, pRequestHeader->version));
623 pRequestHeader->rc = VERR_INVALID_PARAMETER;
624 }
625 else
626 {
627 bool bCapsChanged = false;
628
629 VMMDevReqMouseStatus *mouseStatus = (VMMDevReqMouseStatus*)pRequestHeader;
630
631 /* check if the guest wants absolute coordinates */
632 if (mouseStatus->mouseFeatures & VBOXGUEST_MOUSE_GUEST_CAN_ABSOLUTE)
633 {
634 /* set the capability flag and the changed flag if it's actually a change */
635 if (!(pData->mouseCapabilities & VMMDEV_MOUSEGUESTWANTSABS))
636 {
637 pData->mouseCapabilities |= VMMDEV_MOUSEGUESTWANTSABS;
638 bCapsChanged = true;
639 LogRel(("Guest requests mouse pointer integration\n"));
640 }
641 } else
642 {
643 if (pData->mouseCapabilities & VMMDEV_MOUSEGUESTWANTSABS)
644 {
645 pData->mouseCapabilities &= ~VMMDEV_MOUSEGUESTWANTSABS;
646 bCapsChanged = true;
647 LogRel(("Guest disables mouse pointer integration\n"));
648 }
649 }
650 if (mouseStatus->mouseFeatures & VBOXGUEST_MOUSE_GUEST_NEEDS_HOST_CURSOR)
651 pData->mouseCapabilities |= VMMDEV_MOUSEGUESTNEEDSHOSTCUR;
652 else
653 pData->mouseCapabilities &= ~VMMDEV_MOUSEGUESTNEEDSHOSTCUR;
654
655 /*
656 * Notify connector if something has changed
657 */
658 if (bCapsChanged)
659 {
660 Log(("VMMDevReq_SetMouseStatus: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
661 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
662 }
663 pRequestHeader->rc = VINF_SUCCESS;
664 }
665
666 break;
667 }
668
669 /*
670 * Set a new mouse pointer shape
671 */
672 case VMMDevReq_SetPointerShape:
673 {
674 if (pRequestHeader->size < sizeof(VMMDevReqMousePointer))
675 {
676 AssertMsg(pRequestHeader->size == 0x10028 && pRequestHeader->version == 10000, /* don't bitch about legacy!!! */
677 ("VMMDev mouse shape structure has invalid size %d (%#x) version=%d!\n",
678 pRequestHeader->size, pRequestHeader->size, pRequestHeader->size, pRequestHeader->version));
679 pRequestHeader->rc = VERR_INVALID_PARAMETER;
680 }
681 else
682 {
683 VMMDevReqMousePointer *pointerShape = (VMMDevReqMousePointer*)pRequestHeader;
684
685 bool fVisible = (pointerShape->fFlags & VBOX_MOUSE_POINTER_VISIBLE) != 0;
686 bool fAlpha = (pointerShape->fFlags & VBOX_MOUSE_POINTER_ALPHA) != 0;
687 bool fShape = (pointerShape->fFlags & VBOX_MOUSE_POINTER_SHAPE) != 0;
688
689 Log(("VMMDevReq_SetPointerShape: visible: %d, alpha: %d, shape = %d, width: %d, height: %d\n",
690 fVisible, fAlpha, fShape, pointerShape->width, pointerShape->height));
691
692 if (pRequestHeader->size == sizeof(VMMDevReqMousePointer))
693 {
694 /* The guest did not provide the shape actually. */
695 fShape = false;
696 }
697
698 /* forward call to driver */
699 if (fShape)
700 {
701 pData->pDrv->pfnUpdatePointerShape(pData->pDrv,
702 fVisible,
703 fAlpha,
704 pointerShape->xHot, pointerShape->yHot,
705 pointerShape->width, pointerShape->height,
706 pointerShape->pointerData);
707 }
708 else
709 {
710 pData->pDrv->pfnUpdatePointerShape(pData->pDrv,
711 fVisible,
712 0,
713 0, 0,
714 0, 0,
715 NULL);
716 }
717 pRequestHeader->rc = VINF_SUCCESS;
718 }
719 break;
720 }
721
722 /*
723 * Query the system time from the host
724 */
725 case VMMDevReq_GetHostTime:
726 {
727 if (pRequestHeader->size != sizeof(VMMDevReqHostTime))
728 {
729 AssertMsgFailed(("VMMDev host time structure has invalid size!\n"));
730 pRequestHeader->rc = VERR_INVALID_PARAMETER;
731 }
732 else if (RT_UNLIKELY(pData->fGetHostTimeDisabled))
733 pRequestHeader->rc = VERR_NOT_SUPPORTED;
734 else
735 {
736 VMMDevReqHostTime *hostTimeReq = (VMMDevReqHostTime*)pRequestHeader;
737 RTTIMESPEC now;
738 hostTimeReq->time = RTTimeSpecGetMilli(PDMDevHlpUTCNow(pDevIns, &now));
739 pRequestHeader->rc = VINF_SUCCESS;
740 }
741 break;
742 }
743
744 /*
745 * Query information about the hypervisor
746 */
747 case VMMDevReq_GetHypervisorInfo:
748 {
749 if (pRequestHeader->size != sizeof(VMMDevReqHypervisorInfo))
750 {
751 AssertMsgFailed(("VMMDev hypervisor info structure has invalid size!\n"));
752 pRequestHeader->rc = VERR_INVALID_PARAMETER;
753 }
754 else
755 {
756 VMMDevReqHypervisorInfo *hypervisorInfo = (VMMDevReqHypervisorInfo*)pRequestHeader;
757 PVM pVM = PDMDevHlpGetVM(pDevIns);
758 pRequestHeader->rc = PGMR3MappingsSize(pVM, &hypervisorInfo->hypervisorSize);
759 }
760 break;
761 }
762
763 /*
764 * Set hypervisor information
765 */
766 case VMMDevReq_SetHypervisorInfo:
767 {
768 if (pRequestHeader->size != sizeof(VMMDevReqHypervisorInfo))
769 {
770 AssertMsgFailed(("VMMDev hypervisor info structure has invalid size!\n"));
771 pRequestHeader->rc = VERR_INVALID_PARAMETER;
772 }
773 else
774 {
775 VMMDevReqHypervisorInfo *hypervisorInfo = (VMMDevReqHypervisorInfo*)pRequestHeader;
776 PVM pVM = PDMDevHlpGetVM(pDevIns);
777 if (hypervisorInfo->hypervisorStart == 0)
778 pRequestHeader->rc = PGMR3MappingsUnfix(pVM);
779 else
780 {
781 /* only if the client has queried the size before! */
782 uint32_t mappingsSize;
783 pRequestHeader->rc = PGMR3MappingsSize(pVM, &mappingsSize);
784 if (VBOX_SUCCESS(pRequestHeader->rc) && hypervisorInfo->hypervisorSize == mappingsSize)
785 {
786 /* new reservation */
787 pRequestHeader->rc = PGMR3MappingsFix(pVM, hypervisorInfo->hypervisorStart,
788 hypervisorInfo->hypervisorSize);
789 LogRel(("Guest reported fixed hypervisor window at 0x%p (size = 0x%x, rc = %Vrc)\n",
790 hypervisorInfo->hypervisorStart,
791 hypervisorInfo->hypervisorSize,
792 pRequestHeader->rc));
793 }
794 }
795 }
796 break;
797 }
798
799 /*
800 * Set the system power status
801 */
802 case VMMDevReq_SetPowerStatus:
803 {
804 if (pRequestHeader->size != sizeof(VMMDevPowerStateRequest))
805 {
806 AssertMsgFailed(("VMMDev power state request structure has invalid size!\n"));
807 pRequestHeader->rc = VERR_INVALID_PARAMETER;
808 }
809 else
810 {
811 VMMDevPowerStateRequest *powerStateRequest = (VMMDevPowerStateRequest*)pRequestHeader;
812 switch(powerStateRequest->powerState)
813 {
814 case VMMDevPowerState_Pause:
815 {
816 LogRel(("Guest requests the VM to be suspended (paused)\n"));
817 pRequestHeader->rc = rcRet = PDMDevHlpVMSuspend(pDevIns);
818 break;
819 }
820
821 case VMMDevPowerState_PowerOff:
822 {
823 LogRel(("Guest requests the VM to be turned off\n"));
824 pRequestHeader->rc = rcRet = PDMDevHlpVMPowerOff(pDevIns);
825 break;
826 }
827
828 case VMMDevPowerState_SaveState:
829 {
830 /** @todo no API for that yet */
831 pRequestHeader->rc = VERR_NOT_IMPLEMENTED;
832 break;
833 }
834
835 default:
836 AssertMsgFailed(("VMMDev invalid power state request: %d\n", powerStateRequest->powerState));
837 pRequestHeader->rc = VERR_INVALID_PARAMETER;
838 break;
839 }
840 }
841 break;
842 }
843
844 /*
845 * Get display change request
846 */
847 case VMMDevReq_GetDisplayChangeRequest:
848 {
849 if (pRequestHeader->size != sizeof(VMMDevDisplayChangeRequest))
850 {
851 /* Assert only if the size also not equal to a previous version size to prevent
852 * assertion with old additions.
853 */
854 AssertMsg(pRequestHeader->size == sizeof(VMMDevDisplayChangeRequest) - sizeof (uint32_t),
855 ("VMMDev display change request structure has invalid size!\n"));
856 pRequestHeader->rc = VERR_INVALID_PARAMETER;
857 }
858 else
859 {
860 VMMDevDisplayChangeRequest *displayChangeRequest = (VMMDevDisplayChangeRequest*)pRequestHeader;
861 /* just pass on the information */
862 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d\n",
863 pData->displayChangeRequest.xres, pData->displayChangeRequest.yres, pData->displayChangeRequest.bpp));
864 displayChangeRequest->xres = pData->displayChangeRequest.xres;
865 displayChangeRequest->yres = pData->displayChangeRequest.yres;
866 displayChangeRequest->bpp = pData->displayChangeRequest.bpp;
867
868 if (displayChangeRequest->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
869 {
870 /* Remember which resolution the client has queried. */
871 pData->lastReadDisplayChangeRequest = pData->displayChangeRequest;
872 }
873
874 pRequestHeader->rc = VINF_SUCCESS;
875 }
876 break;
877 }
878
879 case VMMDevReq_GetDisplayChangeRequest2:
880 {
881 if (pRequestHeader->size != sizeof(VMMDevDisplayChangeRequest2))
882 {
883 pRequestHeader->rc = VERR_INVALID_PARAMETER;
884 }
885 else
886 {
887 VMMDevDisplayChangeRequest2 *displayChangeRequest = (VMMDevDisplayChangeRequest2*)pRequestHeader;
888 /* just pass on the information */
889 Log(("VMMDev: returning display change request xres = %d, yres = %d, bpp = %d at %d\n",
890 pData->displayChangeRequest.xres, pData->displayChangeRequest.yres, pData->displayChangeRequest.bpp, pData->displayChangeRequest.display));
891 displayChangeRequest->xres = pData->displayChangeRequest.xres;
892 displayChangeRequest->yres = pData->displayChangeRequest.yres;
893 displayChangeRequest->bpp = pData->displayChangeRequest.bpp;
894 displayChangeRequest->display = pData->displayChangeRequest.display;
895
896 if (displayChangeRequest->eventAck == VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST)
897 {
898 /* Remember which resolution the client has queried. */
899 pData->lastReadDisplayChangeRequest = pData->displayChangeRequest;
900 }
901
902 pRequestHeader->rc = VINF_SUCCESS;
903 }
904 break;
905 }
906
907 /*
908 * Query whether the given video mode is supported
909 */
910 case VMMDevReq_VideoModeSupported:
911 {
912 if (pRequestHeader->size != sizeof(VMMDevVideoModeSupportedRequest))
913 {
914 AssertMsgFailed(("VMMDev video mode supported request structure has invalid size!\n"));
915 pRequestHeader->rc = VERR_INVALID_PARAMETER;
916 }
917 else
918 {
919 VMMDevVideoModeSupportedRequest *videoModeSupportedRequest = (VMMDevVideoModeSupportedRequest*)pRequestHeader;
920 /* forward the call */
921 pRequestHeader->rc = pData->pDrv->pfnVideoModeSupported(pData->pDrv,
922 videoModeSupportedRequest->width,
923 videoModeSupportedRequest->height,
924 videoModeSupportedRequest->bpp,
925 &videoModeSupportedRequest->fSupported);
926 }
927 break;
928 }
929
930 /*
931 * Query the height reduction in pixels
932 */
933 case VMMDevReq_GetHeightReduction:
934 {
935 if (pRequestHeader->size != sizeof(VMMDevGetHeightReductionRequest))
936 {
937 AssertMsgFailed(("VMMDev height reduction request structure has invalid size!\n"));
938 pRequestHeader->rc = VERR_INVALID_PARAMETER;
939 }
940 else
941 {
942 VMMDevGetHeightReductionRequest *heightReductionRequest = (VMMDevGetHeightReductionRequest*)pRequestHeader;
943 /* forward the call */
944 pRequestHeader->rc = pData->pDrv->pfnGetHeightReduction(pData->pDrv,
945 &heightReductionRequest->heightReduction);
946 }
947 break;
948 }
949
950 /*
951 * Acknowledge VMMDev events
952 */
953 case VMMDevReq_AcknowledgeEvents:
954 {
955 if (pRequestHeader->size != sizeof(VMMDevEvents))
956 {
957 AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
958 pRequestHeader->rc = VERR_INVALID_PARAMETER;
959 }
960 else
961 {
962 if (VBOX_GUEST_ADDITIONS_VERSION_1_03 (pData))
963 {
964 vmmdevSetIRQ_Legacy_EMT (pData);
965 }
966 else
967 {
968 VMMDevEvents *pAckRequest;
969
970 if (pData->fNewGuestFilterMask)
971 {
972 pData->fNewGuestFilterMask = false;
973 pData->u32GuestFilterMask = pData->u32NewGuestFilterMask;
974 }
975
976 pAckRequest = (VMMDevEvents *)pRequestHeader;
977 pAckRequest->events =
978 pData->u32HostEventFlags & pData->u32GuestFilterMask;
979
980 pData->u32HostEventFlags &= ~pData->u32GuestFilterMask;
981 pData->pVMMDevRAMHC->V.V1_04.fHaveEvents = false;
982 PDMDevHlpPCISetIrqNoWait (pData->pDevIns, 0, 0);
983 }
984 pRequestHeader->rc = VINF_SUCCESS;
985 }
986 break;
987 }
988
989 /*
990 * Change guest filter mask
991 */
992 case VMMDevReq_CtlGuestFilterMask:
993 {
994 if (pRequestHeader->size != sizeof(VMMDevCtlGuestFilterMask))
995 {
996 AssertMsgFailed(("VMMDevReq_AcknowledgeEvents structure has invalid size!\n"));
997 pRequestHeader->rc = VERR_INVALID_PARAMETER;
998 }
999 else
1000 {
1001 VMMDevCtlGuestFilterMask *pCtlMaskRequest;
1002
1003 pCtlMaskRequest = (VMMDevCtlGuestFilterMask *)pRequestHeader;
1004 /* The HGCM events are enabled by the VMMDev device automatically when any
1005 * HGCM command is issued. The guest then can not disable these events.
1006 */
1007 vmmdevCtlGuestFilterMask_EMT (pData,
1008 pCtlMaskRequest->u32OrMask,
1009 pCtlMaskRequest->u32NotMask & ~VMMDEV_EVENT_HGCM);
1010 pRequestHeader->rc = VINF_SUCCESS;
1011
1012 }
1013 break;
1014 }
1015
1016#ifdef VBOX_HGCM
1017 /*
1018 * Process HGCM request
1019 */
1020 case VMMDevReq_HGCMConnect:
1021 {
1022 if (pRequestHeader->size < sizeof(VMMDevHGCMConnect))
1023 {
1024 AssertMsgFailed(("VMMDevReq_HGCMConnect structure has invalid size!\n"));
1025 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1026 }
1027 else if (!pData->pHGCMDrv)
1028 {
1029 Log(("VMMDevReq_HGCMConnect HGCM Connector is NULL!\n"));
1030 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1031 }
1032 else
1033 {
1034 VMMDevHGCMConnect *pHGCMConnect = (VMMDevHGCMConnect *)pRequestHeader;
1035
1036 Log(("VMMDevReq_HGCMConnect\n"));
1037
1038 pRequestHeader->rc = vmmdevHGCMConnect (pData, pHGCMConnect, (RTGCPHYS)u32);
1039 }
1040 break;
1041 }
1042
1043 case VMMDevReq_HGCMDisconnect:
1044 {
1045 if (pRequestHeader->size < sizeof(VMMDevHGCMDisconnect))
1046 {
1047 AssertMsgFailed(("VMMDevReq_HGCMDisconnect structure has invalid size!\n"));
1048 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1049 }
1050 else if (!pData->pHGCMDrv)
1051 {
1052 Log(("VMMDevReq_HGCMDisconnect HGCM Connector is NULL!\n"));
1053 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1054 }
1055 else
1056 {
1057 VMMDevHGCMDisconnect *pHGCMDisconnect = (VMMDevHGCMDisconnect *)pRequestHeader;
1058
1059 Log(("VMMDevReq_VMMDevHGCMDisconnect\n"));
1060 pRequestHeader->rc = vmmdevHGCMDisconnect (pData, pHGCMDisconnect, (RTGCPHYS)u32);
1061 }
1062 break;
1063 }
1064
1065 case VMMDevReq_HGCMCall:
1066 {
1067 if (pRequestHeader->size < sizeof(VMMDevHGCMCall))
1068 {
1069 AssertMsgFailed(("VMMDevReq_HGCMCall structure has invalid size!\n"));
1070 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1071 }
1072 else if (!pData->pHGCMDrv)
1073 {
1074 Log(("VMMDevReq_HGCMCall HGCM Connector is NULL!\n"));
1075 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1076 }
1077 else
1078 {
1079 VMMDevHGCMCall *pHGCMCall = (VMMDevHGCMCall *)pRequestHeader;
1080
1081 Log2(("VMMDevReq_HGCMCall: sizeof (VMMDevHGCMRequest) = %04X\n", sizeof (VMMDevHGCMCall)));
1082 Log2(("%.*Vhxd\n", pRequestHeader->size, pRequestHeader));
1083
1084 pRequestHeader->rc = vmmdevHGCMCall (pData, pHGCMCall, (RTGCPHYS)u32);
1085 }
1086 break;
1087 }
1088#endif /* VBOX_HGCM */
1089
1090 case VMMDevReq_VideoAccelEnable:
1091 {
1092 if (pRequestHeader->size < sizeof(VMMDevVideoAccelEnable))
1093 {
1094 Log(("VMMDevReq_VideoAccelEnable request size too small!!!\n"));
1095 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1096 }
1097 else if (!pData->pDrv)
1098 {
1099 Log(("VMMDevReq_VideoAccelEnable Connector is NULL!!!\n"));
1100 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1101 }
1102 else
1103 {
1104 VMMDevVideoAccelEnable *ptr = (VMMDevVideoAccelEnable *)pRequestHeader;
1105
1106 if (ptr->cbRingBuffer != VBVA_RING_BUFFER_SIZE)
1107 {
1108 /* The guest driver seems compiled with another headers. */
1109 Log(("VMMDevReq_VideoAccelEnable guest ring buffer size %d, should be %d!!!\n", ptr->cbRingBuffer, VBVA_RING_BUFFER_SIZE));
1110 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1111 }
1112 else
1113 {
1114 /* The request is correct. */
1115 ptr->fu32Status |= VBVA_F_STATUS_ACCEPTED;
1116
1117 LogFlow(("VMMDevReq_VideoAccelEnable ptr->u32Enable = %d\n", ptr->u32Enable));
1118
1119 pRequestHeader->rc = ptr->u32Enable?
1120 pData->pDrv->pfnVideoAccelEnable (pData->pDrv, true, &pData->pVMMDevRAMHC->vbvaMemory):
1121 pData->pDrv->pfnVideoAccelEnable (pData->pDrv, false, NULL);
1122
1123 if ( ptr->u32Enable
1124 && VBOX_SUCCESS (pRequestHeader->rc))
1125 {
1126 ptr->fu32Status |= VBVA_F_STATUS_ENABLED;
1127
1128 /* Remember that guest successfully enabled acceleration.
1129 * We need to reestablish it on restoring the VM from saved state.
1130 */
1131 pData->u32VideoAccelEnabled = 1;
1132 }
1133 else
1134 {
1135 /* The acceleration was not enabled. Remember that. */
1136 pData->u32VideoAccelEnabled = 0;
1137 }
1138 }
1139 }
1140 break;
1141 }
1142
1143 case VMMDevReq_VideoAccelFlush:
1144 {
1145 if (pRequestHeader->size < sizeof(VMMDevVideoAccelFlush))
1146 {
1147 AssertMsgFailed(("VMMDevReq_VideoAccelFlush request size too small.\n"));
1148 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1149 }
1150 else if (!pData->pDrv)
1151 {
1152 Log(("VMMDevReq_VideoAccelFlush Connector is NULL!\n"));
1153 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1154 }
1155 else
1156 {
1157 pData->pDrv->pfnVideoAccelFlush (pData->pDrv);
1158
1159 pRequestHeader->rc = VINF_SUCCESS;
1160 }
1161 break;
1162 }
1163
1164 case VMMDevReq_VideoSetVisibleRegion:
1165 {
1166 if (pRequestHeader->size < sizeof(VMMDevVideoSetVisibleRegion))
1167 {
1168 Log(("VMMDevReq_VideoSetVisibleRegion request size too small!!!\n"));
1169 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1170 }
1171 else if (!pData->pDrv)
1172 {
1173 Log(("VMMDevReq_VideoSetVisibleRegion Connector is NULL!!!\n"));
1174 pRequestHeader->rc = VERR_NOT_SUPPORTED;
1175 }
1176 else
1177 {
1178 VMMDevVideoSetVisibleRegion *ptr = (VMMDevVideoSetVisibleRegion *)pRequestHeader;
1179
1180 if (!ptr->cRect)
1181 {
1182 Log(("VMMDevReq_VideoSetVisibleRegion no rectangles!!!\n"));
1183 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1184 }
1185 else
1186 if (pRequestHeader->size != sizeof(VMMDevVideoSetVisibleRegion) + (ptr->cRect-1)*sizeof(RTRECT))
1187 {
1188 Log(("VMMDevReq_VideoSetVisibleRegion request size too small!!!\n"));
1189 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1190 }
1191 else
1192 {
1193 Log(("VMMDevReq_VideoSetVisibleRegion %d rectangles\n", ptr->cRect));
1194 /* forward the call */
1195 pRequestHeader->rc = pData->pDrv->pfnSetVisibleRegion(pData->pDrv, ptr->cRect, &ptr->Rect);
1196 }
1197 }
1198 break;
1199 }
1200
1201 case VMMDevReq_GetSeamlessChangeRequest:
1202 {
1203 if (pRequestHeader->size != sizeof(VMMDevSeamlessChangeRequest))
1204 {
1205 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1206 }
1207 else
1208 {
1209 VMMDevSeamlessChangeRequest *seamlessChangeRequest = (VMMDevSeamlessChangeRequest*)pRequestHeader;
1210 /* just pass on the information */
1211 Log(("VMMDev: returning seamless change request mode=%d\n", pData->fSeamlessEnabled));
1212 if (pData->fSeamlessEnabled)
1213 seamlessChangeRequest->mode = VMMDev_Seamless_Visible_Region;
1214 else
1215 seamlessChangeRequest->mode = VMMDev_Seamless_Disabled;
1216
1217 if (seamlessChangeRequest->eventAck == VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST)
1218 {
1219 /* Remember which mode the client has queried. */
1220 pData->fLastSeamlessEnabled = pData->fSeamlessEnabled;
1221 }
1222
1223 pRequestHeader->rc = VINF_SUCCESS;
1224 }
1225 break;
1226 }
1227
1228 case VMMDevReq_GetVRDPChangeRequest:
1229 {
1230 if (pRequestHeader->size != sizeof(VMMDevVRDPChangeRequest))
1231 {
1232 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1233 }
1234 else
1235 {
1236 VMMDevVRDPChangeRequest *vrdpChangeRequest = (VMMDevVRDPChangeRequest*)pRequestHeader;
1237 /* just pass on the information */
1238 Log(("VMMDev: returning VRDP status %d level %d\n", pData->fVRDPEnabled, pData->u32VRDPExperienceLevel));
1239
1240 vrdpChangeRequest->u8VRDPActive = pData->fVRDPEnabled;
1241 vrdpChangeRequest->u32VRDPExperienceLevel = pData->u32VRDPExperienceLevel;
1242
1243 pRequestHeader->rc = VINF_SUCCESS;
1244 }
1245 break;
1246 }
1247
1248 case VMMDevReq_GetMemBalloonChangeRequest:
1249 {
1250 Log(("VMMDevReq_GetMemBalloonChangeRequest\n"));
1251 if (pRequestHeader->size != sizeof(VMMDevGetMemBalloonChangeRequest))
1252 {
1253 AssertFailed();
1254 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1255 }
1256 else
1257 {
1258 VMMDevGetMemBalloonChangeRequest *memBalloonChangeRequest = (VMMDevGetMemBalloonChangeRequest*)pRequestHeader;
1259 /* just pass on the information */
1260 Log(("VMMDev: returning memory balloon size =%d\n", pData->u32MemoryBalloonSize));
1261 memBalloonChangeRequest->u32BalloonSize = pData->u32MemoryBalloonSize;
1262 memBalloonChangeRequest->u32PhysMemSize = pData->cbGuestRAM / (uint64_t)_1M;
1263
1264 if (memBalloonChangeRequest->eventAck == VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
1265 {
1266 /* Remember which mode the client has queried. */
1267 pData->u32LastMemoryBalloonSize = pData->u32MemoryBalloonSize;
1268 }
1269
1270 pRequestHeader->rc = VINF_SUCCESS;
1271 }
1272 break;
1273 }
1274
1275 case VMMDevReq_ChangeMemBalloon:
1276 {
1277 VMMDevChangeMemBalloon *memBalloonChange = (VMMDevChangeMemBalloon*)pRequestHeader;
1278
1279 Log(("VMMDevReq_ChangeMemBalloon\n"));
1280 if ( pRequestHeader->size < sizeof(VMMDevChangeMemBalloon)
1281 || memBalloonChange->cPages != VMMDEV_MEMORY_BALLOON_CHUNK_PAGES
1282 || pRequestHeader->size != (uint32_t)RT_OFFSETOF(VMMDevChangeMemBalloon, aPhysPage[memBalloonChange->cPages]))
1283 {
1284 AssertFailed();
1285 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1286 }
1287 else
1288 {
1289 pRequestHeader->rc = pData->pDrv->pfnChangeMemoryBalloon(pData->pDrv, !!memBalloonChange->fInflate, memBalloonChange->cPages, memBalloonChange->aPhysPage);
1290 }
1291 break;
1292 }
1293
1294 case VMMDevReq_GetStatisticsChangeRequest:
1295 {
1296 Log(("VMMDevReq_GetStatisticsChangeRequest\n"));
1297 if (pRequestHeader->size != sizeof(VMMDevGetStatisticsChangeRequest))
1298 {
1299 AssertFailed();
1300 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1301 }
1302 else
1303 {
1304 VMMDevGetStatisticsChangeRequest *statIntervalChangeRequest = (VMMDevGetStatisticsChangeRequest*)pRequestHeader;
1305 /* just pass on the information */
1306 Log(("VMMDev: returning statistics interval %d seconds\n", pData->u32StatIntervalSize));
1307 statIntervalChangeRequest->u32StatInterval = pData->u32StatIntervalSize;
1308
1309 if (statIntervalChangeRequest->eventAck == VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST)
1310 {
1311 /* Remember which mode the client has queried. */
1312 pData->u32LastStatIntervalSize= pData->u32StatIntervalSize;
1313 }
1314
1315 pRequestHeader->rc = VINF_SUCCESS;
1316 }
1317 break;
1318 }
1319
1320 case VMMDevReq_ReportGuestStats:
1321 {
1322 Log(("VMMDevReq_ReportGuestStats\n"));
1323 if (pRequestHeader->size != sizeof(VMMDevReportGuestStats))
1324 {
1325 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1326 }
1327 else
1328 {
1329 VMMDevReportGuestStats *stats = (VMMDevReportGuestStats*)pRequestHeader;
1330
1331#ifdef DEBUG
1332 VBoxGuestStatistics *pGuestStats = &stats->guestStats;
1333
1334 Log(("Current statistics:\n"));
1335 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_IDLE)
1336 Log(("CPU%d: CPU Load Idle %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Idle));
1337
1338 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_KERNEL)
1339 Log(("CPU%d: CPU Load Kernel %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_Kernel));
1340
1341 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_USER)
1342 Log(("CPU%d: CPU Load User %-3d%%\n", pGuestStats->u32CpuId, pGuestStats->u32CpuLoad_User));
1343
1344 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_THREADS)
1345 Log(("CPU%d: Thread %d\n", pGuestStats->u32CpuId, pGuestStats->u32Threads));
1346
1347 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PROCESSES)
1348 Log(("CPU%d: Processes %d\n", pGuestStats->u32CpuId, pGuestStats->u32Processes));
1349
1350 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_HANDLES)
1351 Log(("CPU%d: Handles %d\n", pGuestStats->u32CpuId, pGuestStats->u32Handles));
1352
1353 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEMORY_LOAD)
1354 Log(("CPU%d: Memory Load %d%%\n", pGuestStats->u32CpuId, pGuestStats->u32MemoryLoad));
1355
1356 /* Note that reported values are in pages; upper layers expect them in megabytes */
1357 Assert(pGuestStats->u32PageSize == 4096);
1358 if (pGuestStats->u32PageSize != 4096)
1359 pGuestStats->u32PageSize = 4096;
1360
1361 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_TOTAL)
1362 Log(("CPU%d: Total physical memory %-4d MB\n", pGuestStats->u32CpuId, (pGuestStats->u32PhysMemTotal + (_1M/pGuestStats->u32PageSize)-1)/ (_1M/pGuestStats->u32PageSize)));
1363
1364 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_AVAIL)
1365 Log(("CPU%d: Free physical memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemAvail / (_1M/pGuestStats->u32PageSize)));
1366
1367 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON)
1368 Log(("CPU%d: Memory balloon size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PhysMemBalloon / (_1M/pGuestStats->u32PageSize)));
1369
1370 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_COMMIT_TOTAL)
1371 Log(("CPU%d: Committed memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemCommitTotal / (_1M/pGuestStats->u32PageSize)));
1372
1373 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_TOTAL)
1374 Log(("CPU%d: Total kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelTotal / (_1M/pGuestStats->u32PageSize)));
1375
1376 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_PAGED)
1377 Log(("CPU%d: Paged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelPaged / (_1M/pGuestStats->u32PageSize)));
1378
1379 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED)
1380 Log(("CPU%d: Nonpaged kernel memory %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemKernelNonPaged / (_1M/pGuestStats->u32PageSize)));
1381
1382 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE)
1383 Log(("CPU%d: System cache size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32MemSystemCache / (_1M/pGuestStats->u32PageSize)));
1384
1385 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE)
1386 Log(("CPU%d: Page file size %-4d MB\n", pGuestStats->u32CpuId, pGuestStats->u32PageFileSize / (_1M/pGuestStats->u32PageSize)));
1387 Log(("Statistics end *******************\n"));
1388#endif
1389
1390 /* forward the call */
1391 pRequestHeader->rc = pData->pDrv->pfnReportStatistics(pData->pDrv, &stats->guestStats);
1392 }
1393 break;
1394 }
1395
1396 case VMMDevReq_QueryCredentials:
1397 {
1398 if (pRequestHeader->size != sizeof(VMMDevCredentials))
1399 {
1400 AssertMsgFailed(("VMMDevReq_QueryCredentials request size too small.\n"));
1401 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1402 }
1403 else
1404 {
1405 VMMDevCredentials *credentials = (VMMDevCredentials*)pRequestHeader;
1406
1407 /* let's start by nulling out the data */
1408 memset(credentials->szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1409 memset(credentials->szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1410 memset(credentials->szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1411
1412 /* should we return whether we got credentials for a logon? */
1413 if (credentials->u32Flags & VMMDEV_CREDENTIALS_QUERYPRESENCE)
1414 {
1415 if ( pData->credentialsLogon.szUserName[0]
1416 || pData->credentialsLogon.szPassword[0]
1417 || pData->credentialsLogon.szDomain[0])
1418 {
1419 credentials->u32Flags |= VMMDEV_CREDENTIALS_PRESENT;
1420 }
1421 else
1422 {
1423 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_PRESENT;
1424 }
1425 }
1426
1427 /* does the guest want to read logon credentials? */
1428 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READ)
1429 {
1430 if (pData->credentialsLogon.szUserName[0])
1431 strcpy(credentials->szUserName, pData->credentialsLogon.szUserName);
1432 if (pData->credentialsLogon.szPassword[0])
1433 strcpy(credentials->szPassword, pData->credentialsLogon.szPassword);
1434 if (pData->credentialsLogon.szDomain[0])
1435 strcpy(credentials->szDomain, pData->credentialsLogon.szDomain);
1436 if (!pData->credentialsLogon.fAllowInteractiveLogon)
1437 credentials->u32Flags |= VMMDEV_CREDENTIALS_NOLOCALLOGON;
1438 else
1439 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_NOLOCALLOGON;
1440 }
1441
1442 if (!pData->fKeepCredentials)
1443 {
1444 /* does the caller want us to destroy the logon credentials? */
1445 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEAR)
1446 {
1447 memset(pData->credentialsLogon.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1448 memset(pData->credentialsLogon.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1449 memset(pData->credentialsLogon.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1450 }
1451 }
1452
1453 /* does the guest want to read credentials for verification? */
1454 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READJUDGE)
1455 {
1456 if (pData->credentialsJudge.szUserName[0])
1457 strcpy(credentials->szUserName, pData->credentialsJudge.szUserName);
1458 if (pData->credentialsJudge.szPassword[0])
1459 strcpy(credentials->szPassword, pData->credentialsJudge.szPassword);
1460 if (pData->credentialsJudge.szDomain[0])
1461 strcpy(credentials->szDomain, pData->credentialsJudge.szDomain);
1462 }
1463
1464 /* does the caller want us to destroy the judgement credentials? */
1465 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEARJUDGE)
1466 {
1467 memset(pData->credentialsJudge.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1468 memset(pData->credentialsJudge.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1469 memset(pData->credentialsJudge.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1470 }
1471
1472 pRequestHeader->rc = VINF_SUCCESS;
1473 }
1474 break;
1475 }
1476
1477 case VMMDevReq_ReportCredentialsJudgement:
1478 {
1479 if (pRequestHeader->size != sizeof(VMMDevCredentials))
1480 {
1481 AssertMsgFailed(("VMMDevReq_ReportCredentialsJudgement request size too small.\n"));
1482 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1483 }
1484 else
1485 {
1486 VMMDevCredentials *credentials = (VMMDevCredentials*)pRequestHeader;
1487
1488 /* what does the guest think about the credentials? (note: the order is important here!) */
1489 if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_DENY)
1490 {
1491 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_DENY);
1492 }
1493 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT)
1494 {
1495 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT);
1496 }
1497 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_OK)
1498 {
1499 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_OK);
1500 }
1501 else
1502 Log(("VMMDevReq_ReportCredentialsJudgement: invalid flags: %d!!!\n", credentials->u32Flags));
1503
1504 pRequestHeader->rc = VINF_SUCCESS;
1505 }
1506 break;
1507 }
1508
1509#ifdef DEBUG
1510 case VMMDevReq_LogString:
1511 {
1512 if (pRequestHeader->size < sizeof(VMMDevReqLogString))
1513 {
1514 AssertMsgFailed(("VMMDevReq_LogString request size too small.\n"));
1515 pRequestHeader->rc = VERR_INVALID_PARAMETER;
1516 }
1517 else
1518 {
1519 VMMDevReqLogString *pReqLogString = (VMMDevReqLogString*)pRequestHeader;
1520#undef LOG_GROUP
1521#define LOG_GROUP LOG_GROUP_DEV_VMM_BACKDOOR
1522// Log(("Guest Log: %s", pReqLogString->szString));
1523 Log(("DEBUG LOG: %s", pReqLogString->szString));
1524
1525#undef LOG_GROUP
1526#define LOG_GROUP LOG_GROUP_DEV_VMM
1527 pRequestHeader->rc = VINF_SUCCESS;
1528 }
1529 break;
1530 }
1531#endif
1532 default:
1533 {
1534 pRequestHeader->rc = VERR_NOT_IMPLEMENTED;
1535
1536 Log(("VMMDev unknown request type %d\n", pRequestHeader->requestType));
1537
1538 break;
1539 }
1540 }
1541
1542end:
1543 /* Write the result back to guest memory */
1544 if (pRequestHeader)
1545 {
1546 PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)u32, pRequestHeader, pRequestHeader->size);
1547 RTMemFree(pRequestHeader);
1548 }
1549 else
1550 {
1551 /* early error case; write back header only */
1552 PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)u32, &requestHeader, sizeof(requestHeader));
1553 }
1554 return rcRet;
1555}
1556
1557/**
1558 * Callback function for mapping an PCI I/O region.
1559 *
1560 * @return VBox status code.
1561 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1562 * @param iRegion The region number.
1563 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1564 * I/O port, else it's a physical address.
1565 * This address is *NOT* relative to pci_mem_base like earlier!
1566 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1567 */
1568static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1569{
1570 LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%VGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
1571 VMMDevState *pData = PCIDEV_2_VMMDEVSTATE(pPciDev);
1572 int rc;
1573
1574 AssertReturn(iRegion == 1 && enmType == PCI_ADDRESS_SPACE_MEM, VERR_INTERNAL_ERROR);
1575 Assert(pData->pVMMDevRAMHC != NULL);
1576
1577 if (GCPhysAddress != NIL_RTGCPHYS)
1578 {
1579 /*
1580 * Map the MMIO2 memory.
1581 */
1582 pData->GCPhysVMMDevRAM = GCPhysAddress;
1583 Assert(pData->GCPhysVMMDevRAM == GCPhysAddress);
1584 rc = PDMDevHlpMMIO2Map(pPciDev->pDevIns, iRegion, GCPhysAddress);
1585 }
1586 else
1587 {
1588 /*
1589 * It is about to be unmapped, just clean up.
1590 */
1591 pData->GCPhysVMMDevRAM = NIL_RTGCPHYS32;
1592 rc = VINF_SUCCESS;
1593 }
1594
1595 return rc;
1596}
1597
1598
1599/**
1600 * Callback function for mapping a PCI I/O region.
1601 *
1602 * @return VBox status code.
1603 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1604 * @param iRegion The region number.
1605 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1606 * I/O port, else it's a physical address.
1607 * This address is *NOT* relative to pci_mem_base like earlier!
1608 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1609 */
1610static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1611{
1612 VMMDevState *pData = PCIDEV_2_VMMDEVSTATE(pPciDev);
1613 int rc = VINF_SUCCESS;
1614
1615 Assert(enmType == PCI_ADDRESS_SPACE_IO);
1616 Assert(iRegion == 0);
1617 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
1618
1619 /*
1620 * Save the base port address to simplify Port offset calculations.
1621 */
1622 pData->PortBase = (RTIOPORT)GCPhysAddress;
1623
1624 /*
1625 * Register our port IO handlers.
1626 */
1627 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns,
1628 (RTIOPORT)GCPhysAddress + PORT_VMMDEV_REQUEST_OFFSET, 1,
1629 (void*)pData, vmmdevRequestHandler,
1630 NULL, NULL, NULL, "VMMDev Request Handler");
1631 AssertRC(rc);
1632 return rc;
1633}
1634
1635/**
1636 * Queries an interface to the driver.
1637 *
1638 * @returns Pointer to interface.
1639 * @returns NULL if the interface was not supported by the driver.
1640 * @param pInterface Pointer to this interface structure.
1641 * @param enmInterface The requested interface identification.
1642 * @thread Any thread.
1643 */
1644static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
1645{
1646 VMMDevState *pData = (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, Base));
1647 switch (enmInterface)
1648 {
1649 case PDMINTERFACE_BASE:
1650 return &pData->Base;
1651 case PDMINTERFACE_VMMDEV_PORT:
1652 return &pData->Port;
1653#ifdef VBOX_HGCM
1654 case PDMINTERFACE_HGCM_PORT:
1655 return &pData->HGCMPort;
1656#endif
1657 case PDMINTERFACE_LED_PORTS:
1658 /* Currently only for shared folders */
1659 return &pData->SharedFolders.ILeds;
1660 default:
1661 return NULL;
1662 }
1663}
1664
1665/**
1666 * Gets the pointer to the status LED of a unit.
1667 *
1668 * @returns VBox status code.
1669 * @param pInterface Pointer to the interface structure containing the called function pointer.
1670 * @param iLUN The unit which status LED we desire.
1671 * @param ppLed Where to store the LED pointer.
1672 */
1673static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
1674{
1675 VMMDevState *pData = (VMMDevState *)( (uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, SharedFolders.ILeds) );
1676 if (iLUN == 0) /* LUN 0 is shared folders */
1677 {
1678 *ppLed = &pData->SharedFolders.Led;
1679 return VINF_SUCCESS;
1680 }
1681 return VERR_PDM_LUN_NOT_FOUND;
1682}
1683
1684/* -=-=-=-=-=- IVMMDevPort -=-=-=-=-=- */
1685
1686/** Converts a VMMDev port interface pointer to a VMMDev state pointer. */
1687#define IVMMDEVPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, Port)) )
1688
1689
1690/**
1691 * Return the current absolute mouse position in pixels
1692 *
1693 * @returns VBox status code
1694 * @param pAbsX Pointer of result value, can be NULL
1695 * @param pAbsY Pointer of result value, can be NULL
1696 */
1697static DECLCALLBACK(int) vmmdevQueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t *pAbsX, uint32_t *pAbsY)
1698{
1699 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1700 if (pAbsX)
1701 *pAbsX = pData->mouseXAbs;
1702 if (pAbsY)
1703 *pAbsY = pData->mouseYAbs;
1704 return VINF_SUCCESS;
1705}
1706
1707/**
1708 * Set the new absolute mouse position in pixels
1709 *
1710 * @returns VBox status code
1711 * @param absX New absolute X position
1712 * @param absY New absolute Y position
1713 */
1714static DECLCALLBACK(int) vmmdevSetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t absX, uint32_t absY)
1715{
1716 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1717 Log2(("vmmdevSetAbsoluteMouse: settings absolute position to x = %d, y = %d\n", absX, absY));
1718 pData->mouseXAbs = absX;
1719 pData->mouseYAbs = absY;
1720 return VINF_SUCCESS;
1721}
1722
1723/**
1724 * Return the current mouse capability flags
1725 *
1726 * @returns VBox status code
1727 * @param pCapabilities Pointer of result value
1728 */
1729static DECLCALLBACK(int) vmmdevQueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pCapabilities)
1730{
1731 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1732 if (!pCapabilities)
1733 return VERR_INVALID_PARAMETER;
1734 *pCapabilities = pData->mouseCapabilities;
1735 return VINF_SUCCESS;
1736}
1737
1738/**
1739 * Set the current mouse capability flag (host side)
1740 *
1741 * @returns VBox status code
1742 * @param capabilities Capability mask
1743 */
1744static DECLCALLBACK(int) vmmdevSetMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t capabilities)
1745{
1746 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1747
1748 bool bCapsChanged = ((capabilities & VMMDEV_MOUSEHOSTWANTSABS)
1749 != (pData->mouseCapabilities & VMMDEV_MOUSEHOSTWANTSABS));
1750
1751 Log(("vmmdevSetMouseCapabilities: bCapsChanged %d\n", bCapsChanged));
1752
1753 if (capabilities & VMMDEV_MOUSEHOSTCANNOTHWPOINTER)
1754 pData->mouseCapabilities |= VMMDEV_MOUSEHOSTCANNOTHWPOINTER;
1755 else
1756 pData->mouseCapabilities &= ~VMMDEV_MOUSEHOSTCANNOTHWPOINTER;
1757
1758 if (capabilities & VMMDEV_MOUSEHOSTWANTSABS)
1759 pData->mouseCapabilities |= VMMDEV_MOUSEHOSTWANTSABS;
1760 else
1761 pData->mouseCapabilities &= ~VMMDEV_MOUSEHOSTWANTSABS;
1762
1763 if (bCapsChanged)
1764 VMMDevNotifyGuest (pData, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
1765
1766 return VINF_SUCCESS;
1767}
1768
1769
1770static DECLCALLBACK(int) vmmdevRequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t xres, uint32_t yres, uint32_t bpp, uint32_t display)
1771{
1772 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1773
1774 /* Verify that the new resolution is different and that guest does not yet know about it. */
1775 bool fSameResolution = (!xres || (pData->lastReadDisplayChangeRequest.xres == xres)) &&
1776 (!yres || (pData->lastReadDisplayChangeRequest.yres == yres)) &&
1777 (!bpp || (pData->lastReadDisplayChangeRequest.bpp == bpp)) &&
1778 pData->lastReadDisplayChangeRequest.display == display;
1779
1780 if (!xres && !yres && !bpp)
1781 {
1782 /* Special case of reset video mode. */
1783 fSameResolution = false;
1784 }
1785
1786 Log3(("vmmdevRequestDisplayChange: same=%d. new: xres=%d, yres=%d, bpp=%d, display=%d. old: xres=%d, yres=%d, bpp=%d, display=%d.\n",
1787 fSameResolution, xres, yres, bpp, display, pData->lastReadDisplayChangeRequest.xres, pData->lastReadDisplayChangeRequest.yres, pData->lastReadDisplayChangeRequest.bpp, pData->lastReadDisplayChangeRequest.display));
1788
1789 if (!fSameResolution)
1790 {
1791 LogRel(("VMMDev::SetVideoModeHint: got a video mode hint (%dx%dx%d) at %d\n",
1792 xres, yres, bpp, display));
1793
1794 /* we could validate the information here but hey, the guest can do that as well! */
1795 pData->displayChangeRequest.xres = xres;
1796 pData->displayChangeRequest.yres = yres;
1797 pData->displayChangeRequest.bpp = bpp;
1798 pData->displayChangeRequest.display = display;
1799
1800 /* IRQ so the guest knows what's going on */
1801 VMMDevNotifyGuest (pData, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
1802 }
1803
1804 return VINF_SUCCESS;
1805}
1806
1807static DECLCALLBACK(int) vmmdevRequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
1808{
1809 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1810
1811 /* Verify that the new resolution is different and that guest does not yet know about it. */
1812 bool fSameMode = (pData->fLastSeamlessEnabled == fEnabled);
1813
1814 Log(("vmmdevRequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
1815
1816 if (!fSameMode)
1817 {
1818 /* we could validate the information here but hey, the guest can do that as well! */
1819 pData->fSeamlessEnabled = fEnabled;
1820
1821 /* IRQ so the guest knows what's going on */
1822 VMMDevNotifyGuest (pData, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
1823 }
1824
1825 return VINF_SUCCESS;
1826}
1827
1828static DECLCALLBACK(int) vmmdevSetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t ulBalloonSize)
1829{
1830 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1831
1832 /* Verify that the new resolution is different and that guest does not yet know about it. */
1833 bool fSame = (pData->u32LastMemoryBalloonSize == ulBalloonSize);
1834
1835 Log(("vmmdevSetMemoryBalloon: old=%d. new=%d\n", pData->u32LastMemoryBalloonSize, ulBalloonSize));
1836
1837 if (!fSame)
1838 {
1839 /* we could validate the information here but hey, the guest can do that as well! */
1840 pData->u32MemoryBalloonSize = ulBalloonSize;
1841
1842 /* IRQ so the guest knows what's going on */
1843 VMMDevNotifyGuest (pData, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
1844 }
1845
1846 return VINF_SUCCESS;
1847}
1848
1849static DECLCALLBACK(int) vmmdevVRDPChange(PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t u32VRDPExperienceLevel)
1850{
1851 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1852
1853 bool fSame = (pData->fVRDPEnabled == fVRDPEnabled);
1854
1855 Log(("vmmdevVRDPChange: old=%d. new=%d\n", pData->fVRDPEnabled, fVRDPEnabled));
1856
1857 if (!fSame)
1858 {
1859 pData->fVRDPEnabled = fVRDPEnabled;
1860 pData->u32VRDPExperienceLevel = u32VRDPExperienceLevel;
1861
1862 VMMDevNotifyGuest (pData, VMMDEV_EVENT_VRDP);
1863 }
1864
1865 return VINF_SUCCESS;
1866}
1867
1868static DECLCALLBACK(int) vmmdevSetStatisticsInterval(PPDMIVMMDEVPORT pInterface, uint32_t ulStatInterval)
1869{
1870 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1871
1872 /* Verify that the new resolution is different and that guest does not yet know about it. */
1873 bool fSame = (pData->u32LastStatIntervalSize == ulStatInterval);
1874
1875 Log(("vmmdevSetStatisticsInterval: old=%d. new=%d\n", pData->u32LastStatIntervalSize, ulStatInterval));
1876
1877 if (!fSame)
1878 {
1879 /* we could validate the information here but hey, the guest can do that as well! */
1880 pData->u32StatIntervalSize = ulStatInterval;
1881
1882 /* IRQ so the guest knows what's going on */
1883 VMMDevNotifyGuest (pData, VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST);
1884 }
1885
1886 return VINF_SUCCESS;
1887}
1888
1889
1890static DECLCALLBACK(int) vmmdevSetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
1891 const char *pszPassword, const char *pszDomain,
1892 uint32_t u32Flags)
1893{
1894 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1895
1896 /* logon mode? */
1897 if (u32Flags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
1898 {
1899 /* memorize the data */
1900 strcpy(pData->credentialsLogon.szUserName, pszUsername);
1901 strcpy(pData->credentialsLogon.szPassword, pszPassword);
1902 strcpy(pData->credentialsLogon.szDomain, pszDomain);
1903 pData->credentialsLogon.fAllowInteractiveLogon = !(u32Flags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
1904 }
1905 /* credentials verification mode? */
1906 else if (u32Flags & VMMDEV_SETCREDENTIALS_JUDGE)
1907 {
1908 /* memorize the data */
1909 strcpy(pData->credentialsJudge.szUserName, pszUsername);
1910 strcpy(pData->credentialsJudge.szPassword, pszPassword);
1911 strcpy(pData->credentialsJudge.szDomain, pszDomain);
1912
1913 VMMDevNotifyGuest (pData, VMMDEV_EVENT_JUDGE_CREDENTIALS);
1914 }
1915 else
1916 return VERR_INVALID_PARAMETER;
1917
1918 return VINF_SUCCESS;
1919}
1920
1921/**
1922 * Notification from the Display. Especially useful when
1923 * acceleration is disabled after a video mode change.
1924 *
1925 * @param fEnable Current acceleration status.
1926 */
1927static DECLCALLBACK(void) vmmdevVBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
1928{
1929 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1930
1931 Log(("vmmdevVBVAChange: fEnabled = %d\n", fEnabled));
1932
1933 if (pData)
1934 {
1935 pData->u32VideoAccelEnabled = fEnabled;
1936 }
1937
1938 return;
1939}
1940
1941
1942/* -=-=-=-=-=- IHGCMPort -=-=-=-=-=- */
1943
1944/** Converts a VMMDev port interface pointer to a VMMDev state pointer. */
1945#define IHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, HGCMPort)) )
1946
1947
1948
1949#define VMMDEV_SSM_VERSION 8
1950
1951/**
1952 * Saves a state of the VMM device.
1953 *
1954 * @returns VBox status code.
1955 * @param pDevIns The device instance.
1956 * @param pSSMHandle The handle to save the state to.
1957 */
1958static DECLCALLBACK(int) vmmdevSaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1959{
1960 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
1961 SSMR3PutU32(pSSMHandle, pData->hypervisorSize);
1962 SSMR3PutU32(pSSMHandle, pData->mouseCapabilities);
1963 SSMR3PutU32(pSSMHandle, pData->mouseXAbs);
1964 SSMR3PutU32(pSSMHandle, pData->mouseYAbs);
1965
1966 SSMR3PutBool(pSSMHandle, pData->fNewGuestFilterMask);
1967 SSMR3PutU32(pSSMHandle, pData->u32NewGuestFilterMask);
1968 SSMR3PutU32(pSSMHandle, pData->u32GuestFilterMask);
1969 SSMR3PutU32(pSSMHandle, pData->u32HostEventFlags);
1970 // here be dragons (probably)
1971// SSMR3PutBool(pSSMHandle, pData->pVMMDevRAMHC->V.V1_04.fHaveEvents);
1972 SSMR3PutMem(pSSMHandle, &pData->pVMMDevRAMHC->V, sizeof (pData->pVMMDevRAMHC->V));
1973
1974 SSMR3PutMem(pSSMHandle, &pData->guestInfo, sizeof (pData->guestInfo));
1975 SSMR3PutU32(pSSMHandle, pData->fu32AdditionsOk);
1976 SSMR3PutU32(pSSMHandle, pData->u32VideoAccelEnabled);
1977
1978 SSMR3PutU32(pSSMHandle, pData->guestCaps);
1979
1980#ifdef VBOX_HGCM
1981 vmmdevHGCMSaveState (pData, pSSMHandle);
1982#endif /* VBOX_HGCM */
1983
1984 return VINF_SUCCESS;
1985}
1986
1987/**
1988 * Loads the saved VMM device state.
1989 *
1990 * @returns VBox status code.
1991 * @param pDevIns The device instance.
1992 * @param pSSMHandle The handle to the saved state.
1993 * @param u32Version The data unit version number.
1994 */
1995static DECLCALLBACK(int) vmmdevLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
1996{
1997 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
1998 if ( SSM_VERSION_MAJOR_CHANGED(u32Version, VMMDEV_SSM_VERSION)
1999 || (SSM_VERSION_MINOR(u32Version) < 6))
2000 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2001 SSMR3GetU32(pSSMHandle, &pData->hypervisorSize);
2002 SSMR3GetU32(pSSMHandle, &pData->mouseCapabilities);
2003 SSMR3GetU32(pSSMHandle, &pData->mouseXAbs);
2004 SSMR3GetU32(pSSMHandle, &pData->mouseYAbs);
2005
2006 SSMR3GetBool(pSSMHandle, &pData->fNewGuestFilterMask);
2007 SSMR3GetU32(pSSMHandle, &pData->u32NewGuestFilterMask);
2008 SSMR3GetU32(pSSMHandle, &pData->u32GuestFilterMask);
2009 SSMR3GetU32(pSSMHandle, &pData->u32HostEventFlags);
2010// SSMR3GetBool(pSSMHandle, &pData->pVMMDevRAMHC->fHaveEvents);
2011 // here be dragons (probably)
2012 SSMR3GetMem(pSSMHandle, &pData->pVMMDevRAMHC->V, sizeof (pData->pVMMDevRAMHC->V));
2013
2014 SSMR3GetMem(pSSMHandle, &pData->guestInfo, sizeof (pData->guestInfo));
2015 SSMR3GetU32(pSSMHandle, &pData->fu32AdditionsOk);
2016 SSMR3GetU32(pSSMHandle, &pData->u32VideoAccelEnabled);
2017
2018 SSMR3GetU32(pSSMHandle, &pData->guestCaps);
2019
2020 /* Attributes which were temporarily introduced in r30072 */
2021 if ( SSM_VERSION_MAJOR(u32Version) == 0
2022 && SSM_VERSION_MINOR(u32Version) == 7)
2023 {
2024 uint32_t temp;
2025 SSMR3GetU32(pSSMHandle, &temp);
2026 SSMR3GetU32(pSSMHandle, &temp);
2027 }
2028
2029#ifdef VBOX_HGCM
2030 vmmdevHGCMLoadState (pData, pSSMHandle);
2031#endif /* VBOX_HGCM */
2032
2033 /*
2034 * On a resume, we send the capabilities changed message so
2035 * that listeners can sync their state again
2036 */
2037 Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
2038 if (pData->pDrv)
2039 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
2040
2041 /* Reestablish the acceleration status. */
2042 if ( pData->u32VideoAccelEnabled
2043 && pData->pDrv)
2044 {
2045 pData->pDrv->pfnVideoAccelEnable (pData->pDrv, !!pData->u32VideoAccelEnabled, &pData->pVMMDevRAMHC->vbvaMemory);
2046 }
2047
2048 if (pData->fu32AdditionsOk)
2049 {
2050 LogRel(("Guest Additions information report: additionsVersion = 0x%08X, osType = 0x%08X\n",
2051 pData->guestInfo.additionsVersion,
2052 pData->guestInfo.osType));
2053 if (pData->pDrv)
2054 pData->pDrv->pfnUpdateGuestVersion(pData->pDrv, &pData->guestInfo);
2055 }
2056 if (pData->pDrv)
2057 pData->pDrv->pfnUpdateGuestCapabilities(pData->pDrv, pData->guestCaps);
2058
2059 return VINF_SUCCESS;
2060}
2061
2062/**
2063 * Load state done callback. Notify guest of restore event.
2064 *
2065 * @returns VBox status code.
2066 * @param pDevIns The device instance.
2067 * @param pSSMHandle The handle to the saved state.
2068 */
2069static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
2070{
2071 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
2072
2073#ifdef VBOX_HGCM
2074 vmmdevHGCMLoadStateDone (pData, pSSMHandle);
2075#endif /* VBOX_HGCM */
2076
2077 VMMDevNotifyGuest (pData, VMMDEV_EVENT_RESTORED);
2078
2079 return VINF_SUCCESS;
2080}
2081
2082/**
2083 * (Re-)initializes the MMIO2 data.
2084 *
2085 * @param pData Pointer to the VMMDev instance data.
2086 */
2087static void vmmdevInitRam(VMMDevState *pData)
2088{
2089 memset(pData->pVMMDevRAMHC, 0, sizeof(VMMDevMemory));
2090 pData->pVMMDevRAMHC->u32Size = sizeof(VMMDevMemory);
2091 pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
2092}
2093
2094/**
2095 * Construct a device instance for a VM.
2096 *
2097 * @returns VBox status.
2098 * @param pDevIns The device instance data.
2099 * If the registration structure is needed, pDevIns->pDevReg points to it.
2100 * @param iInstance Instance number. Use this to figure out which registers and such to use.
2101 * The device number is also found in pDevIns->iInstance, but since it's
2102 * likely to be freqently used PDM passes it as parameter.
2103 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
2104 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
2105 * iInstance it's expected to be used a bit in this function.
2106 */
2107static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
2108{
2109 int rc;
2110 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
2111
2112 Assert(iInstance == 0);
2113
2114 /*
2115 * Validate and read the configuration.
2116 */
2117 if (!CFGMR3AreValuesValid(pCfgHandle, "GetHostTimeDisabled\0BackdoorLogDisabled\0KeepCredentials\0"))
2118 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2119
2120 rc = CFGMR3QueryBool(pCfgHandle, "GetHostTimeDisabled", &pData->fGetHostTimeDisabled);
2121 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2122 pData->fGetHostTimeDisabled = false;
2123 else if (VBOX_FAILURE(rc))
2124 return PDMDEV_SET_ERROR(pDevIns, rc,
2125 N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
2126
2127 rc = CFGMR3QueryBool(pCfgHandle, "BackdoorLogDisabled", &pData->fBackdoorLogDisabled);
2128 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2129 pData->fBackdoorLogDisabled = false;
2130 else if (VBOX_FAILURE(rc))
2131 return PDMDEV_SET_ERROR(pDevIns, rc,
2132 N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
2133
2134 rc = CFGMR3QueryBool(pCfgHandle, "KeepCredentials", &pData->fKeepCredentials);
2135 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2136 pData->fKeepCredentials = false;
2137 else if (VBOX_FAILURE(rc))
2138 return PDMDEV_SET_ERROR(pDevIns, rc,
2139 N_("Configuration error: Failed querying \"KeepCredentials\" as a boolean"));
2140
2141 /*
2142 * Initialize data (most of it anyway).
2143 */
2144 /* Save PDM device instance data for future reference. */
2145 pData->pDevIns = pDevIns;
2146
2147 /* PCI vendor, just a free bogus value */
2148 pData->dev.config[0x00] = 0xee;
2149 pData->dev.config[0x01] = 0x80;
2150 /* device ID */
2151 pData->dev.config[0x02] = 0xfe;
2152 pData->dev.config[0x03] = 0xca;
2153 /* class sub code (other type of system peripheral) */
2154 pData->dev.config[0x0a] = 0x80;
2155 /* class base code (base system peripheral) */
2156 pData->dev.config[0x0b] = 0x08;
2157 /* header type */
2158 pData->dev.config[0x0e] = 0x00;
2159 /* interrupt on pin 0 */
2160 pData->dev.config[0x3d] = 0x01;
2161
2162 /*
2163 * Interfaces
2164 */
2165 /* Base */
2166 pData->Base.pfnQueryInterface = vmmdevPortQueryInterface;
2167
2168 /* VMMDev port */
2169 pData->Port.pfnQueryAbsoluteMouse = vmmdevQueryAbsoluteMouse;
2170 pData->Port.pfnSetAbsoluteMouse = vmmdevSetAbsoluteMouse;
2171 pData->Port.pfnQueryMouseCapabilities = vmmdevQueryMouseCapabilities;
2172 pData->Port.pfnSetMouseCapabilities = vmmdevSetMouseCapabilities;
2173 pData->Port.pfnRequestDisplayChange = vmmdevRequestDisplayChange;
2174 pData->Port.pfnSetCredentials = vmmdevSetCredentials;
2175 pData->Port.pfnVBVAChange = vmmdevVBVAChange;
2176 pData->Port.pfnRequestSeamlessChange = vmmdevRequestSeamlessChange;
2177 pData->Port.pfnSetMemoryBalloon = vmmdevSetMemoryBalloon;
2178 pData->Port.pfnSetStatisticsInterval = vmmdevSetStatisticsInterval;
2179 pData->Port.pfnVRDPChange = vmmdevVRDPChange;
2180
2181 /* Shared folder LED */
2182 pData->SharedFolders.Led.u32Magic = PDMLED_MAGIC;
2183 pData->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
2184
2185#ifdef VBOX_HGCM
2186 /* HGCM port */
2187 pData->HGCMPort.pfnCompleted = hgcmCompleted;
2188#endif
2189
2190 /** @todo convert this into a config parameter like we do everywhere else.*/
2191 pData->cbGuestRAM = MMR3PhysGetRamSize(PDMDevHlpGetVM(pDevIns));
2192
2193 /*
2194 * Register the backdoor logging port
2195 */
2196 rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog, NULL, NULL, NULL, "VMMDev backdoor logging");
2197 AssertRCReturn(rc, rc);
2198
2199#ifdef TIMESYNC_BACKDOOR
2200 /*
2201 * Alternative timesync source (temporary!)
2202 */
2203 rc = PDMDevHlpIOPortRegister(pDevIns, 0x505, 1, NULL, vmmdevTimesyncBackdoorWrite, vmmdevTimesyncBackdoorRead, NULL, NULL, "VMMDev timesync backdoor");
2204 AssertRCReturn(rc, rc);
2205#endif
2206
2207 /*
2208 * Allocate and initialize the MMIO2 memory.
2209 */
2210 rc = PDMDevHlpMMIO2Register(pDevIns, 1 /*iRegion*/, VMMDEV_RAM_SIZE, 0, (void **)&pData->pVMMDevRAMHC, "VMMDev");
2211 if (RT_FAILURE(rc))
2212 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2213 N_("Failed to allocate %u bytes of memory for the VMM device"), VMMDEV_RAM_SIZE);
2214 vmmdevInitRam(pData);
2215
2216 /*
2217 * Register the PCI device.
2218 */
2219 rc = PDMDevHlpPCIRegister(pDevIns, &pData->dev);
2220 if (VBOX_FAILURE(rc))
2221 return rc;
2222 if (pData->dev.devfn == 32 || iInstance != 0)
2223 Log(("!!WARNING!!: pData->dev.devfn=%d (ignore if testcase or no started by Main)\n", pData->dev.devfn));
2224 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
2225 if (VBOX_FAILURE(rc))
2226 return rc;
2227 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, vmmdevIORAMRegionMap);
2228 if (VBOX_FAILURE(rc))
2229 return rc;
2230
2231 /*
2232 * Get the corresponding connector interface
2233 */
2234 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->Base, &pData->pDrvBase, "VMM Driver Port");
2235 if (VBOX_SUCCESS(rc))
2236 {
2237 pData->pDrv = (PPDMIVMMDEVCONNECTOR)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_VMMDEV_CONNECTOR);
2238 if (!pData->pDrv)
2239 AssertMsgFailedReturn(("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
2240#ifdef VBOX_HGCM
2241 pData->pHGCMDrv = (PPDMIHGCMCONNECTOR)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_HGCM_CONNECTOR);
2242 if (!pData->pHGCMDrv)
2243 {
2244 Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Vrc\n", rc));
2245 /* this is not actually an error, just means that there is no support for HGCM */
2246 }
2247#endif
2248 }
2249 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2250 {
2251 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
2252 rc = VINF_SUCCESS;
2253 }
2254 else
2255 AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Vrc\n", rc), rc);
2256
2257 /*
2258 * Attach status driver for shared folders (optional).
2259 */
2260 PPDMIBASE pBase;
2261 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pData->Base, &pBase, "Status Port");
2262 if (VBOX_SUCCESS(rc))
2263 pData->SharedFolders.pLedsConnector = (PPDMILEDCONNECTORS)
2264 pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
2265 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
2266 {
2267 AssertMsgFailed(("Failed to attach to status driver. rc=%Vrc\n", rc));
2268 return rc;
2269 }
2270
2271 /*
2272 * Register saved state and init the HGCM CmdList critsect.
2273 */
2274 rc = PDMDevHlpSSMRegister(pDevIns, "VMMDev", iInstance, VMMDEV_SSM_VERSION, sizeof(*pData),
2275 NULL, vmmdevSaveState, NULL,
2276 NULL, vmmdevLoadState, vmmdevLoadStateDone);
2277 AssertRCReturn(rc, rc);
2278
2279#ifdef VBOX_HGCM
2280 pData->pHGCMCmdList = NULL;
2281 rc = RTCritSectInit(&pData->critsectHGCMCmdList);
2282 AssertRCReturn(rc, rc);
2283 pData->u32HGCMEnabled = 0;
2284#endif /* VBOX_HGCM */
2285
2286 return rc;
2287}
2288
2289/**
2290 * Reset notification.
2291 *
2292 * @returns VBox status.
2293 * @param pDrvIns The driver instance data.
2294 */
2295static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
2296{
2297 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
2298 /*
2299 * Reset the mouse integration feature bit
2300 */
2301 if (pData->mouseCapabilities & (VMMDEV_MOUSEGUESTWANTSABS|VMMDEV_MOUSEGUESTNEEDSHOSTCUR))
2302 {
2303 pData->mouseCapabilities &= ~VMMDEV_MOUSEGUESTWANTSABS;
2304 /* notify the connector */
2305 Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
2306 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
2307 }
2308
2309 pData->hypervisorSize = 0;
2310
2311 pData->u32HostEventFlags = 0;
2312
2313 /* re-initialize the VMMDev memory */
2314 if (pData->pVMMDevRAMHC)
2315 vmmdevInitRam(pData);
2316
2317 /* credentials have to go away (by default) */
2318 if (!pData->fKeepCredentials)
2319 {
2320 memset(pData->credentialsLogon.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
2321 memset(pData->credentialsLogon.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
2322 memset(pData->credentialsLogon.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
2323 }
2324 memset(pData->credentialsJudge.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
2325 memset(pData->credentialsJudge.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
2326 memset(pData->credentialsJudge.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
2327
2328 /* Reset means that additions will report again. */
2329 pData->fu32AdditionsOk = false;
2330 memset (&pData->guestInfo, 0, sizeof (pData->guestInfo));
2331 pData->pDrv->pfnUpdateGuestVersion(pData->pDrv, &pData->guestInfo);
2332
2333 memset (&pData->lastReadDisplayChangeRequest, 0, sizeof (pData->lastReadDisplayChangeRequest));
2334
2335 /* disable seamless mode */
2336 pData->fLastSeamlessEnabled = false;
2337
2338 /* disabled memory ballooning */
2339 pData->u32LastMemoryBalloonSize = 0;
2340
2341 /* disabled statistics updating */
2342 pData->u32LastStatIntervalSize = 0;
2343
2344 /* Clear the event variables.
2345 *
2346 * Note: The pData->u32HostEventFlags is not cleared.
2347 * It is designed that way so host events do not
2348 * depend on guest resets.
2349 */
2350 pData->u32GuestFilterMask = 0;
2351 pData->u32NewGuestFilterMask = 0;
2352 pData->fNewGuestFilterMask = 0;
2353
2354 /* This is the default, as Windows and OS/2 guests take this for granted. */
2355 /** @todo change this when we next bump the interface version */
2356 pData->guestCaps = VMMDEV_GUEST_SUPPORTS_GRAPHICS;
2357 pData->pDrv->pfnUpdateGuestCapabilities(pData->pDrv, pData->guestCaps);
2358}
2359
2360
2361/**
2362 * The device registration structure.
2363 */
2364extern "C" const PDMDEVREG g_DeviceVMMDev =
2365{
2366 /* u32Version */
2367 PDM_DEVREG_VERSION,
2368 /* szDeviceName */
2369 "VMMDev",
2370 /* szGCMod */
2371 "",
2372 /* szR0Mod */
2373 "",
2374 /* pszDescription */
2375 "VirtualBox VMM Device\n",
2376 /* fFlags */
2377 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32,
2378 /* fClass */
2379 PDM_DEVREG_CLASS_VMM_DEV,
2380 /* cMaxInstances */
2381 1,
2382 /* cbInstance */
2383 sizeof(VMMDevState),
2384 /* pfnConstruct */
2385 vmmdevConstruct,
2386 /* pfnDestruct */
2387 NULL,
2388 /* pfnRelocate */
2389 NULL,
2390 /* pfnIOCtl */
2391 NULL,
2392 /* pfnPowerOn */
2393 NULL,
2394 /* pfnReset */
2395 vmmdevReset,
2396 /* pfnSuspend */
2397 NULL,
2398 /* pfnResume */
2399 NULL,
2400 /* pfnAttach */
2401 NULL,
2402 /* pfnDetach */
2403 NULL,
2404 /* pfnQueryInterface. */
2405 NULL
2406};
2407#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2408
Note: See TracBrowser for help on using the repository browser.

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