VirtualBox

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

Last change on this file since 11347 was 11285, checked in by vboxsync, 16 years ago

Devices: %VGp -> %RGp (just preferred, not mandatory (yet))

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