VirtualBox

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

Last change on this file since 13510 was 13270, checked in by vboxsync, 16 years ago

Deliver event notifications to the guest only when the VM is running (xtracker 3236).

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