VirtualBox

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

Last change on this file since 3477 was 3409, checked in by vboxsync, 18 years ago

Report saved additions information after restoring from saved state.

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