VirtualBox

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

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

The Big Sun Rebranding Header Change

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 90.9 KB
Line 
1/* $Id: VBoxDev.cpp 8155 2008-04-18 15:16:47Z 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 "VMMDEV_GUEST_SUPPORTS_SEAMLESS: %s "
535 "VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING: %s "
536 "VMMDEV_GUEST_SUPPORTS_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 "VMMDEV_GUEST_SUPPORTS_SEAMLESS: %s "
566 "VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING: %s "
567 "VMMDEV_GUEST_SUPPORTS_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 6
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 (u32Version != VMMDEV_SSM_VERSION)
1999 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2000 SSMR3GetU32(pSSMHandle, &pData->hypervisorSize);
2001 SSMR3GetU32(pSSMHandle, &pData->mouseCapabilities);
2002 SSMR3GetU32(pSSMHandle, &pData->mouseXAbs);
2003 SSMR3GetU32(pSSMHandle, &pData->mouseYAbs);
2004
2005 SSMR3GetBool(pSSMHandle, &pData->fNewGuestFilterMask);
2006 SSMR3GetU32(pSSMHandle, &pData->u32NewGuestFilterMask);
2007 SSMR3GetU32(pSSMHandle, &pData->u32GuestFilterMask);
2008 SSMR3GetU32(pSSMHandle, &pData->u32HostEventFlags);
2009// SSMR3GetBool(pSSMHandle, &pData->pVMMDevRAMHC->fHaveEvents);
2010 // here be dragons (probably)
2011 SSMR3GetMem(pSSMHandle, &pData->pVMMDevRAMHC->V, sizeof (pData->pVMMDevRAMHC->V));
2012
2013 SSMR3GetMem(pSSMHandle, &pData->guestInfo, sizeof (pData->guestInfo));
2014 SSMR3GetU32(pSSMHandle, &pData->fu32AdditionsOk);
2015 SSMR3GetU32(pSSMHandle, &pData->u32VideoAccelEnabled);
2016
2017 SSMR3GetU32(pSSMHandle, &pData->guestCaps);
2018
2019#ifdef VBOX_HGCM
2020 vmmdevHGCMLoadState (pData, pSSMHandle);
2021#endif /* VBOX_HGCM */
2022
2023 /*
2024 * On a resume, we send the capabilities changed message so
2025 * that listeners can sync their state again
2026 */
2027 Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
2028 if (pData->pDrv)
2029 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
2030
2031 /* Reestablish the acceleration status. */
2032 if ( pData->u32VideoAccelEnabled
2033 && pData->pDrv)
2034 {
2035 pData->pDrv->pfnVideoAccelEnable (pData->pDrv, !!pData->u32VideoAccelEnabled, &pData->pVMMDevRAMHC->vbvaMemory);
2036 }
2037
2038 if (pData->fu32AdditionsOk)
2039 {
2040 LogRel(("Guest Additions information report: additionsVersion = 0x%08X osType = 0x%08X\n",
2041 pData->guestInfo.additionsVersion,
2042 pData->guestInfo.osType));
2043 if (pData->pDrv)
2044 pData->pDrv->pfnUpdateGuestVersion(pData->pDrv, &pData->guestInfo);
2045 }
2046 if (pData->pDrv)
2047 pData->pDrv->pfnUpdateGuestCapabilities(pData->pDrv, pData->guestCaps);
2048
2049 return VINF_SUCCESS;
2050}
2051
2052/**
2053 * Load state done callback. Notify guest of restore event.
2054 *
2055 * @returns VBox status code.
2056 * @param pDevIns The device instance.
2057 * @param pSSMHandle The handle to the saved state.
2058 */
2059static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
2060{
2061 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
2062
2063#ifdef VBOX_HGCM
2064 vmmdevHGCMLoadStateDone (pData, pSSMHandle);
2065#endif /* VBOX_HGCM */
2066
2067 VMMDevNotifyGuest (pData, VMMDEV_EVENT_RESTORED);
2068
2069 return VINF_SUCCESS;
2070}
2071
2072/**
2073 * (Re-)initializes the MMIO2 data.
2074 *
2075 * @param pData Pointer to the VMMDev instance data.
2076 */
2077static void vmmdevInitRam(VMMDevState *pData)
2078{
2079 memset(pData->pVMMDevRAMHC, 0, sizeof(VMMDevMemory));
2080 pData->pVMMDevRAMHC->u32Size = sizeof(VMMDevMemory);
2081 pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
2082}
2083
2084/**
2085 * Construct a device instance for a VM.
2086 *
2087 * @returns VBox status.
2088 * @param pDevIns The device instance data.
2089 * If the registration structure is needed, pDevIns->pDevReg points to it.
2090 * @param iInstance Instance number. Use this to figure out which registers and such to use.
2091 * The device number is also found in pDevIns->iInstance, but since it's
2092 * likely to be freqently used PDM passes it as parameter.
2093 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
2094 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
2095 * iInstance it's expected to be used a bit in this function.
2096 */
2097static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
2098{
2099 int rc;
2100 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
2101
2102 Assert(iInstance == 0);
2103
2104 /*
2105 * Validate and read the configuration.
2106 */
2107 if (!CFGMR3AreValuesValid(pCfgHandle, "GetHostTimeDisabled\0BackdoorLogDisabled\0KeepCredentials\0"))
2108 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2109
2110 rc = CFGMR3QueryBool(pCfgHandle, "GetHostTimeDisabled", &pData->fGetHostTimeDisabled);
2111 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2112 pData->fGetHostTimeDisabled = false;
2113 else if (VBOX_FAILURE(rc))
2114 return PDMDEV_SET_ERROR(pDevIns, rc,
2115 N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
2116
2117 rc = CFGMR3QueryBool(pCfgHandle, "BackdoorLogDisabled", &pData->fBackdoorLogDisabled);
2118 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2119 pData->fBackdoorLogDisabled = false;
2120 else if (VBOX_FAILURE(rc))
2121 return PDMDEV_SET_ERROR(pDevIns, rc,
2122 N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
2123
2124 rc = CFGMR3QueryBool(pCfgHandle, "KeepCredentials", &pData->fKeepCredentials);
2125 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
2126 pData->fKeepCredentials = false;
2127 else if (VBOX_FAILURE(rc))
2128 return PDMDEV_SET_ERROR(pDevIns, rc,
2129 N_("Configuration error: Failed querying \"KeepCredentials\" as a boolean"));
2130
2131 /*
2132 * Initialize data (most of it anyway).
2133 */
2134 /* Save PDM device instance data for future reference. */
2135 pData->pDevIns = pDevIns;
2136
2137 /* PCI vendor, just a free bogus value */
2138 pData->dev.config[0x00] = 0xee;
2139 pData->dev.config[0x01] = 0x80;
2140 /* device ID */
2141 pData->dev.config[0x02] = 0xfe;
2142 pData->dev.config[0x03] = 0xca;
2143 /* class sub code (other type of system peripheral) */
2144 pData->dev.config[0x0a] = 0x80;
2145 /* class base code (base system peripheral) */
2146 pData->dev.config[0x0b] = 0x08;
2147 /* header type */
2148 pData->dev.config[0x0e] = 0x00;
2149 /* interrupt on pin 0 */
2150 pData->dev.config[0x3d] = 0x01;
2151
2152 /*
2153 * Interfaces
2154 */
2155 /* Base */
2156 pData->Base.pfnQueryInterface = vmmdevPortQueryInterface;
2157
2158 /* VMMDev port */
2159 pData->Port.pfnQueryAbsoluteMouse = vmmdevQueryAbsoluteMouse;
2160 pData->Port.pfnSetAbsoluteMouse = vmmdevSetAbsoluteMouse;
2161 pData->Port.pfnQueryMouseCapabilities = vmmdevQueryMouseCapabilities;
2162 pData->Port.pfnSetMouseCapabilities = vmmdevSetMouseCapabilities;
2163 pData->Port.pfnRequestDisplayChange = vmmdevRequestDisplayChange;
2164 pData->Port.pfnSetCredentials = vmmdevSetCredentials;
2165 pData->Port.pfnVBVAChange = vmmdevVBVAChange;
2166 pData->Port.pfnRequestSeamlessChange = vmmdevRequestSeamlessChange;
2167 pData->Port.pfnSetMemoryBalloon = vmmdevSetMemoryBalloon;
2168 pData->Port.pfnSetStatisticsInterval = vmmdevSetStatisticsInterval;
2169 pData->Port.pfnVRDPChange = vmmdevVRDPChange;
2170
2171 /* Shared folder LED */
2172 pData->SharedFolders.Led.u32Magic = PDMLED_MAGIC;
2173 pData->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
2174
2175#ifdef VBOX_HGCM
2176 /* HGCM port */
2177 pData->HGCMPort.pfnCompleted = hgcmCompleted;
2178#endif
2179
2180 /** @todo convert this into a config parameter like we do everywhere else.*/
2181 pData->cbGuestRAM = MMR3PhysGetRamSize(PDMDevHlpGetVM(pDevIns));
2182
2183 /*
2184 * Register the backdoor logging port
2185 */
2186 rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog, NULL, NULL, NULL, "VMMDev backdoor logging");
2187 AssertRCReturn(rc, rc);
2188
2189#ifdef TIMESYNC_BACKDOOR
2190 /*
2191 * Alternative timesync source (temporary!)
2192 */
2193 rc = PDMDevHlpIOPortRegister(pDevIns, 0x505, 1, NULL, vmmdevTimesyncBackdoorWrite, vmmdevTimesyncBackdoorRead, NULL, NULL, "VMMDev timesync backdoor");
2194 AssertRCReturn(rc, rc);
2195#endif
2196
2197 /*
2198 * Allocate and initialize the MMIO2 memory.
2199 */
2200 rc = PDMDevHlpMMIO2Register(pDevIns, 1 /*iRegion*/, VMMDEV_RAM_SIZE, 0, (void **)&pData->pVMMDevRAMHC, "VMMDev");
2201 if (RT_FAILURE(rc))
2202 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
2203 N_("Failed to allocate %u bytes of memory for the VMM device"), VMMDEV_RAM_SIZE);
2204 vmmdevInitRam(pData);
2205
2206 /*
2207 * Register the PCI device.
2208 */
2209 rc = PDMDevHlpPCIRegister(pDevIns, &pData->dev);
2210 if (VBOX_FAILURE(rc))
2211 return rc;
2212 if (pData->dev.devfn == 32 || iInstance != 0)
2213 Log(("!!WARNING!!: pData->dev.devfn=%d (ignore if testcase or no started by Main)\n", pData->dev.devfn));
2214 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
2215 if (VBOX_FAILURE(rc))
2216 return rc;
2217 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, vmmdevIORAMRegionMap);
2218 if (VBOX_FAILURE(rc))
2219 return rc;
2220
2221 /*
2222 * Get the corresponding connector interface
2223 */
2224 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->Base, &pData->pDrvBase, "VMM Driver Port");
2225 if (VBOX_SUCCESS(rc))
2226 {
2227 pData->pDrv = (PPDMIVMMDEVCONNECTOR)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_VMMDEV_CONNECTOR);
2228 if (!pData->pDrv)
2229 AssertMsgFailedReturn(("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
2230#ifdef VBOX_HGCM
2231 pData->pHGCMDrv = (PPDMIHGCMCONNECTOR)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_HGCM_CONNECTOR);
2232 if (!pData->pHGCMDrv)
2233 {
2234 Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Vrc\n", rc));
2235 /* this is not actually an error, just means that there is no support for HGCM */
2236 }
2237#endif
2238 }
2239 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2240 {
2241 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
2242 rc = VINF_SUCCESS;
2243 }
2244 else
2245 AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Vrc\n", rc), rc);
2246
2247 /*
2248 * Attach status driver for shared folders (optional).
2249 */
2250 PPDMIBASE pBase;
2251 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pData->Base, &pBase, "Status Port");
2252 if (VBOX_SUCCESS(rc))
2253 pData->SharedFolders.pLedsConnector = (PPDMILEDCONNECTORS)
2254 pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
2255 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
2256 {
2257 AssertMsgFailed(("Failed to attach to status driver. rc=%Vrc\n", rc));
2258 return rc;
2259 }
2260
2261 /*
2262 * Register saved state and init the HGCM CmdList critsect.
2263 */
2264 rc = PDMDevHlpSSMRegister(pDevIns, "VMMDev", iInstance, VMMDEV_SSM_VERSION, sizeof(*pData),
2265 NULL, vmmdevSaveState, NULL,
2266 NULL, vmmdevLoadState, vmmdevLoadStateDone);
2267 AssertRCReturn(rc, rc);
2268
2269#ifdef VBOX_HGCM
2270 pData->pHGCMCmdList = NULL;
2271 rc = RTCritSectInit(&pData->critsectHGCMCmdList);
2272 AssertRCReturn(rc, rc);
2273 pData->u32HGCMEnabled = 0;
2274#endif /* VBOX_HGCM */
2275
2276 return rc;
2277}
2278
2279/**
2280 * Reset notification.
2281 *
2282 * @returns VBox status.
2283 * @param pDrvIns The driver instance data.
2284 */
2285static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
2286{
2287 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
2288 /*
2289 * Reset the mouse integration feature bit
2290 */
2291 if (pData->mouseCapabilities & (VMMDEV_MOUSEGUESTWANTSABS|VMMDEV_MOUSEGUESTNEEDSHOSTCUR))
2292 {
2293 pData->mouseCapabilities &= ~VMMDEV_MOUSEGUESTWANTSABS;
2294 /* notify the connector */
2295 Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
2296 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
2297 }
2298
2299 pData->hypervisorSize = 0;
2300
2301 pData->u32HostEventFlags = 0;
2302
2303 /* re-initialize the VMMDev memory */
2304 if (pData->pVMMDevRAMHC)
2305 vmmdevInitRam(pData);
2306
2307 /* credentials have to go away (by default) */
2308 if (!pData->fKeepCredentials)
2309 {
2310 memset(pData->credentialsLogon.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
2311 memset(pData->credentialsLogon.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
2312 memset(pData->credentialsLogon.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
2313 }
2314 memset(pData->credentialsJudge.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
2315 memset(pData->credentialsJudge.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
2316 memset(pData->credentialsJudge.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
2317
2318 /* Reset means that additions will report again. */
2319 pData->fu32AdditionsOk = false;
2320 memset (&pData->guestInfo, 0, sizeof (pData->guestInfo));
2321
2322 memset (&pData->lastReadDisplayChangeRequest, 0, sizeof (pData->lastReadDisplayChangeRequest));
2323
2324 /* disable seamless mode */
2325 pData->fLastSeamlessEnabled = false;
2326
2327 /* disabled memory ballooning */
2328 pData->u32LastMemoryBalloonSize = 0;
2329
2330 /* disabled statistics updating */
2331 pData->u32LastStatIntervalSize = 0;
2332
2333 /* Clear the event variables.
2334 *
2335 * Note: The pData->u32HostEventFlags is not cleared.
2336 * It is designed that way so host events do not
2337 * depend on guest resets.
2338 */
2339 pData->u32GuestFilterMask = 0;
2340 pData->u32NewGuestFilterMask = 0;
2341 pData->fNewGuestFilterMask = 0;
2342
2343 /* This is the default, as Windows and OS/2 guests take this for granted. */
2344 /** @todo change this when we next bump the interface version */
2345 pData->guestCaps = VMMDEV_GUEST_SUPPORTS_GRAPHICS;
2346 pData->pDrv->pfnUpdateGuestCapabilities(pData->pDrv, pData->guestCaps);
2347}
2348
2349
2350/**
2351 * The device registration structure.
2352 */
2353extern "C" const PDMDEVREG g_DeviceVMMDev =
2354{
2355 /* u32Version */
2356 PDM_DEVREG_VERSION,
2357 /* szDeviceName */
2358 "VMMDev",
2359 /* szGCMod */
2360 "",
2361 /* szR0Mod */
2362 "",
2363 /* pszDescription */
2364 "VirtualBox VMM Device\n",
2365 /* fFlags */
2366 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32,
2367 /* fClass */
2368 PDM_DEVREG_CLASS_VMM_DEV,
2369 /* cMaxInstances */
2370 1,
2371 /* cbInstance */
2372 sizeof(VMMDevState),
2373 /* pfnConstruct */
2374 vmmdevConstruct,
2375 /* pfnDestruct */
2376 NULL,
2377 /* pfnRelocate */
2378 NULL,
2379 /* pfnIOCtl */
2380 NULL,
2381 /* pfnPowerOn */
2382 NULL,
2383 /* pfnReset */
2384 vmmdevReset,
2385 /* pfnSuspend */
2386 NULL,
2387 /* pfnResume */
2388 NULL,
2389 /* pfnAttach */
2390 NULL,
2391 /* pfnDetach */
2392 NULL,
2393 /* pfnQueryInterface. */
2394 NULL
2395};
2396#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2397
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