VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/VMMDevInterface.cpp

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.9 KB
Line 
1/* $Id: VMMDevInterface.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VirtualBox Driver Interface to VMM device.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_VMMDEVINTERFACES
29#include "LoggingNew.h"
30
31#include "VMMDev.h"
32#include "ConsoleImpl.h"
33#include "DisplayImpl.h"
34#include "GuestImpl.h"
35#include "MouseImpl.h"
36
37#include <VBox/vmm/pdmdrv.h>
38#include <VBox/VMMDev.h>
39#include <VBox/shflsvc.h>
40#include <iprt/asm.h>
41
42#ifdef VBOX_WITH_HGCM
43# include "HGCM.h"
44# include "HGCMObjects.h"
45#endif
46
47//
48// defines
49//
50
51#ifdef RT_OS_OS2
52# define VBOXSHAREDFOLDERS_DLL "VBoxSFld"
53#else
54# define VBOXSHAREDFOLDERS_DLL "VBoxSharedFolders"
55#endif
56
57//
58// globals
59//
60
61
62/**
63 * VMMDev driver instance data.
64 */
65typedef struct DRVMAINVMMDEV
66{
67 /** Pointer to the VMMDev object. */
68 VMMDev *pVMMDev;
69 /** Pointer to the driver instance structure. */
70 PPDMDRVINS pDrvIns;
71 /** Pointer to the VMMDev port interface of the driver/device above us. */
72 PPDMIVMMDEVPORT pUpPort;
73 /** Our VMM device connector interface. */
74 PDMIVMMDEVCONNECTOR Connector;
75
76#ifdef VBOX_WITH_HGCM
77 /** Pointer to the HGCM port interface of the driver/device above us. */
78 PPDMIHGCMPORT pHGCMPort;
79 /** Our HGCM connector interface. */
80 PDMIHGCMCONNECTOR HGCMConnector;
81#endif
82
83#ifdef VBOX_WITH_GUEST_PROPS
84 HGCMSVCEXTHANDLE hHgcmSvcExtGstProps;
85#endif
86#ifdef VBOX_WITH_GUEST_CONTROL
87 HGCMSVCEXTHANDLE hHgcmSvcExtGstCtrl;
88#endif
89} DRVMAINVMMDEV, *PDRVMAINVMMDEV;
90
91//
92// constructor / destructor
93//
94VMMDev::VMMDev(Console *console)
95 : mpDrv(NULL)
96 , mParent(console)
97{
98 int vrc = RTSemEventCreate(&mCredentialsEvent);
99 AssertRC(vrc);
100#ifdef VBOX_WITH_HGCM
101 vrc = HGCMHostInit();
102 AssertRC(vrc);
103 m_fHGCMActive = true;
104#endif /* VBOX_WITH_HGCM */
105 mu32CredentialsFlags = 0;
106}
107
108VMMDev::~VMMDev()
109{
110#ifdef VBOX_WITH_HGCM
111 if (ASMAtomicCmpXchgBool(&m_fHGCMActive, false, true))
112 HGCMHostShutdown(true /*fUvmIsInvalid*/);
113#endif
114 RTSemEventDestroy(mCredentialsEvent);
115 if (mpDrv)
116 mpDrv->pVMMDev = NULL;
117 mpDrv = NULL;
118}
119
120PPDMIVMMDEVPORT VMMDev::getVMMDevPort()
121{
122 if (!mpDrv)
123 return NULL;
124 return mpDrv->pUpPort;
125}
126
127
128
129//
130// public methods
131//
132
133/**
134 * Wait on event semaphore for guest credential judgement result.
135 */
136int VMMDev::WaitCredentialsJudgement(uint32_t u32Timeout, uint32_t *pu32CredentialsFlags)
137{
138 if (u32Timeout == 0)
139 {
140 u32Timeout = 5000;
141 }
142
143 int vrc = RTSemEventWait(mCredentialsEvent, u32Timeout);
144
145 if (RT_SUCCESS(vrc))
146 {
147 *pu32CredentialsFlags = mu32CredentialsFlags;
148 }
149
150 return vrc;
151}
152
153int VMMDev::SetCredentialsJudgementResult(uint32_t u32Flags)
154{
155 mu32CredentialsFlags = u32Flags;
156
157 int vrc = RTSemEventSignal(mCredentialsEvent);
158 AssertRC(vrc);
159
160 return vrc;
161}
162
163
164/**
165 * @interface_method_impl{PDMIVMMDEVCONNECTOR,pfnUpdateGuestStatus}
166 */
167static DECLCALLBACK(void) vmmdevUpdateGuestStatus(PPDMIVMMDEVCONNECTOR pInterface, uint32_t uFacility, uint16_t uStatus,
168 uint32_t fFlags, PCRTTIMESPEC pTimeSpecTS)
169{
170 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
171 Console *pConsole = pDrv->pVMMDev->getParent();
172
173 /* Store that information in IGuest */
174 Guest* guest = pConsole->i_getGuest();
175 AssertPtrReturnVoid(guest);
176
177 guest->i_setAdditionsStatus((VBoxGuestFacilityType)uFacility, (VBoxGuestFacilityStatus)uStatus, fFlags, pTimeSpecTS);
178 pConsole->i_onAdditionsStateChange();
179}
180
181
182/**
183 * @interface_method_impl{PDMIVMMDEVCONNECTOR,pfnUpdateGuestUserState}
184 */
185static DECLCALLBACK(void) vmmdevUpdateGuestUserState(PPDMIVMMDEVCONNECTOR pInterface,
186 const char *pszUser, const char *pszDomain,
187 uint32_t uState,
188 const uint8_t *pabDetails, uint32_t cbDetails)
189{
190 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
191 AssertPtr(pDrv);
192 Console *pConsole = pDrv->pVMMDev->getParent();
193 AssertPtr(pConsole);
194
195 /* Store that information in IGuest. */
196 Guest* pGuest = pConsole->i_getGuest();
197 AssertPtrReturnVoid(pGuest);
198
199 pGuest->i_onUserStateChanged(Utf8Str(pszUser), Utf8Str(pszDomain), (VBoxGuestUserState)uState, pabDetails, cbDetails);
200}
201
202
203/**
204 * Reports Guest Additions API and OS version.
205 *
206 * Called whenever the Additions issue a guest version report request or the VM
207 * is reset.
208 *
209 * @param pInterface Pointer to this interface.
210 * @param guestInfo Pointer to guest information structure.
211 * @thread The emulation thread.
212 */
213static DECLCALLBACK(void) vmmdevUpdateGuestInfo(PPDMIVMMDEVCONNECTOR pInterface, const VBoxGuestInfo *guestInfo)
214{
215 AssertPtrReturnVoid(guestInfo);
216
217 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
218 Console *pConsole = pDrv->pVMMDev->getParent();
219
220 /* Store that information in IGuest */
221 Guest* guest = pConsole->i_getGuest();
222 AssertPtrReturnVoid(guest);
223
224 if (guestInfo->interfaceVersion != 0)
225 {
226 char version[16];
227 RTStrPrintf(version, sizeof(version), "%d", guestInfo->interfaceVersion);
228 guest->i_setAdditionsInfo(Bstr(version), guestInfo->osType);
229
230 /*
231 * Tell the console interface about the event
232 * so that it can notify its consumers.
233 */
234 pConsole->i_onAdditionsStateChange();
235
236 if (guestInfo->interfaceVersion < VMMDEV_VERSION)
237 pConsole->i_onAdditionsOutdated();
238 }
239 else
240 {
241 /*
242 * The Guest Additions was disabled because of a reset
243 * or driver unload.
244 */
245 guest->i_setAdditionsInfo(Bstr(), guestInfo->osType); /* Clear interface version + OS type. */
246 /** @todo Would be better if GuestImpl.cpp did all this in the above method call
247 * while holding down the. */
248 guest->i_setAdditionsInfo2(0, "", 0, 0); /* Clear Guest Additions version. */
249 RTTIMESPEC TimeSpecTS;
250 RTTimeNow(&TimeSpecTS);
251 guest->i_setAdditionsStatus(VBoxGuestFacilityType_All, VBoxGuestFacilityStatus_Inactive, 0 /*fFlags*/, &TimeSpecTS);
252 pConsole->i_onAdditionsStateChange();
253 }
254}
255
256/**
257 * @interface_method_impl{PDMIVMMDEVCONNECTOR,pfnUpdateGuestInfo2}
258 */
259static DECLCALLBACK(void) vmmdevUpdateGuestInfo2(PPDMIVMMDEVCONNECTOR pInterface, uint32_t uFullVersion,
260 const char *pszName, uint32_t uRevision, uint32_t fFeatures)
261{
262 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
263 AssertPtr(pszName);
264 Assert(uFullVersion);
265
266 /* Store that information in IGuest. */
267 Guest *pGuest = pDrv->pVMMDev->getParent()->i_getGuest();
268 AssertPtrReturnVoid(pGuest);
269
270 /* Just pass it on... */
271 pGuest->i_setAdditionsInfo2(uFullVersion, pszName, uRevision, fFeatures);
272
273 /*
274 * No need to tell the console interface about the update;
275 * vmmdevUpdateGuestInfo takes care of that when called as the
276 * last event in the chain.
277 */
278}
279
280/**
281 * Update the Guest Additions capabilities.
282 * This is called when the Guest Additions capabilities change. The new capabilities
283 * are given and the connector should update its internal state.
284 *
285 * @param pInterface Pointer to this interface.
286 * @param newCapabilities New capabilities.
287 * @thread The emulation thread.
288 */
289static DECLCALLBACK(void) vmmdevUpdateGuestCapabilities(PPDMIVMMDEVCONNECTOR pInterface, uint32_t newCapabilities)
290{
291 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
292 AssertPtr(pDrv);
293 Console *pConsole = pDrv->pVMMDev->getParent();
294
295 /* store that information in IGuest */
296 Guest* pGuest = pConsole->i_getGuest();
297 AssertPtrReturnVoid(pGuest);
298
299 /*
300 * Report our current capabilities (and assume none is active yet).
301 */
302 pGuest->i_setSupportedFeatures(newCapabilities);
303
304 /*
305 * Tell the Display, so that it can update the "supports graphics"
306 * capability if the graphics card has not asserted it.
307 */
308 Display* pDisplay = pConsole->i_getDisplay();
309 AssertPtrReturnVoid(pDisplay);
310 pDisplay->i_handleUpdateVMMDevSupportsGraphics(RT_BOOL(newCapabilities & VMMDEV_GUEST_SUPPORTS_GRAPHICS));
311
312 /*
313 * Tell the console interface about the event
314 * so that it can notify its consumers.
315 */
316 pConsole->i_onAdditionsStateChange();
317}
318
319/**
320 * Update the mouse capabilities.
321 * This is called when the mouse capabilities change. The new capabilities
322 * are given and the connector should update its internal state.
323 *
324 * @param pInterface Pointer to this interface.
325 * @param fNewCaps New capabilities.
326 * @thread The emulation thread.
327 */
328static DECLCALLBACK(void) vmmdevUpdateMouseCapabilities(PPDMIVMMDEVCONNECTOR pInterface, uint32_t fNewCaps)
329{
330 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
331 Console *pConsole = pDrv->pVMMDev->getParent();
332
333 /*
334 * Tell the console interface about the event
335 * so that it can notify its consumers.
336 */
337 Mouse *pMouse = pConsole->i_getMouse();
338 if (pMouse) /** @todo and if not? Can that actually happen? */
339 pMouse->i_onVMMDevGuestCapsChange(fNewCaps & VMMDEV_MOUSE_GUEST_MASK);
340}
341
342/**
343 * Update the pointer shape or visibility.
344 *
345 * This is called when the mouse pointer shape changes or pointer is hidden/displaying.
346 * The new shape is passed as a caller allocated buffer that will be freed after returning.
347 *
348 * @param pInterface Pointer to this interface.
349 * @param fVisible Whether the pointer is visible or not.
350 * @param fAlpha Alpha channel information is present.
351 * @param xHot Horizontal coordinate of the pointer hot spot.
352 * @param yHot Vertical coordinate of the pointer hot spot.
353 * @param width Pointer width in pixels.
354 * @param height Pointer height in pixels.
355 * @param pShape The shape buffer. If NULL, then only pointer visibility is being changed.
356 * @thread The emulation thread.
357 */
358static DECLCALLBACK(void) vmmdevUpdatePointerShape(PPDMIVMMDEVCONNECTOR pInterface, bool fVisible, bool fAlpha,
359 uint32_t xHot, uint32_t yHot,
360 uint32_t width, uint32_t height,
361 void *pShape)
362{
363 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
364 Console *pConsole = pDrv->pVMMDev->getParent();
365
366 /* tell the console about it */
367 uint32_t cbShape = 0;
368 if (pShape)
369 {
370 cbShape = (width + 7) / 8 * height; /* size of the AND mask */
371 cbShape = ((cbShape + 3) & ~3) + width * 4 * height; /* + gap + size of the XOR mask */
372 }
373 pConsole->i_onMousePointerShapeChange(fVisible, fAlpha, xHot, yHot, width, height, (uint8_t *)pShape, cbShape);
374}
375
376static DECLCALLBACK(int) iface_VideoAccelEnable(PPDMIVMMDEVCONNECTOR pInterface, bool fEnable, VBVAMEMORY *pVbvaMemory)
377{
378 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
379 Console *pConsole = pDrv->pVMMDev->getParent();
380
381 Display *display = pConsole->i_getDisplay();
382
383 if (display)
384 {
385 Log9(("MAIN::VMMDevInterface::iface_VideoAccelEnable: %d, %p\n", fEnable, pVbvaMemory));
386 return display->VideoAccelEnableVMMDev(fEnable, pVbvaMemory);
387 }
388
389 return VERR_NOT_SUPPORTED;
390}
391
392static DECLCALLBACK(void) iface_VideoAccelFlush(PPDMIVMMDEVCONNECTOR pInterface)
393{
394 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
395 Console *pConsole = pDrv->pVMMDev->getParent();
396
397 Display *display = pConsole->i_getDisplay();
398
399 if (display)
400 {
401 Log9(("MAIN::VMMDevInterface::iface_VideoAccelFlush\n"));
402 display->VideoAccelFlushVMMDev();
403 }
404}
405
406static DECLCALLBACK(int) vmmdevVideoModeSupported(PPDMIVMMDEVCONNECTOR pInterface, uint32_t display, uint32_t width, uint32_t height,
407 uint32_t bpp, bool *fSupported)
408{
409 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
410 Console *pConsole = pDrv->pVMMDev->getParent();
411
412 if (!fSupported)
413 return VERR_INVALID_PARAMETER;
414#ifdef DEBUG_sunlover
415 Log(("vmmdevVideoModeSupported: [%d]: %dx%dx%d\n", display, width, height, bpp));
416#endif
417 IFramebuffer *framebuffer = NULL;
418 HRESULT hrc = pConsole->i_getDisplay()->QueryFramebuffer(display, &framebuffer);
419 if (SUCCEEDED(hrc) && framebuffer)
420 {
421 framebuffer->VideoModeSupported(width, height, bpp, (BOOL*)fSupported);
422 framebuffer->Release();
423 }
424 else
425 {
426#ifdef DEBUG_sunlover
427 Log(("vmmdevVideoModeSupported: hrc %x, framebuffer %p!!!\n", hrc, framebuffer));
428#endif
429 *fSupported = true;
430 }
431 return VINF_SUCCESS;
432}
433
434static DECLCALLBACK(int) vmmdevGetHeightReduction(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *heightReduction)
435{
436 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
437 Console *pConsole = pDrv->pVMMDev->getParent();
438
439 if (!heightReduction)
440 return VERR_INVALID_PARAMETER;
441 IFramebuffer *framebuffer = NULL;
442 HRESULT hrc = pConsole->i_getDisplay()->QueryFramebuffer(0, &framebuffer);
443 if (SUCCEEDED(hrc) && framebuffer)
444 {
445 framebuffer->COMGETTER(HeightReduction)((ULONG*)heightReduction);
446 framebuffer->Release();
447 }
448 else
449 *heightReduction = 0;
450 return VINF_SUCCESS;
451}
452
453static DECLCALLBACK(int) vmmdevSetCredentialsJudgementResult(PPDMIVMMDEVCONNECTOR pInterface, uint32_t u32Flags)
454{
455 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
456
457 if (pDrv->pVMMDev)
458 return pDrv->pVMMDev->SetCredentialsJudgementResult(u32Flags);
459
460 return VERR_GENERAL_FAILURE;
461}
462
463static DECLCALLBACK(int) vmmdevSetVisibleRegion(PPDMIVMMDEVCONNECTOR pInterface, uint32_t cRect, PRTRECT pRect)
464{
465 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
466 Console *pConsole = pDrv->pVMMDev->getParent();
467
468 /* Forward to Display, which calls corresponding framebuffers. */
469 pConsole->i_getDisplay()->i_handleSetVisibleRegion(cRect, pRect);
470
471 return VINF_SUCCESS;
472}
473
474/**
475 * @interface_method_impl{PDMIVMMDEVCONNECTOR,pfnUpdateMonitorPositions}
476 */
477static DECLCALLBACK(int) vmmdevUpdateMonitorPositions(PPDMIVMMDEVCONNECTOR pInterface, uint32_t cPositions, PCRTPOINT paPositions)
478{
479 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
480 Console *pConsole = pDrv->pVMMDev->getParent();
481
482 pConsole->i_getDisplay()->i_handleUpdateMonitorPositions(cPositions, paPositions);
483
484 return VINF_SUCCESS;
485}
486
487static DECLCALLBACK(int) vmmdevQueryVisibleRegion(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcRects, PRTRECT paRects)
488{
489 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
490 Console *pConsole = pDrv->pVMMDev->getParent();
491
492 /* Forward to Display, which calls corresponding framebuffers. */
493 pConsole->i_getDisplay()->i_handleQueryVisibleRegion(pcRects, paRects);
494
495 return VINF_SUCCESS;
496}
497
498/**
499 * Request the statistics interval
500 *
501 * @returns VBox status code.
502 * @param pInterface Pointer to this interface.
503 * @param pulInterval Pointer to interval in seconds
504 * @thread The emulation thread.
505 */
506static DECLCALLBACK(int) vmmdevQueryStatisticsInterval(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pulInterval)
507{
508 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
509 Console *pConsole = pDrv->pVMMDev->getParent();
510 ULONG val = 0;
511
512 if (!pulInterval)
513 return VERR_INVALID_POINTER;
514
515 /* store that information in IGuest */
516 Guest* guest = pConsole->i_getGuest();
517 AssertPtrReturn(guest, VERR_GENERAL_FAILURE);
518
519 guest->COMGETTER(StatisticsUpdateInterval)(&val);
520 *pulInterval = val;
521 return VINF_SUCCESS;
522}
523
524/**
525 * Query the current balloon size
526 *
527 * @returns VBox status code.
528 * @param pInterface Pointer to this interface.
529 * @param pcbBalloon Balloon size
530 * @thread The emulation thread.
531 */
532static DECLCALLBACK(int) vmmdevQueryBalloonSize(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcbBalloon)
533{
534 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
535 Console *pConsole = pDrv->pVMMDev->getParent();
536 ULONG val = 0;
537
538 if (!pcbBalloon)
539 return VERR_INVALID_POINTER;
540
541 /* store that information in IGuest */
542 Guest* guest = pConsole->i_getGuest();
543 AssertPtrReturn(guest, VERR_GENERAL_FAILURE);
544
545 guest->COMGETTER(MemoryBalloonSize)(&val);
546 *pcbBalloon = val;
547 return VINF_SUCCESS;
548}
549
550/**
551 * Query the current page fusion setting
552 *
553 * @returns VBox status code.
554 * @param pInterface Pointer to this interface.
555 * @param pfPageFusionEnabled Pointer to boolean
556 * @thread The emulation thread.
557 */
558static DECLCALLBACK(int) vmmdevIsPageFusionEnabled(PPDMIVMMDEVCONNECTOR pInterface, bool *pfPageFusionEnabled)
559{
560 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
561 Console *pConsole = pDrv->pVMMDev->getParent();
562
563 if (!pfPageFusionEnabled)
564 return VERR_INVALID_POINTER;
565
566 /* store that information in IGuest */
567 Guest* guest = pConsole->i_getGuest();
568 AssertPtrReturn(guest, VERR_GENERAL_FAILURE);
569
570 *pfPageFusionEnabled = !!guest->i_isPageFusionEnabled();
571 return VINF_SUCCESS;
572}
573
574/**
575 * Report new guest statistics
576 *
577 * @returns VBox status code.
578 * @param pInterface Pointer to this interface.
579 * @param pGuestStats Guest statistics
580 * @thread The emulation thread.
581 */
582static DECLCALLBACK(int) vmmdevReportStatistics(PPDMIVMMDEVCONNECTOR pInterface, VBoxGuestStatistics *pGuestStats)
583{
584 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, Connector);
585 Console *pConsole = pDrv->pVMMDev->getParent();
586
587 AssertPtrReturn(pGuestStats, VERR_INVALID_POINTER);
588
589 /* store that information in IGuest */
590 Guest* guest = pConsole->i_getGuest();
591 AssertPtrReturn(guest, VERR_GENERAL_FAILURE);
592
593 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_IDLE)
594 guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_CPUIDLE, pGuestStats->u32CpuLoad_Idle);
595
596 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_KERNEL)
597 guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_CPUKERNEL, pGuestStats->u32CpuLoad_Kernel);
598
599 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_CPU_LOAD_USER)
600 guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_CPUUSER, pGuestStats->u32CpuLoad_User);
601
602
603 /** @todo r=bird: Convert from 4KB to 1KB units?
604 * CollectorGuestHAL::i_getGuestMemLoad says it returns KB units to
605 * preCollect(). I might be wrong ofc, this is convoluted code... */
606 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_TOTAL)
607 guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_MEMTOTAL, pGuestStats->u32PhysMemTotal);
608
609 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_AVAIL)
610 guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_MEMFREE, pGuestStats->u32PhysMemAvail);
611
612 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PHYS_MEM_BALLOON)
613 guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_MEMBALLOON, pGuestStats->u32PhysMemBalloon);
614
615 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_MEM_SYSTEM_CACHE)
616 guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_MEMCACHE, pGuestStats->u32MemSystemCache);
617
618 if (pGuestStats->u32StatCaps & VBOX_GUEST_STAT_PAGE_FILE_SIZE)
619 guest->i_setStatistic(pGuestStats->u32CpuId, GUESTSTATTYPE_PAGETOTAL, pGuestStats->u32PageFileSize);
620
621 return VINF_SUCCESS;
622}
623
624#ifdef VBOX_WITH_HGCM
625
626/* HGCM connector interface */
627
628static DECLCALLBACK(int) iface_hgcmConnect(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd,
629 PHGCMSERVICELOCATION pServiceLocation,
630 uint32_t *pu32ClientID)
631{
632 Log9(("Enter\n"));
633
634 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, HGCMConnector);
635
636 if ( !pServiceLocation
637 || ( pServiceLocation->type != VMMDevHGCMLoc_LocalHost
638 && pServiceLocation->type != VMMDevHGCMLoc_LocalHost_Existing))
639 {
640 return VERR_INVALID_PARAMETER;
641 }
642
643 /* Check if service name is a string terminated by zero*/
644 size_t cchInfo = 0;
645 if (RTStrNLenEx(pServiceLocation->u.host.achName, sizeof(pServiceLocation->u.host.achName), &cchInfo) != VINF_SUCCESS)
646 {
647 return VERR_INVALID_PARAMETER;
648 }
649
650 if (!pDrv->pVMMDev || !pDrv->pVMMDev->hgcmIsActive())
651 return VERR_INVALID_STATE;
652 return HGCMGuestConnect(pDrv->pHGCMPort, pCmd, pServiceLocation->u.host.achName, pu32ClientID);
653}
654
655static DECLCALLBACK(int) iface_hgcmDisconnect(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t u32ClientID)
656{
657 Log9(("Enter\n"));
658
659 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, HGCMConnector);
660
661 if (!pDrv->pVMMDev || !pDrv->pVMMDev->hgcmIsActive())
662 return VERR_INVALID_STATE;
663
664 return HGCMGuestDisconnect(pDrv->pHGCMPort, pCmd, u32ClientID);
665}
666
667static DECLCALLBACK(int) iface_hgcmCall(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t u32ClientID,
668 uint32_t u32Function, uint32_t cParms, PVBOXHGCMSVCPARM paParms, uint64_t tsArrival)
669{
670 Log9(("Enter\n"));
671
672 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, HGCMConnector);
673
674 if (!pDrv->pVMMDev || !pDrv->pVMMDev->hgcmIsActive())
675 return VERR_INVALID_STATE;
676
677 return HGCMGuestCall(pDrv->pHGCMPort, pCmd, u32ClientID, u32Function, cParms, paParms, tsArrival);
678}
679
680static DECLCALLBACK(void) iface_hgcmCancelled(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t idClient)
681{
682 Log9(("Enter\n"));
683
684 PDRVMAINVMMDEV pDrv = RT_FROM_MEMBER(pInterface, DRVMAINVMMDEV, HGCMConnector);
685 if ( pDrv->pVMMDev
686 && pDrv->pVMMDev->hgcmIsActive())
687 return HGCMGuestCancelled(pDrv->pHGCMPort, pCmd, idClient);
688}
689
690/**
691 * Execute state save operation.
692 *
693 * @returns VBox status code.
694 * @param pDrvIns Driver instance of the driver which registered the data unit.
695 * @param pSSM SSM operation handle.
696 */
697/*static*/ DECLCALLBACK(int) VMMDev::hgcmSave(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)
698{
699 PDRVMAINVMMDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV);
700 Log9(("Enter\n"));
701
702 AssertReturn(pThis->pVMMDev, VERR_INTERNAL_ERROR_2);
703 Console::SafeVMPtrQuiet ptrVM(pThis->pVMMDev->mParent);
704 AssertReturn(ptrVM.isOk(), VERR_INTERNAL_ERROR_3);
705 return HGCMHostSaveState(pSSM, ptrVM.vtable());
706}
707
708
709/**
710 * Execute state load operation.
711 *
712 * @returns VBox status code.
713 * @param pDrvIns Driver instance of the driver which registered the data unit.
714 * @param pSSM SSM operation handle.
715 * @param uVersion Data layout version.
716 * @param uPass The data pass.
717 */
718/*static*/ DECLCALLBACK(int) VMMDev::hgcmLoad(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
719{
720 PDRVMAINVMMDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV);
721 LogFlowFunc(("Enter\n"));
722
723 if ( uVersion != HGCM_SAVED_STATE_VERSION
724 && uVersion != HGCM_SAVED_STATE_VERSION_V2)
725 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
726 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
727
728 AssertReturn(pThis->pVMMDev, VERR_INTERNAL_ERROR_2);
729 Console::SafeVMPtrQuiet ptrVM(pThis->pVMMDev->mParent);
730 AssertReturn(ptrVM.isOk(), VERR_INTERNAL_ERROR_3);
731 return HGCMHostLoadState(pSSM, ptrVM.vtable(), uVersion);
732}
733
734int VMMDev::hgcmLoadService(const char *pszServiceLibrary, const char *pszServiceName)
735{
736 if (!hgcmIsActive())
737 return VERR_INVALID_STATE;
738
739 /** @todo Construct all the services in the VMMDev::drvConstruct()!! */
740 Assert( (mpDrv && mpDrv->pHGCMPort)
741 || !strcmp(pszServiceLibrary, "VBoxHostChannel")
742 || !strcmp(pszServiceLibrary, "VBoxSharedClipboard")
743 || !strcmp(pszServiceLibrary, "VBoxDragAndDropSvc")
744 || !strcmp(pszServiceLibrary, "VBoxGuestPropSvc")
745 || !strcmp(pszServiceLibrary, "VBoxSharedCrOpenGL")
746 );
747 Console::SafeVMPtrQuiet ptrVM(mParent);
748 return HGCMHostLoad(pszServiceLibrary, pszServiceName, ptrVM.rawUVM(), ptrVM.vtable(), mpDrv ? mpDrv->pHGCMPort : NULL);
749}
750
751int VMMDev::hgcmHostCall(const char *pszServiceName, uint32_t u32Function,
752 uint32_t cParms, PVBOXHGCMSVCPARM paParms)
753{
754 if (!hgcmIsActive())
755 return VERR_INVALID_STATE;
756 return HGCMHostCall(pszServiceName, u32Function, cParms, paParms);
757}
758
759/**
760 * Used by Console::i_powerDown to shut down the services before the VM is destroyed.
761 */
762void VMMDev::hgcmShutdown(bool fUvmIsInvalid /*= false*/)
763{
764#ifdef VBOX_WITH_GUEST_PROPS
765 if (mpDrv && mpDrv->hHgcmSvcExtGstProps)
766 {
767 HGCMHostUnregisterServiceExtension(mpDrv->hHgcmSvcExtGstProps);
768 mpDrv->hHgcmSvcExtGstProps = NULL;
769 }
770#endif
771
772#ifdef VBOX_WITH_GUEST_CONTROL
773 if (mpDrv && mpDrv->hHgcmSvcExtGstCtrl)
774 {
775 HGCMHostUnregisterServiceExtension(mpDrv->hHgcmSvcExtGstCtrl);
776 mpDrv->hHgcmSvcExtGstCtrl = NULL;
777 }
778#endif
779
780 if (ASMAtomicCmpXchgBool(&m_fHGCMActive, false, true))
781 HGCMHostShutdown(fUvmIsInvalid);
782}
783
784#endif /* HGCM */
785
786
787/**
788 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
789 */
790DECLCALLBACK(void *) VMMDev::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
791{
792 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
793 PDRVMAINVMMDEV pDrv = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV);
794
795 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
796 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIVMMDEVCONNECTOR, &pDrv->Connector);
797#ifdef VBOX_WITH_HGCM
798 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHGCMCONNECTOR, &pDrv->HGCMConnector);
799#endif
800 return NULL;
801}
802
803/**
804 * @interface_method_impl{PDMDRVREG,pfnSuspend}
805 */
806/*static*/ DECLCALLBACK(void) VMMDev::drvSuspend(PPDMDRVINS pDrvIns)
807{
808 RT_NOREF(pDrvIns);
809#ifdef VBOX_WITH_HGCM
810 HGCMBroadcastEvent(HGCMNOTIFYEVENT_SUSPEND);
811#endif
812}
813
814/**
815 * @interface_method_impl{PDMDRVREG,pfnResume}
816 */
817/*static*/ DECLCALLBACK(void) VMMDev::drvResume(PPDMDRVINS pDrvIns)
818{
819 RT_NOREF(pDrvIns);
820#ifdef VBOX_WITH_HGCM
821 HGCMBroadcastEvent(HGCMNOTIFYEVENT_RESUME);
822#endif
823}
824
825/**
826 * @interface_method_impl{PDMDRVREG,pfnPowerOff}
827 */
828/*static*/ DECLCALLBACK(void) VMMDev::drvPowerOff(PPDMDRVINS pDrvIns)
829{
830 RT_NOREF(pDrvIns);
831#ifdef VBOX_WITH_HGCM
832 HGCMBroadcastEvent(HGCMNOTIFYEVENT_POWER_ON);
833#endif
834}
835
836/**
837 * @interface_method_impl{PDMDRVREG,pfnPowerOn}
838 */
839/*static*/ DECLCALLBACK(void) VMMDev::drvPowerOn(PPDMDRVINS pDrvIns)
840{
841 RT_NOREF(pDrvIns);
842#ifdef VBOX_WITH_HGCM
843 HGCMBroadcastEvent(HGCMNOTIFYEVENT_POWER_ON);
844#endif
845}
846
847/**
848 * @interface_method_impl{PDMDRVREG,pfnReset}
849 */
850DECLCALLBACK(void) VMMDev::drvReset(PPDMDRVINS pDrvIns)
851{
852 RT_NOREF(pDrvIns);
853 LogFlow(("VMMDev::drvReset: iInstance=%d\n", pDrvIns->iInstance));
854#ifdef VBOX_WITH_HGCM
855 HGCMHostReset(false /*fForShutdown*/);
856#endif
857}
858
859/**
860 * @interface_method_impl{PDMDRVREG,pfnDestruct}
861 */
862DECLCALLBACK(void) VMMDev::drvDestruct(PPDMDRVINS pDrvIns)
863{
864 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
865 PDRVMAINVMMDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV);
866 LogFlow(("VMMDev::drvDestruct: iInstance=%d\n", pDrvIns->iInstance));
867
868#ifdef VBOX_WITH_GUEST_PROPS
869 if (pThis->hHgcmSvcExtGstProps)
870 {
871 HGCMHostUnregisterServiceExtension(pThis->hHgcmSvcExtGstProps);
872 pThis->hHgcmSvcExtGstProps = NULL;
873 }
874#endif
875
876#ifdef VBOX_WITH_GUEST_CONTROL
877 if (pThis->hHgcmSvcExtGstCtrl)
878 {
879 HGCMHostUnregisterServiceExtension(pThis->hHgcmSvcExtGstCtrl);
880 pThis->hHgcmSvcExtGstCtrl = NULL;
881 }
882#endif
883
884 if (pThis->pVMMDev)
885 {
886#ifdef VBOX_WITH_HGCM
887 /* When VM construction goes wrong, we prefer shutting down HGCM here
888 while pUVM is still valid, rather than in ~VMMDev. */
889 if (ASMAtomicCmpXchgBool(&pThis->pVMMDev->m_fHGCMActive, false, true))
890 HGCMHostShutdown();
891#endif
892 pThis->pVMMDev->mpDrv = NULL;
893 }
894}
895
896#ifdef VBOX_WITH_GUEST_PROPS
897
898/**
899 * Set an array of guest properties
900 */
901void VMMDev::i_guestPropSetMultiple(void *names, void *values, void *timestamps, void *flags)
902{
903 VBOXHGCMSVCPARM parms[4];
904
905 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
906 parms[0].u.pointer.addr = names;
907 parms[0].u.pointer.size = 0; /* We don't actually care. */
908 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
909 parms[1].u.pointer.addr = values;
910 parms[1].u.pointer.size = 0; /* We don't actually care. */
911 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
912 parms[2].u.pointer.addr = timestamps;
913 parms[2].u.pointer.size = 0; /* We don't actually care. */
914 parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
915 parms[3].u.pointer.addr = flags;
916 parms[3].u.pointer.size = 0; /* We don't actually care. */
917
918 hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROPS, 4, &parms[0]);
919}
920
921/**
922 * Set a single guest property
923 */
924void VMMDev::i_guestPropSet(const char *pszName, const char *pszValue, const char *pszFlags)
925{
926 VBOXHGCMSVCPARM parms[4];
927
928 AssertPtrReturnVoid(pszName);
929 AssertPtrReturnVoid(pszValue);
930 AssertPtrReturnVoid(pszFlags);
931 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
932 parms[0].u.pointer.addr = (void *)pszName;
933 parms[0].u.pointer.size = (uint32_t)strlen(pszName) + 1;
934 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
935 parms[1].u.pointer.addr = (void *)pszValue;
936 parms[1].u.pointer.size = (uint32_t)strlen(pszValue) + 1;
937 parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
938 parms[2].u.pointer.addr = (void *)pszFlags;
939 parms[2].u.pointer.size = (uint32_t)strlen(pszFlags) + 1;
940 hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROP, 3, &parms[0]);
941}
942
943/**
944 * Set the global flags value by calling the service
945 * @returns the status returned by the call to the service
946 *
947 * @param pTable the service instance handle
948 * @param eFlags the flags to set
949 */
950int VMMDev::i_guestPropSetGlobalPropertyFlags(uint32_t fFlags)
951{
952 VBOXHGCMSVCPARM parm;
953 HGCMSvcSetU32(&parm, fFlags);
954 int vrc = hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_GLOBAL_FLAGS, 1, &parm);
955 if (RT_FAILURE(vrc))
956 {
957 char szFlags[GUEST_PROP_MAX_FLAGS_LEN];
958 if (RT_FAILURE(GuestPropWriteFlags(fFlags, szFlags)))
959 Log(("Failed to set the global flags.\n"));
960 else
961 Log(("Failed to set the global flags \"%s\".\n", szFlags));
962 }
963 return vrc;
964}
965
966
967/**
968 * Set up the Guest Property service, populate it with properties read from
969 * the machine XML and set a couple of initial properties.
970 */
971int VMMDev::i_guestPropLoadAndConfigure()
972{
973 Assert(mpDrv);
974 ComObjPtr<Console> ptrConsole = this->mParent;
975 AssertReturn(ptrConsole.isNotNull(), VERR_INVALID_POINTER);
976
977 /*
978 * Load the service
979 */
980 int vrc = hgcmLoadService("VBoxGuestPropSvc", "VBoxGuestPropSvc");
981 if (RT_FAILURE(vrc))
982 {
983 LogRel(("VBoxGuestPropSvc is not available. vrc = %Rrc\n", vrc));
984 return VINF_SUCCESS; /* That is not a fatal failure. */
985 }
986
987 /*
988 * Pull over the properties from the server.
989 */
990 SafeArray<BSTR> namesOut;
991 SafeArray<BSTR> valuesOut;
992 SafeArray<LONG64> timestampsOut;
993 SafeArray<BSTR> flagsOut;
994 HRESULT hrc = ptrConsole->i_pullGuestProperties(ComSafeArrayAsOutParam(namesOut),
995 ComSafeArrayAsOutParam(valuesOut),
996 ComSafeArrayAsOutParam(timestampsOut),
997 ComSafeArrayAsOutParam(flagsOut));
998 AssertLogRelMsgReturn(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc), VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR);
999 size_t const cProps = namesOut.size();
1000 size_t const cAlloc = cProps + 1;
1001 AssertLogRelReturn(valuesOut.size() == cProps, VERR_INTERNAL_ERROR_2);
1002 AssertLogRelReturn(timestampsOut.size() == cProps, VERR_INTERNAL_ERROR_3);
1003 AssertLogRelReturn(flagsOut.size() == cProps, VERR_INTERNAL_ERROR_4);
1004
1005 char szEmpty[] = "";
1006 char **papszNames = (char **)RTMemTmpAllocZ(sizeof(char *) * cAlloc);
1007 char **papszValues = (char **)RTMemTmpAllocZ(sizeof(char *) * cAlloc);
1008 LONG64 *pai64Timestamps = (LONG64 *)RTMemTmpAllocZ(sizeof(LONG64) * cAlloc);
1009 char **papszFlags = (char **)RTMemTmpAllocZ(sizeof(char *) * cAlloc);
1010 if (papszNames && papszValues && pai64Timestamps && papszFlags)
1011 {
1012 for (unsigned i = 0; RT_SUCCESS(vrc) && i < cProps; ++i)
1013 {
1014 AssertPtrBreakStmt(namesOut[i], vrc = VERR_INVALID_PARAMETER);
1015 vrc = RTUtf16ToUtf8(namesOut[i], &papszNames[i]);
1016 if (RT_FAILURE(vrc))
1017 break;
1018 if (valuesOut[i])
1019 vrc = RTUtf16ToUtf8(valuesOut[i], &papszValues[i]);
1020 else
1021 papszValues[i] = szEmpty;
1022 if (RT_FAILURE(vrc))
1023 break;
1024 pai64Timestamps[i] = timestampsOut[i];
1025 if (flagsOut[i])
1026 vrc = RTUtf16ToUtf8(flagsOut[i], &papszFlags[i]);
1027 else
1028 papszFlags[i] = szEmpty;
1029 }
1030 if (RT_SUCCESS(vrc))
1031 i_guestPropSetMultiple((void *)papszNames, (void *)papszValues, (void *)pai64Timestamps, (void *)papszFlags);
1032 for (unsigned i = 0; i < cProps; ++i)
1033 {
1034 RTStrFree(papszNames[i]);
1035 if (valuesOut[i])
1036 RTStrFree(papszValues[i]);
1037 if (flagsOut[i])
1038 RTStrFree(papszFlags[i]);
1039 }
1040 }
1041 else
1042 vrc = VERR_NO_MEMORY;
1043 RTMemTmpFree(papszNames);
1044 RTMemTmpFree(papszValues);
1045 RTMemTmpFree(pai64Timestamps);
1046 RTMemTmpFree(papszFlags);
1047 AssertRCReturn(vrc, vrc);
1048
1049 /*
1050 * Register the host notification callback
1051 */
1052 HGCMHostRegisterServiceExtension(&mpDrv->hHgcmSvcExtGstProps, "VBoxGuestPropSvc", Console::i_doGuestPropNotification, ptrConsole.m_p);
1053
1054# ifdef VBOX_WITH_GUEST_PROPS_RDONLY_GUEST
1055 vrc = i_guestPropSetGlobalPropertyFlags(GUEST_PROP_F_RDONLYGUEST);
1056 AssertRCReturn(vrc, vrc);
1057# endif
1058
1059 Log(("Set VBoxGuestPropSvc property store\n"));
1060 return VINF_SUCCESS;
1061}
1062
1063#endif /* VBOX_WITH_GUEST_PROPS */
1064
1065/**
1066 * @interface_method_impl{PDMDRVREG,pfnConstruct}
1067 */
1068DECLCALLBACK(int) VMMDev::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
1069{
1070 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
1071 RT_NOREF(fFlags, pCfg);
1072 PDRVMAINVMMDEV pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINVMMDEV);
1073 LogFlow(("Keyboard::drvConstruct: iInstance=%d\n", pDrvIns->iInstance));
1074
1075 /*
1076 * Validate configuration.
1077 */
1078 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, "", "");
1079 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
1080 ("Configuration error: Not possible to attach anything to this driver!\n"),
1081 VERR_PDM_DRVINS_NO_ATTACH);
1082
1083 /*
1084 * IBase.
1085 */
1086 pDrvIns->IBase.pfnQueryInterface = VMMDev::drvQueryInterface;
1087
1088 pThis->Connector.pfnUpdateGuestStatus = vmmdevUpdateGuestStatus;
1089 pThis->Connector.pfnUpdateGuestUserState = vmmdevUpdateGuestUserState;
1090 pThis->Connector.pfnUpdateGuestInfo = vmmdevUpdateGuestInfo;
1091 pThis->Connector.pfnUpdateGuestInfo2 = vmmdevUpdateGuestInfo2;
1092 pThis->Connector.pfnUpdateGuestCapabilities = vmmdevUpdateGuestCapabilities;
1093 pThis->Connector.pfnUpdateMouseCapabilities = vmmdevUpdateMouseCapabilities;
1094 pThis->Connector.pfnUpdatePointerShape = vmmdevUpdatePointerShape;
1095 pThis->Connector.pfnVideoAccelEnable = iface_VideoAccelEnable;
1096 pThis->Connector.pfnVideoAccelFlush = iface_VideoAccelFlush;
1097 pThis->Connector.pfnVideoModeSupported = vmmdevVideoModeSupported;
1098 pThis->Connector.pfnGetHeightReduction = vmmdevGetHeightReduction;
1099 pThis->Connector.pfnSetCredentialsJudgementResult = vmmdevSetCredentialsJudgementResult;
1100 pThis->Connector.pfnSetVisibleRegion = vmmdevSetVisibleRegion;
1101 pThis->Connector.pfnUpdateMonitorPositions = vmmdevUpdateMonitorPositions;
1102 pThis->Connector.pfnQueryVisibleRegion = vmmdevQueryVisibleRegion;
1103 pThis->Connector.pfnReportStatistics = vmmdevReportStatistics;
1104 pThis->Connector.pfnQueryStatisticsInterval = vmmdevQueryStatisticsInterval;
1105 pThis->Connector.pfnQueryBalloonSize = vmmdevQueryBalloonSize;
1106 pThis->Connector.pfnIsPageFusionEnabled = vmmdevIsPageFusionEnabled;
1107
1108#ifdef VBOX_WITH_HGCM
1109 pThis->HGCMConnector.pfnConnect = iface_hgcmConnect;
1110 pThis->HGCMConnector.pfnDisconnect = iface_hgcmDisconnect;
1111 pThis->HGCMConnector.pfnCall = iface_hgcmCall;
1112 pThis->HGCMConnector.pfnCancelled = iface_hgcmCancelled;
1113#endif
1114
1115 /*
1116 * Get the IVMMDevPort interface of the above driver/device.
1117 */
1118 pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIVMMDEVPORT);
1119 AssertMsgReturn(pThis->pUpPort, ("Configuration error: No VMMDev port interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
1120
1121#ifdef VBOX_WITH_HGCM
1122 pThis->pHGCMPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHGCMPORT);
1123 AssertMsgReturn(pThis->pHGCMPort, ("Configuration error: No HGCM port interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
1124#endif
1125
1126 /*
1127 * Get the Console object pointer and update the mpDrv member.
1128 */
1129 com::Guid uuid(VMMDEV_OID);
1130 pThis->pVMMDev = (VMMDev *)PDMDrvHlpQueryGenericUserObject(pDrvIns, uuid.raw());
1131 if (!pThis->pVMMDev)
1132 {
1133 AssertMsgFailed(("Configuration error: No/bad VMMDev object!\n"));
1134 return VERR_NOT_FOUND;
1135 }
1136 pThis->pVMMDev->mpDrv = pThis;
1137
1138 int vrc = VINF_SUCCESS;
1139#ifdef VBOX_WITH_HGCM
1140 /*
1141 * Load & configure the shared folders service.
1142 */
1143 vrc = pThis->pVMMDev->hgcmLoadService(VBOXSHAREDFOLDERS_DLL, "VBoxSharedFolders");
1144 pThis->pVMMDev->fSharedFolderActive = RT_SUCCESS(vrc);
1145 if (RT_SUCCESS(vrc))
1146 {
1147 PPDMLED pLed;
1148 PPDMILEDPORTS pLedPort;
1149
1150 LogRel(("Shared Folders service loaded\n"));
1151 pLedPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS);
1152 AssertMsgReturn(pLedPort, ("Configuration error: No LED port interface above!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
1153 vrc = pLedPort->pfnQueryStatusLed(pLedPort, 0, &pLed);
1154 if (RT_SUCCESS(vrc) && pLed)
1155 {
1156 VBOXHGCMSVCPARM parm;
1157
1158 parm.type = VBOX_HGCM_SVC_PARM_PTR;
1159 parm.u.pointer.addr = pLed;
1160 parm.u.pointer.size = sizeof(*pLed);
1161
1162 vrc = HGCMHostCall("VBoxSharedFolders", SHFL_FN_SET_STATUS_LED, 1, &parm);
1163 }
1164 else
1165 AssertMsgFailed(("pfnQueryStatusLed failed with %Rrc (pLed=%x)\n", vrc, pLed));
1166 }
1167 else
1168 LogRel(("Failed to load Shared Folders service %Rrc\n", vrc));
1169
1170
1171 /*
1172 * Load and configure the guest control service.
1173 */
1174# ifdef VBOX_WITH_GUEST_CONTROL
1175 vrc = pThis->pVMMDev->hgcmLoadService("VBoxGuestControlSvc", "VBoxGuestControlSvc");
1176 if (RT_SUCCESS(vrc))
1177 {
1178 vrc = HGCMHostRegisterServiceExtension(&pThis->hHgcmSvcExtGstCtrl, "VBoxGuestControlSvc",
1179 &Guest::i_notifyCtrlDispatcher,
1180 pThis->pVMMDev->mParent->i_getGuest());
1181 if (RT_SUCCESS(vrc))
1182 LogRel(("Guest Control service loaded\n"));
1183 else
1184 LogRel(("Warning: Cannot register VBoxGuestControlSvc extension! vrc=%Rrc\n", vrc));
1185 }
1186 else
1187 LogRel(("Warning!: Failed to load the Guest Control Service! %Rrc\n", vrc));
1188# endif /* VBOX_WITH_GUEST_CONTROL */
1189
1190
1191 /*
1192 * Load and configure the guest properties service.
1193 */
1194# ifdef VBOX_WITH_GUEST_PROPS
1195 vrc = pThis->pVMMDev->i_guestPropLoadAndConfigure();
1196 AssertLogRelRCReturn(vrc, vrc);
1197# endif
1198
1199
1200 /*
1201 * The HGCM saved state.
1202 */
1203 vrc = PDMDrvHlpSSMRegisterEx(pDrvIns, HGCM_SAVED_STATE_VERSION, 4096 /* bad guess */,
1204 NULL, NULL, NULL,
1205 NULL, VMMDev::hgcmSave, NULL,
1206 NULL, VMMDev::hgcmLoad, NULL);
1207 if (RT_FAILURE(vrc))
1208 return vrc;
1209
1210#endif /* VBOX_WITH_HGCM */
1211
1212 return VINF_SUCCESS;
1213}
1214
1215
1216/**
1217 * VMMDevice driver registration record.
1218 */
1219const PDMDRVREG VMMDev::DrvReg =
1220{
1221 /* u32Version */
1222 PDM_DRVREG_VERSION,
1223 /* szName */
1224 "HGCM",
1225 /* szRCMod */
1226 "",
1227 /* szR0Mod */
1228 "",
1229 /* pszDescription */
1230 "Main VMMDev driver (Main as in the API).",
1231 /* fFlags */
1232 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
1233 /* fClass. */
1234 PDM_DRVREG_CLASS_VMMDEV,
1235 /* cMaxInstances */
1236 ~0U,
1237 /* cbInstance */
1238 sizeof(DRVMAINVMMDEV),
1239 /* pfnConstruct */
1240 VMMDev::drvConstruct,
1241 /* pfnDestruct */
1242 VMMDev::drvDestruct,
1243 /* pfnRelocate */
1244 NULL,
1245 /* pfnIOCtl */
1246 NULL,
1247 /* pfnPowerOn */
1248 VMMDev::drvPowerOn,
1249 /* pfnReset */
1250 VMMDev::drvReset,
1251 /* pfnSuspend */
1252 VMMDev::drvSuspend,
1253 /* pfnResume */
1254 VMMDev::drvResume,
1255 /* pfnAttach */
1256 NULL,
1257 /* pfnDetach */
1258 NULL,
1259 /* pfnPowerOff */
1260 VMMDev::drvPowerOff,
1261 /* pfnSoftReset */
1262 NULL,
1263 /* u32EndVersion */
1264 PDM_DRVREG_VERSION
1265};
1266/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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