VirtualBox

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

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

Change the 2nd pci range of the vmm device to prefetchable. That should make the broken windows additions skip the region.

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