VirtualBox

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

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

More logging

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