VirtualBox

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

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

Continued Main-VMMDev work on memory ballooning.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 80.4 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
1181 case VMMDevReq_GetMemBalloonChangeRequest:
1182 {
1183 Log(("VMMDevReq_GetMemBalloonChangeRequest\n"));
1184 if (requestHeader->size != sizeof(VMMDevGetMemBalloonChangeRequest))
1185 {
1186 requestHeader->rc = VERR_INVALID_PARAMETER;
1187 }
1188 else
1189 {
1190 VMMDevGetMemBalloonChangeRequest *memBalloonChangeRequest = (VMMDevGetMemBalloonChangeRequest*)requestHeader;
1191 /* just pass on the information */
1192 Log(("VMMDev: returning memory balloon size =%d\n", pData->u32MemoryBalloonSize));
1193 memBalloonChangeRequest->u32BalloonSize = pData->u32MemoryBalloonSize;
1194
1195 if (memBalloonChangeRequest->eventAck == VMMDEV_EVENT_BALLOON_CHANGE_REQUEST)
1196 {
1197 /* Remember which mode the client has queried. */
1198 pData->u32LastMemoryBalloonSize = pData->u32MemoryBalloonSize;
1199 }
1200
1201 requestHeader->rc = VINF_SUCCESS;
1202 }
1203 break;
1204 }
1205
1206 case VMMDevReq_ReportGuestStats:
1207 {
1208 Log(("VMMDevReq_ReportGuestStats\n"));
1209 if (requestHeader->size != sizeof(VMMDevReportGuestStats))
1210 {
1211 requestHeader->rc = VERR_INVALID_PARAMETER;
1212 }
1213 else
1214 {
1215 VMMDevReportGuestStats *stats = (VMMDevReportGuestStats*)requestHeader;
1216
1217 /* Update the last known memory balloon size */
1218 if (stats->guestStats.u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON)
1219 pData->u32LastMemoryBalloonSize = stats->guestStats.u32PhysMemBalloon;
1220
1221 /* forward the call */
1222 requestHeader->rc = pData->pDrv->pfnReportStatistics(pData->pDrv, &stats->guestStats);
1223 }
1224 break;
1225 }
1226
1227 case VMMDevReq_QueryCredentials:
1228 {
1229 if (requestHeader->size != sizeof(VMMDevCredentials))
1230 {
1231 AssertMsgFailed(("VMMDevReq_QueryCredentials request size too small.\n"));
1232 requestHeader->rc = VERR_INVALID_PARAMETER;
1233 }
1234 else
1235 {
1236 VMMDevCredentials *credentials = (VMMDevCredentials*)requestHeader;
1237
1238 /* let's start by nulling out the data */
1239 memset(credentials->szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1240 memset(credentials->szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1241 memset(credentials->szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1242
1243 /* should we return whether we got credentials for a logon? */
1244 if (credentials->u32Flags & VMMDEV_CREDENTIALS_QUERYPRESENCE)
1245 {
1246 if ( pData->credentialsLogon.szUserName[0]
1247 || pData->credentialsLogon.szPassword[0]
1248 || pData->credentialsLogon.szDomain[0])
1249 {
1250 credentials->u32Flags |= VMMDEV_CREDENTIALS_PRESENT;
1251 }
1252 else
1253 {
1254 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_PRESENT;
1255 }
1256 }
1257
1258 /* does the guest want to read logon credentials? */
1259 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READ)
1260 {
1261 if (pData->credentialsLogon.szUserName[0])
1262 strcpy(credentials->szUserName, pData->credentialsLogon.szUserName);
1263 if (pData->credentialsLogon.szPassword[0])
1264 strcpy(credentials->szPassword, pData->credentialsLogon.szPassword);
1265 if (pData->credentialsLogon.szDomain[0])
1266 strcpy(credentials->szDomain, pData->credentialsLogon.szDomain);
1267 if (!pData->credentialsLogon.fAllowInteractiveLogon)
1268 credentials->u32Flags |= VMMDEV_CREDENTIALS_NOLOCALLOGON;
1269 else
1270 credentials->u32Flags &= ~VMMDEV_CREDENTIALS_NOLOCALLOGON;
1271 }
1272
1273 /* does the caller want us to destroy the logon credentials? */
1274 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEAR)
1275 {
1276 memset(pData->credentialsLogon.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1277 memset(pData->credentialsLogon.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1278 memset(pData->credentialsLogon.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1279 }
1280
1281 /* does the guest want to read credentials for verification? */
1282 if (credentials->u32Flags & VMMDEV_CREDENTIALS_READJUDGE)
1283 {
1284 if (pData->credentialsJudge.szUserName[0])
1285 strcpy(credentials->szUserName, pData->credentialsJudge.szUserName);
1286 if (pData->credentialsJudge.szPassword[0])
1287 strcpy(credentials->szPassword, pData->credentialsJudge.szPassword);
1288 if (pData->credentialsJudge.szDomain[0])
1289 strcpy(credentials->szDomain, pData->credentialsJudge.szDomain);
1290 }
1291
1292 /* does the caller want us to destroy the judgement credentials? */
1293 if (credentials->u32Flags & VMMDEV_CREDENTIALS_CLEARJUDGE)
1294 {
1295 memset(pData->credentialsJudge.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
1296 memset(pData->credentialsJudge.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
1297 memset(pData->credentialsJudge.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
1298 }
1299
1300 requestHeader->rc = VINF_SUCCESS;
1301 }
1302 break;
1303 }
1304
1305 case VMMDevReq_ReportCredentialsJudgement:
1306 {
1307 if (requestHeader->size != sizeof(VMMDevCredentials))
1308 {
1309 AssertMsgFailed(("VMMDevReq_ReportCredentialsJudgement request size too small.\n"));
1310 requestHeader->rc = VERR_INVALID_PARAMETER;
1311 }
1312 else
1313 {
1314 VMMDevCredentials *credentials = (VMMDevCredentials*)requestHeader;
1315
1316 /* what does the guest think about the credentials? (note: the order is important here!) */
1317 if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_DENY)
1318 {
1319 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_DENY);
1320 }
1321 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT)
1322 {
1323 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT);
1324 }
1325 else if (credentials->u32Flags & VMMDEV_CREDENTIALS_JUDGE_OK)
1326 {
1327 pData->pDrv->pfnSetCredentialsJudgementResult(pData->pDrv, VMMDEV_CREDENTIALS_JUDGE_OK);
1328 }
1329 else
1330 Log(("VMMDevReq_ReportCredentialsJudgement: invalid flags: %d!!!\n", credentials->u32Flags));
1331
1332 requestHeader->rc = VINF_SUCCESS;
1333 }
1334 break;
1335 }
1336
1337#ifdef DEBUG
1338 case VMMDevReq_LogString:
1339 {
1340 if (requestHeader->size < sizeof(VMMDevReqLogString))
1341 {
1342 AssertMsgFailed(("VMMDevReq_LogString request size too small.\n"));
1343 requestHeader->rc = VERR_INVALID_PARAMETER;
1344 }
1345 else
1346 {
1347 VMMDevReqLogString *pReqLogString = (VMMDevReqLogString*)requestHeader;
1348#undef LOG_GROUP
1349#define LOG_GROUP LOG_GROUP_DEV_VMM_BACKDOOR
1350// Log(("Guest Log: %s", pReqLogString->szString));
1351 Log(("DEBUG LOG: %s", pReqLogString->szString));
1352
1353#undef LOG_GROUP
1354#define LOG_GROUP LOG_GROUP_DEV_VMM
1355 requestHeader->rc = VINF_SUCCESS;
1356 }
1357 break;
1358 }
1359#endif
1360 default:
1361 {
1362 requestHeader->rc = VERR_NOT_IMPLEMENTED;
1363
1364 Log(("VMMDev unknown request type %d\n", requestHeader->requestType));
1365
1366 break;
1367 }
1368 }
1369
1370 return rcRet;
1371}
1372
1373/**
1374 * Callback function for mapping an PCI I/O region.
1375 *
1376 * @return VBox status code.
1377 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1378 * @param iRegion The region number.
1379 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1380 * I/O port, else it's a physical address.
1381 * This address is *NOT* relative to pci_mem_base like earlier!
1382 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1383 */
1384static DECLCALLBACK(int) vmmdevIORAMRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1385{
1386 int rc;
1387 VMMDevState *pData = PCIDEV_2_VMMDEVSTATE(pPciDev);
1388 LogFlow(("vmmdevR3IORAMRegionMap: iRegion=%d GCPhysAddress=%VGp cb=%#x enmType=%d\n", iRegion, GCPhysAddress, cb, enmType));
1389
1390
1391 Assert(pData->pVMMDevRAMHC != NULL);
1392
1393 memset (pData->pVMMDevRAMHC, 0, sizeof (VMMDevMemory));
1394 pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
1395 pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
1396
1397 /*
1398 * VMMDev RAM mapping.
1399 */
1400 if (iRegion == 1 && enmType == PCI_ADDRESS_SPACE_MEM)
1401 {
1402 /*
1403 * Register and lock the RAM.
1404 *
1405 * Windows usually re-initializes the PCI devices, so we have to check whether the memory was
1406 * already registered before trying to do that all over again.
1407 */
1408 PVM pVM = PDMDevHlpGetVM(pPciDev->pDevIns);
1409
1410 if (pData->GCPhysVMMDevRAM)
1411 {
1412 /*
1413 * Relocate the already registered VMMDevRAM.
1414 */
1415 rc = MMR3PhysRelocate(pVM, pData->GCPhysVMMDevRAM, GCPhysAddress, VMMDEV_RAM_SIZE);
1416 if (VBOX_SUCCESS(rc))
1417 {
1418 pData->GCPhysVMMDevRAM = GCPhysAddress;
1419 return VINF_SUCCESS;
1420 }
1421 AssertReleaseMsgFailed(("Failed to relocate VMMDev RAM from %VGp to %VGp! rc=%Vra\n", pData->GCPhysVMMDevRAM, GCPhysAddress, rc));
1422 }
1423 else
1424 {
1425 /*
1426 * Register and lock the VMMDevRAM.
1427 */
1428 /** @todo MM_RAM_FLAGS_MMIO2 seems to be appropriate for a RW memory.
1429 * Need to check. May be a RO memory is enough for the device.
1430 */
1431 rc = MMR3PhysRegister(pVM, pData->pVMMDevRAMHC, GCPhysAddress, VMMDEV_RAM_SIZE, MM_RAM_FLAGS_MMIO2, "VBoxDev");
1432 if (VBOX_SUCCESS(rc))
1433 {
1434 pData->GCPhysVMMDevRAM = GCPhysAddress;
1435 return VINF_SUCCESS;
1436 }
1437 AssertReleaseMsgFailed(("Failed to register VMMDev RAM! rc=%Vra\n", rc));
1438 }
1439 return rc;
1440 }
1441
1442 AssertReleaseMsgFailed(("VMMDev wrong region type: iRegion=%d enmType=%d\n", iRegion, enmType));
1443 return VERR_INTERNAL_ERROR;
1444}
1445
1446
1447/**
1448 * Callback function for mapping a PCI I/O region.
1449 *
1450 * @return VBox status code.
1451 * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
1452 * @param iRegion The region number.
1453 * @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
1454 * I/O port, else it's a physical address.
1455 * This address is *NOT* relative to pci_mem_base like earlier!
1456 * @param enmType One of the PCI_ADDRESS_SPACE_* values.
1457 */
1458static DECLCALLBACK(int) vmmdevIOPortRegionMap(PPCIDEVICE pPciDev, /*unsigned*/ int iRegion, RTGCPHYS GCPhysAddress, uint32_t cb, PCIADDRESSSPACE enmType)
1459{
1460 VMMDevState *pData = PCIDEV_2_VMMDEVSTATE(pPciDev);
1461 int rc = VINF_SUCCESS;
1462
1463 Assert(enmType == PCI_ADDRESS_SPACE_IO);
1464 Assert(iRegion == 0);
1465 AssertMsg(RT_ALIGN(GCPhysAddress, 8) == GCPhysAddress, ("Expected 8 byte alignment. GCPhysAddress=%#x\n", GCPhysAddress));
1466
1467 /*
1468 * Save the base port address to simplify Port offset calculations.
1469 */
1470 pData->PortBase = (RTIOPORT)GCPhysAddress;
1471
1472 /*
1473 * Register our port IO handlers.
1474 */
1475 rc = PDMDevHlpIOPortRegister(pPciDev->pDevIns,
1476 (RTIOPORT)GCPhysAddress + PORT_VMMDEV_REQUEST_OFFSET, 1,
1477 (void*)pData, vmmdevRequestHandler,
1478 NULL, NULL, NULL, "VMMDev Request Handler");
1479 AssertRC(rc);
1480 return rc;
1481}
1482
1483/**
1484 * Queries an interface to the driver.
1485 *
1486 * @returns Pointer to interface.
1487 * @returns NULL if the interface was not supported by the driver.
1488 * @param pInterface Pointer to this interface structure.
1489 * @param enmInterface The requested interface identification.
1490 * @thread Any thread.
1491 */
1492static DECLCALLBACK(void *) vmmdevPortQueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
1493{
1494 VMMDevState *pData = (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, Base));
1495 switch (enmInterface)
1496 {
1497 case PDMINTERFACE_BASE:
1498 return &pData->Base;
1499 case PDMINTERFACE_VMMDEV_PORT:
1500 return &pData->Port;
1501#ifdef VBOX_HGCM
1502 case PDMINTERFACE_HGCM_PORT:
1503 return &pData->HGCMPort;
1504#endif
1505 case PDMINTERFACE_LED_PORTS:
1506 /* Currently only for shared folders */
1507 return &pData->SharedFolders.ILeds;
1508 default:
1509 return NULL;
1510 }
1511}
1512
1513/**
1514 * Gets the pointer to the status LED of a unit.
1515 *
1516 * @returns VBox status code.
1517 * @param pInterface Pointer to the interface structure containing the called function pointer.
1518 * @param iLUN The unit which status LED we desire.
1519 * @param ppLed Where to store the LED pointer.
1520 */
1521static DECLCALLBACK(int) vmmdevQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
1522{
1523 VMMDevState *pData = (VMMDevState *)( (uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, SharedFolders.ILeds) );
1524 if (iLUN == 0) /* LUN 0 is shared folders */
1525 {
1526 *ppLed = &pData->SharedFolders.Led;
1527 return VINF_SUCCESS;
1528 }
1529 return VERR_PDM_LUN_NOT_FOUND;
1530}
1531
1532/* -=-=-=-=-=- IVMMDevPort -=-=-=-=-=- */
1533
1534/** Converts a VMMDev port interface pointer to a VMMDev state pointer. */
1535#define IVMMDEVPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, Port)) )
1536
1537
1538/**
1539 * Return the current absolute mouse position in pixels
1540 *
1541 * @returns VBox status code
1542 * @param pAbsX Pointer of result value, can be NULL
1543 * @param pAbsY Pointer of result value, can be NULL
1544 */
1545static DECLCALLBACK(int) vmmdevQueryAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t *pAbsX, uint32_t *pAbsY)
1546{
1547 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1548 if (pAbsX)
1549 *pAbsX = pData->mouseXAbs;
1550 if (pAbsY)
1551 *pAbsY = pData->mouseYAbs;
1552 return VINF_SUCCESS;
1553}
1554
1555/**
1556 * Set the new absolute mouse position in pixels
1557 *
1558 * @returns VBox status code
1559 * @param absX New absolute X position
1560 * @param absY New absolute Y position
1561 */
1562static DECLCALLBACK(int) vmmdevSetAbsoluteMouse(PPDMIVMMDEVPORT pInterface, uint32_t absX, uint32_t absY)
1563{
1564 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1565 Log2(("vmmdevSetAbsoluteMouse: settings absolute position to x = %d, y = %d\n", absX, absY));
1566 pData->mouseXAbs = absX;
1567 pData->mouseYAbs = absY;
1568 return VINF_SUCCESS;
1569}
1570
1571/**
1572 * Return the current mouse capability flags
1573 *
1574 * @returns VBox status code
1575 * @param pCapabilities Pointer of result value
1576 */
1577static DECLCALLBACK(int) vmmdevQueryMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t *pCapabilities)
1578{
1579 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1580 if (!pCapabilities)
1581 return VERR_INVALID_PARAMETER;
1582 *pCapabilities = pData->mouseCapabilities;
1583 return VINF_SUCCESS;
1584}
1585
1586/**
1587 * Set the current mouse capability flag (host side)
1588 *
1589 * @returns VBox status code
1590 * @param capabilities Capability mask
1591 */
1592static DECLCALLBACK(int) vmmdevSetMouseCapabilities(PPDMIVMMDEVPORT pInterface, uint32_t capabilities)
1593{
1594 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1595
1596 bool bCapsChanged = ((capabilities & VMMDEV_MOUSEHOSTWANTSABS)
1597 != (pData->mouseCapabilities & VMMDEV_MOUSEHOSTWANTSABS));
1598
1599 Log(("vmmdevSetMouseCapabilities: bCapsChanged %d\n", bCapsChanged));
1600
1601 if (capabilities & VMMDEV_MOUSEHOSTCANNOTHWPOINTER)
1602 pData->mouseCapabilities |= VMMDEV_MOUSEHOSTCANNOTHWPOINTER;
1603 else
1604 pData->mouseCapabilities &= ~VMMDEV_MOUSEHOSTCANNOTHWPOINTER;
1605
1606 if (capabilities & VMMDEV_MOUSEHOSTWANTSABS)
1607 pData->mouseCapabilities |= VMMDEV_MOUSEHOSTWANTSABS;
1608 else
1609 pData->mouseCapabilities &= ~VMMDEV_MOUSEHOSTWANTSABS;
1610
1611 if (bCapsChanged)
1612 VMMDevNotifyGuest (pData, VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED);
1613
1614 return VINF_SUCCESS;
1615}
1616
1617
1618static DECLCALLBACK(int) vmmdevRequestDisplayChange(PPDMIVMMDEVPORT pInterface, uint32_t xres, uint32_t yres, uint32_t bpp, uint32_t display)
1619{
1620 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1621
1622 /* Verify that the new resolution is different and that guest does not yet know about it. */
1623 bool fSameResolution = (!xres || (pData->lastReadDisplayChangeRequest.xres == xres)) &&
1624 (!yres || (pData->lastReadDisplayChangeRequest.yres == yres)) &&
1625 (!bpp || (pData->lastReadDisplayChangeRequest.bpp == bpp)) &&
1626 pData->lastReadDisplayChangeRequest.display == display;
1627
1628 if (!xres && !yres && !bpp)
1629 {
1630 /* Special case of reset video mode. */
1631 fSameResolution = false;
1632 }
1633
1634#ifdef DEBUG_sunlover
1635 Log(("vmmdevRequestDisplayChange: same=%d. new: xres=%d, yres=%d, bpp=%d, display=%d. old: xres=%d, yres=%d, bpp=%d, display=%d.\n",
1636 fSameResolution, xres, yres, bpp, display, pData->lastReadDisplayChangeRequest.xres, pData->lastReadDisplayChangeRequest.yres, pData->lastReadDisplayChangeRequest.bpp, pData->lastReadDisplayChangeRequest.display));
1637#endif /* DEBUG_sunlover */
1638
1639 if (!fSameResolution)
1640 {
1641 LogRel(("VMMDev::SetVideoModeHint: got a video mode hint (%dx%dx%d) at %d\n",
1642 xres, yres, bpp, display));
1643
1644 /* we could validate the information here but hey, the guest can do that as well! */
1645 pData->displayChangeRequest.xres = xres;
1646 pData->displayChangeRequest.yres = yres;
1647 pData->displayChangeRequest.bpp = bpp;
1648 pData->displayChangeRequest.display = display;
1649
1650 /* IRQ so the guest knows what's going on */
1651 VMMDevNotifyGuest (pData, VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST);
1652 }
1653
1654 return VINF_SUCCESS;
1655}
1656
1657static DECLCALLBACK(int) vmmdevRequestSeamlessChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
1658{
1659 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1660
1661 /* Verify that the new resolution is different and that guest does not yet know about it. */
1662 bool fSameMode = (pData->fLastSeamlessEnabled == fEnabled);
1663
1664 Log(("vmmdevRequestSeamlessChange: same=%d. new=%d\n", fSameMode, fEnabled));
1665
1666 if (!fSameMode)
1667 {
1668 /* we could validate the information here but hey, the guest can do that as well! */
1669 pData->fSeamlessEnabled = fEnabled;
1670
1671 /* IRQ so the guest knows what's going on */
1672 VMMDevNotifyGuest (pData, VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST);
1673 }
1674
1675 return VINF_SUCCESS;
1676}
1677
1678static DECLCALLBACK(int) vmmdevSetMemoryBalloon(PPDMIVMMDEVPORT pInterface, uint32_t ulBalloonSize)
1679{
1680 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1681
1682 /* Verify that the new resolution is different and that guest does not yet know about it. */
1683 bool fSame = (pData->u32LastMemoryBalloonSize == ulBalloonSize);
1684
1685 Log(("vmmdevSetMemoryBalloon: old=%d. new=%d\n", pData->u32LastMemoryBalloonSize, ulBalloonSize));
1686
1687 if (!fSame)
1688 {
1689 /* we could validate the information here but hey, the guest can do that as well! */
1690 pData->u32MemoryBalloonSize = ulBalloonSize;
1691
1692 /* IRQ so the guest knows what's going on */
1693 VMMDevNotifyGuest (pData, VMMDEV_EVENT_BALLOON_CHANGE_REQUEST);
1694 }
1695
1696 return VINF_SUCCESS;
1697}
1698
1699static DECLCALLBACK(int) vmmdevSetCredentials(PPDMIVMMDEVPORT pInterface, const char *pszUsername,
1700 const char *pszPassword, const char *pszDomain,
1701 uint32_t u32Flags)
1702{
1703 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1704
1705 /* logon mode? */
1706 if (u32Flags & VMMDEV_SETCREDENTIALS_GUESTLOGON)
1707 {
1708 /* memorize the data */
1709 strcpy(pData->credentialsLogon.szUserName, pszUsername);
1710 strcpy(pData->credentialsLogon.szPassword, pszPassword);
1711 strcpy(pData->credentialsLogon.szDomain, pszDomain);
1712 pData->credentialsLogon.fAllowInteractiveLogon = !(u32Flags & VMMDEV_SETCREDENTIALS_NOLOCALLOGON);
1713 }
1714 /* credentials verification mode? */
1715 else if (u32Flags & VMMDEV_SETCREDENTIALS_JUDGE)
1716 {
1717 /* memorize the data */
1718 strcpy(pData->credentialsJudge.szUserName, pszUsername);
1719 strcpy(pData->credentialsJudge.szPassword, pszPassword);
1720 strcpy(pData->credentialsJudge.szDomain, pszDomain);
1721
1722 VMMDevNotifyGuest (pData, VMMDEV_EVENT_JUDGE_CREDENTIALS);
1723 }
1724 else
1725 return VERR_INVALID_PARAMETER;
1726
1727 return VINF_SUCCESS;
1728}
1729
1730/**
1731 * Notification from the Display. Especially useful when
1732 * acceleration is disabled after a video mode change.
1733 *
1734 * @param fEnable Current acceleration status.
1735 */
1736static DECLCALLBACK(void) vmmdevVBVAChange(PPDMIVMMDEVPORT pInterface, bool fEnabled)
1737{
1738 VMMDevState *pData = IVMMDEVPORT_2_VMMDEVSTATE(pInterface);
1739
1740 Log(("vmmdevVBVAChange: fEnabled = %d\n", fEnabled));
1741
1742 if (pData)
1743 {
1744 pData->u32VideoAccelEnabled = fEnabled;
1745 }
1746
1747 return;
1748}
1749
1750
1751/* -=-=-=-=-=- IHGCMPort -=-=-=-=-=- */
1752
1753/** Converts a VMMDev port interface pointer to a VMMDev state pointer. */
1754#define IHGCMPORT_2_VMMDEVSTATE(pInterface) ( (VMMDevState*)((uintptr_t)pInterface - RT_OFFSETOF(VMMDevState, HGCMPort)) )
1755
1756
1757
1758#define VMMDEV_SSM_VERSION 5
1759
1760/**
1761 * Saves a state of the VMM device.
1762 *
1763 * @returns VBox status code.
1764 * @param pDevIns The device instance.
1765 * @param pSSMHandle The handle to save the state to.
1766 */
1767static DECLCALLBACK(int) vmmdevSaveState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1768{
1769 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
1770 SSMR3PutU32(pSSMHandle, pData->hypervisorSize);
1771 SSMR3PutU32(pSSMHandle, pData->mouseCapabilities);
1772 SSMR3PutU32(pSSMHandle, pData->mouseXAbs);
1773 SSMR3PutU32(pSSMHandle, pData->mouseYAbs);
1774
1775 SSMR3PutBool(pSSMHandle, pData->fNewGuestFilterMask);
1776 SSMR3PutU32(pSSMHandle, pData->u32NewGuestFilterMask);
1777 SSMR3PutU32(pSSMHandle, pData->u32GuestFilterMask);
1778 SSMR3PutU32(pSSMHandle, pData->u32HostEventFlags);
1779 // here be dragons (probably)
1780// SSMR3PutBool(pSSMHandle, pData->pVMMDevRAMHC->V.V1_04.fHaveEvents);
1781 SSMR3PutMem(pSSMHandle, &pData->pVMMDevRAMHC->V, sizeof (pData->pVMMDevRAMHC->V));
1782
1783 SSMR3PutMem(pSSMHandle, &pData->guestInfo, sizeof (pData->guestInfo));
1784 SSMR3PutU32(pSSMHandle, pData->fu32AdditionsOk);
1785 SSMR3PutU32(pSSMHandle, pData->u32VideoAccelEnabled);
1786
1787 SSMR3PutU32(pSSMHandle, pData->guestCaps);
1788
1789#ifdef VBOX_HGCM
1790 vmmdevHGCMSaveState (pData, pSSMHandle);
1791#endif /* VBOX_HGCM */
1792
1793 return VINF_SUCCESS;
1794}
1795
1796/**
1797 * Loads the saved VMM device state.
1798 *
1799 * @returns VBox status code.
1800 * @param pDevIns The device instance.
1801 * @param pSSMHandle The handle to the saved state.
1802 * @param u32Version The data unit version number.
1803 */
1804static DECLCALLBACK(int) vmmdevLoadState(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
1805{
1806 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
1807 if (u32Version != VMMDEV_SSM_VERSION)
1808 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1809 SSMR3GetU32(pSSMHandle, &pData->hypervisorSize);
1810 SSMR3GetU32(pSSMHandle, &pData->mouseCapabilities);
1811 SSMR3GetU32(pSSMHandle, &pData->mouseXAbs);
1812 SSMR3GetU32(pSSMHandle, &pData->mouseYAbs);
1813
1814 SSMR3GetBool(pSSMHandle, &pData->fNewGuestFilterMask);
1815 SSMR3GetU32(pSSMHandle, &pData->u32NewGuestFilterMask);
1816 SSMR3GetU32(pSSMHandle, &pData->u32GuestFilterMask);
1817 SSMR3GetU32(pSSMHandle, &pData->u32HostEventFlags);
1818// SSMR3GetBool(pSSMHandle, &pData->pVMMDevRAMHC->fHaveEvents);
1819 // here be dragons (probably)
1820 SSMR3GetMem(pSSMHandle, &pData->pVMMDevRAMHC->V, sizeof (pData->pVMMDevRAMHC->V));
1821
1822 SSMR3GetMem(pSSMHandle, &pData->guestInfo, sizeof (pData->guestInfo));
1823 SSMR3GetU32(pSSMHandle, &pData->fu32AdditionsOk);
1824 SSMR3GetU32(pSSMHandle, &pData->u32VideoAccelEnabled);
1825
1826 SSMR3GetU32(pSSMHandle, &pData->guestCaps);
1827
1828#ifdef VBOX_HGCM
1829 vmmdevHGCMLoadState (pData, pSSMHandle);
1830#endif /* VBOX_HGCM */
1831
1832 /*
1833 * On a resume, we send the capabilities changed message so
1834 * that listeners can sync their state again
1835 */
1836 Log(("vmmdevLoadState: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
1837 if (pData->pDrv)
1838 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
1839
1840 /* Reestablish the acceleration status. */
1841 if ( pData->u32VideoAccelEnabled
1842 && pData->pDrv)
1843 {
1844 pData->pDrv->pfnVideoAccelEnable (pData->pDrv, !!pData->u32VideoAccelEnabled, &pData->pVMMDevRAMHC->vbvaMemory);
1845 }
1846
1847 if (pData->fu32AdditionsOk)
1848 {
1849 LogRel(("Guest Additions information report: additionsVersion = 0x%08X osType = 0x%08X\n",
1850 pData->guestInfo.additionsVersion,
1851 pData->guestInfo.osType));
1852 if (pData->pDrv)
1853 pData->pDrv->pfnUpdateGuestVersion(pData->pDrv, &pData->guestInfo);
1854 }
1855 if (pData->pDrv)
1856 pData->pDrv->pfnUpdateGuestCapabilities(pData->pDrv, pData->guestCaps);
1857
1858 return VINF_SUCCESS;
1859}
1860
1861/**
1862 * Load state done callback. Notify guest of restore event.
1863 *
1864 * @returns VBox status code.
1865 * @param pDevIns The device instance.
1866 * @param pSSMHandle The handle to the saved state.
1867 */
1868static DECLCALLBACK(int) vmmdevLoadStateDone(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
1869{
1870 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
1871
1872#ifdef VBOX_HGCM
1873 vmmdevHGCMLoadStateDone (pData, pSSMHandle);
1874#endif /* VBOX_HGCM */
1875
1876 VMMDevNotifyGuest (pData, VMMDEV_EVENT_RESTORED);
1877
1878 return VINF_SUCCESS;
1879}
1880
1881/**
1882 * Construct a device instance for a VM.
1883 *
1884 * @returns VBox status.
1885 * @param pDevIns The device instance data.
1886 * If the registration structure is needed, pDevIns->pDevReg points to it.
1887 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1888 * The device number is also found in pDevIns->iInstance, but since it's
1889 * likely to be freqently used PDM passes it as parameter.
1890 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1891 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1892 * iInstance it's expected to be used a bit in this function.
1893 */
1894static DECLCALLBACK(int) vmmdevConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1895{
1896 int rc;
1897 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState *);
1898
1899 Assert(iInstance == 0);
1900
1901 /*
1902 * Validate and read the configuration.
1903 */
1904 if (!CFGMR3AreValuesValid(pCfgHandle, "GetHostTimeDisabled\0BackdoorLogDisabled\0"))
1905 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1906
1907 rc = CFGMR3QueryBool(pCfgHandle, "GetHostTimeDisabled", &pData->fGetHostTimeDisabled);
1908 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1909 pData->fGetHostTimeDisabled = false;
1910 else if (VBOX_FAILURE(rc))
1911 return PDMDEV_SET_ERROR(pDevIns, rc,
1912 N_("Configuration error: Failed querying \"GetHostTimeDisabled\" as a boolean"));
1913
1914 rc = CFGMR3QueryBool(pCfgHandle, "BackdoorLogDisabled", &pData->fBackdoorLogDisabled);
1915 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1916 pData->fBackdoorLogDisabled = false;
1917 else if (VBOX_FAILURE(rc))
1918 return PDMDEV_SET_ERROR(pDevIns, rc,
1919 N_("Configuration error: Failed querying \"BackdoorLogDisabled\" as a boolean"));
1920
1921 /*
1922 * Initialize data (most of it anyway).
1923 */
1924 /* Save PDM device instance data for future reference. */
1925 pData->pDevIns = pDevIns;
1926
1927 /* PCI vendor, just a free bogus value */
1928 pData->dev.config[0x00] = 0xee;
1929 pData->dev.config[0x01] = 0x80;
1930 /* device ID */
1931 pData->dev.config[0x02] = 0xfe;
1932 pData->dev.config[0x03] = 0xca;
1933 /* class sub code (other type of system peripheral) */
1934 pData->dev.config[0x0a] = 0x80;
1935 /* class base code (base system peripheral) */
1936 pData->dev.config[0x0b] = 0x08;
1937 /* header type */
1938 pData->dev.config[0x0e] = 0x00;
1939 /* interrupt on pin 0 */
1940 pData->dev.config[0x3d] = 0x01;
1941
1942 /*
1943 * Register the backdoor logging port
1944 */
1945 rc = PDMDevHlpIOPortRegister(pDevIns, RTLOG_DEBUG_PORT, 1, NULL, vmmdevBackdoorLog, NULL, NULL, NULL, "VMMDev backdoor logging");
1946 AssertRCReturn(rc, rc);
1947
1948#ifdef TIMESYNC_BACKDOOR
1949 /*
1950 * Alternative timesync source (temporary!)
1951 */
1952 rc = PDMDevHlpIOPortRegister(pDevIns, 0x505, 1, NULL, vmmdevTimesyncBackdoorWrite, vmmdevTimesyncBackdoorRead, NULL, NULL, "VMMDev timesync backdoor");
1953 AssertRCReturn(rc, rc);
1954#endif
1955
1956 /*
1957 * Register the PCI device.
1958 */
1959 rc = PDMDevHlpPCIRegister(pDevIns, &pData->dev);
1960 if (VBOX_FAILURE(rc))
1961 return rc;
1962 if (pData->dev.devfn == 32 || iInstance != 0)
1963 Log(("!!WARNING!!: pData->dev.devfn=%d (ignore if testcase or no started by Main)\n", pData->dev.devfn));
1964 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, 0x20, PCI_ADDRESS_SPACE_IO, vmmdevIOPortRegionMap);
1965 if (VBOX_FAILURE(rc))
1966 return rc;
1967 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 1, VMMDEV_RAM_SIZE, PCI_ADDRESS_SPACE_MEM, vmmdevIORAMRegionMap);
1968 if (VBOX_FAILURE(rc))
1969 return rc;
1970
1971 /*
1972 * Interfaces
1973 */
1974 /* Base */
1975 pData->Base.pfnQueryInterface = vmmdevPortQueryInterface;
1976
1977 /* VMMDev port */
1978 pData->Port.pfnQueryAbsoluteMouse = vmmdevQueryAbsoluteMouse;
1979 pData->Port.pfnSetAbsoluteMouse = vmmdevSetAbsoluteMouse;
1980 pData->Port.pfnQueryMouseCapabilities = vmmdevQueryMouseCapabilities;
1981 pData->Port.pfnSetMouseCapabilities = vmmdevSetMouseCapabilities;
1982 pData->Port.pfnRequestDisplayChange = vmmdevRequestDisplayChange;
1983 pData->Port.pfnSetCredentials = vmmdevSetCredentials;
1984 pData->Port.pfnVBVAChange = vmmdevVBVAChange;
1985 pData->Port.pfnRequestSeamlessChange = vmmdevRequestSeamlessChange;
1986 pData->Port.pfnSetMemoryBalloon = vmmdevSetMemoryBalloon;
1987
1988 /* Shared folder LED */
1989 pData->SharedFolders.Led.u32Magic = PDMLED_MAGIC;
1990 pData->SharedFolders.ILeds.pfnQueryStatusLed = vmmdevQueryStatusLed;
1991
1992#ifdef VBOX_HGCM
1993 /* HGCM port */
1994 pData->HGCMPort.pfnCompleted = hgcmCompleted;
1995#endif
1996
1997 /*
1998 * Get the corresponding connector interface
1999 */
2000 rc = PDMDevHlpDriverAttach(pDevIns, 0, &pData->Base, &pData->pDrvBase, "VMM Driver Port");
2001 if (VBOX_SUCCESS(rc))
2002 {
2003 pData->pDrv = (PPDMIVMMDEVCONNECTOR)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_VMMDEV_CONNECTOR);
2004 if (!pData->pDrv)
2005 AssertMsgFailedReturn(("LUN #0 doesn't have a VMMDev connector interface!\n"), VERR_PDM_MISSING_INTERFACE);
2006#ifdef VBOX_HGCM
2007 pData->pHGCMDrv = (PPDMIHGCMCONNECTOR)pData->pDrvBase->pfnQueryInterface(pData->pDrvBase, PDMINTERFACE_HGCM_CONNECTOR);
2008 if (!pData->pHGCMDrv)
2009 {
2010 Log(("LUN #0 doesn't have a HGCM connector interface, HGCM is not supported. rc=%Vrc\n", rc));
2011 /* this is not actually an error, just means that there is no support for HGCM */
2012 }
2013#endif
2014 }
2015 else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
2016 {
2017 Log(("%s/%d: warning: no driver attached to LUN #0!\n", pDevIns->pDevReg->szDeviceName, pDevIns->iInstance));
2018 rc = VINF_SUCCESS;
2019 }
2020 else
2021 AssertMsgFailedReturn(("Failed to attach LUN #0! rc=%Vrc\n", rc), rc);
2022
2023 /*
2024 * Attach status driver for shared folders (optional).
2025 */
2026 PPDMIBASE pBase;
2027 rc = PDMDevHlpDriverAttach(pDevIns, PDM_STATUS_LUN, &pData->Base, &pBase, "Status Port");
2028 if (VBOX_SUCCESS(rc))
2029 pData->SharedFolders.pLedsConnector = (PPDMILEDCONNECTORS)
2030 pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
2031 else if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
2032 {
2033 AssertMsgFailed(("Failed to attach to status driver. rc=%Vrc\n", rc));
2034 return rc;
2035 }
2036
2037 /*
2038 * Register saved state and init the HGCM CmdList critsect.
2039 */
2040 rc = PDMDevHlpSSMRegister(pDevIns, "VMMDev", iInstance, VMMDEV_SSM_VERSION, sizeof(*pData),
2041 NULL, vmmdevSaveState, NULL,
2042 NULL, vmmdevLoadState, vmmdevLoadStateDone);
2043 AssertRCReturn(rc, rc);
2044
2045#ifdef VBOX_HGCM
2046 pData->pHGCMCmdList = NULL;
2047 rc = RTCritSectInit(&pData->critsectHGCMCmdList);
2048 AssertRCReturn(rc, rc);
2049 pData->u32HGCMEnabled = 0;
2050#endif /* VBOX_HGCM */
2051
2052 /*
2053 * Allocate the VMMDev RAM region.
2054 */
2055 /** @todo freeing of the RAM. */
2056 rc = SUPPageAlloc(VMMDEV_RAM_SIZE >> PAGE_SHIFT, (void **)&pData->pVMMDevRAMHC);
2057 AssertMsgRCReturn(rc, ("VMMDev SUPPageAlloc(%#x,) -> %Vrc\n", VMMDEV_RAM_SIZE, rc), rc);
2058
2059 /* initialize the VMMDev memory */
2060 pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
2061 pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
2062
2063 return rc;
2064}
2065
2066/**
2067 * Reset notification.
2068 *
2069 * @returns VBox status.
2070 * @param pDrvIns The driver instance data.
2071 */
2072static DECLCALLBACK(void) vmmdevReset(PPDMDEVINS pDevIns)
2073{
2074 VMMDevState *pData = PDMINS2DATA(pDevIns, VMMDevState*);
2075 /*
2076 * Reset the mouse integration feature bit
2077 */
2078 if (pData->mouseCapabilities & (VMMDEV_MOUSEGUESTWANTSABS|VMMDEV_MOUSEGUESTNEEDSHOSTCUR))
2079 {
2080 pData->mouseCapabilities &= ~VMMDEV_MOUSEGUESTWANTSABS;
2081 /* notify the connector */
2082 Log(("vmmdevReset: capabilities changed (%x), informing connector\n", pData->mouseCapabilities));
2083 pData->pDrv->pfnUpdateMouseCapabilities(pData->pDrv, pData->mouseCapabilities);
2084 }
2085
2086 pData->hypervisorSize = 0;
2087
2088 pData->u32HostEventFlags = 0;
2089
2090 if (pData->pVMMDevRAMHC)
2091 {
2092 /* re-initialize the VMMDev memory */
2093 memset (pData->pVMMDevRAMHC, 0, VMMDEV_RAM_SIZE);
2094 pData->pVMMDevRAMHC->u32Size = sizeof (VMMDevMemory);
2095 pData->pVMMDevRAMHC->u32Version = VMMDEV_MEMORY_VERSION;
2096 }
2097
2098 /* credentials have to go away */
2099 memset(pData->credentialsLogon.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
2100 memset(pData->credentialsLogon.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
2101 memset(pData->credentialsLogon.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
2102 memset(pData->credentialsJudge.szUserName, '\0', VMMDEV_CREDENTIALS_STRLEN);
2103 memset(pData->credentialsJudge.szPassword, '\0', VMMDEV_CREDENTIALS_STRLEN);
2104 memset(pData->credentialsJudge.szDomain, '\0', VMMDEV_CREDENTIALS_STRLEN);
2105
2106 /* Reset means that additions will report again. */
2107 pData->fu32AdditionsOk = false;
2108 memset (&pData->guestInfo, 0, sizeof (pData->guestInfo));
2109 pData->guestCaps = 0;
2110
2111 memset (&pData->lastReadDisplayChangeRequest, 0, sizeof (pData->lastReadDisplayChangeRequest));
2112
2113 /* disable seamless mode */
2114 pData->fLastSeamlessEnabled = false;
2115
2116 /* disabled memory ballooning */
2117 pData->u32LastMemoryBalloonSize = 0;
2118
2119 /* Clear the event variables.
2120 *
2121 * Note: The pData->u32HostEventFlags is not cleared.
2122 * It is designed that way so host events do not
2123 * depend on guest resets.
2124 */
2125 pData->u32GuestFilterMask = 0;
2126 pData->u32NewGuestFilterMask = 0;
2127 pData->fNewGuestFilterMask = 0;
2128}
2129
2130
2131/**
2132 * The device registration structure.
2133 */
2134extern "C" const PDMDEVREG g_DeviceVMMDev =
2135{
2136 /* u32Version */
2137 PDM_DEVREG_VERSION,
2138 /* szDeviceName */
2139 "VMMDev",
2140 /* szGCMod */
2141 "",
2142 /* szR0Mod */
2143 "",
2144 /* pszDescription */
2145 "VirtualBox VMM Device\n",
2146 /* fFlags */
2147 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32,
2148 /* fClass */
2149 PDM_DEVREG_CLASS_VMM_DEV,
2150 /* cMaxInstances */
2151 1,
2152 /* cbInstance */
2153 sizeof(VMMDevState),
2154 /* pfnConstruct */
2155 vmmdevConstruct,
2156 /* pfnDestruct */
2157 NULL,
2158 /* pfnRelocate */
2159 NULL,
2160 /* pfnIOCtl */
2161 NULL,
2162 /* pfnPowerOn */
2163 NULL,
2164 /* pfnReset */
2165 vmmdevReset,
2166 /* pfnSuspend */
2167 NULL,
2168 /* pfnResume */
2169 NULL,
2170 /* pfnAttach */
2171 NULL,
2172 /* pfnDetach */
2173 NULL,
2174 /* pfnQueryInterface. */
2175 NULL
2176};
2177#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
2178
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