VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibMisc.cpp@ 27080

Last change on this file since 27080 was 27080, checked in by vboxsync, 15 years ago

VBoxGuestR3LibMisc.cpp,VBoxGuestLib.h: minor adjustments.

  • Property svn:eol-style set to native
  • Property svn:keyword set to Id
  • Property svn:keywords set to Id
File size: 15.8 KB
Line 
1/* $Id: VBoxGuestR3LibMisc.cpp 27080 2010-03-05 12:49:22Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Misc.
4 */
5
6/*
7 * Copyright (C) 2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <iprt/mem.h>
36#include <iprt/string.h>
37#include <VBox/log.h>
38#include <VBox/version.h>
39#include "VBGLR3Internal.h"
40
41/** @todo Split this file up so we can drop most of the VBOX_VBGLR3_XFREE86
42 * #ifdef'ing. */
43
44/**
45 * Wait for the host to signal one or more events and return which.
46 *
47 * The events will only be delivered by the host if they have been enabled
48 * previously using @a VbglR3CtlFilterMask. If one or several of the events
49 * have already been signalled but not yet waited for, this function will return
50 * immediately and return those events.
51 *
52 * @returns IPRT status code.
53 *
54 * @param fMask The events we want to wait for, or-ed together.
55 * @param cMillies How long to wait before giving up and returning
56 * (VERR_TIMEOUT). Use RT_INDEFINITE_WAIT to wait until we
57 * are interrupted or one of the events is signalled.
58 * @param pfEvents Where to store the events signalled. Optional.
59 */
60VBGLR3DECL(int) VbglR3WaitEvent(uint32_t fMask, uint32_t cMillies, uint32_t *pfEvents)
61{
62#ifndef VBOX_VBGLR3_XFREE86
63 LogFlow(("VbglR3WaitEvent: fMask=0x%x, cMillies=%u, pfEvents=%p\n",
64 fMask, cMillies, pfEvents));
65 AssertReturn((fMask & ~VMMDEV_EVENT_VALID_EVENT_MASK) == 0, VERR_INVALID_PARAMETER);
66 AssertPtrNullReturn(pfEvents, VERR_INVALID_POINTER);
67#endif
68
69 VBoxGuestWaitEventInfo waitEvent;
70 waitEvent.u32TimeoutIn = cMillies;
71 waitEvent.u32EventMaskIn = fMask;
72 waitEvent.u32Result = VBOXGUEST_WAITEVENT_ERROR;
73 waitEvent.u32EventFlagsOut = 0;
74 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_WAITEVENT, &waitEvent, sizeof(waitEvent));
75 if (RT_SUCCESS(rc))
76 {
77#if !defined(VBOX_VBGLR3_XFREE86) && !defined(RT_OS_WINDOWS)
78 AssertMsg(waitEvent.u32Result == VBOXGUEST_WAITEVENT_OK, ("%d rc=%Rrc\n", waitEvent.u32Result, rc));
79#endif
80 if (pfEvents)
81 *pfEvents = waitEvent.u32EventFlagsOut;
82 }
83
84#ifndef VBOX_VBGLR3_XFREE86
85 LogFlow(("VbglR3WaitEvent: rc=%Rrc, u32EventFlagsOut=0x%x. u32Result=%d\n",
86 rc, waitEvent.u32EventFlagsOut, waitEvent.u32Result));
87#endif
88 return rc;
89}
90
91
92/**
93 * Cause any pending WaitEvent calls (VBOXGUEST_IOCTL_WAITEVENT) to return
94 * with a VERR_INTERRUPTED status.
95 *
96 * Can be used in combination with a termination flag variable for interrupting
97 * event loops. Avoiding race conditions is the responsibility of the caller.
98 *
99 * @returns IPRT status code.
100 */
101VBGLR3DECL(int) VbglR3InterruptEventWaits(void)
102{
103 return vbglR3DoIOCtl(VBOXGUEST_IOCTL_CANCEL_ALL_WAITEVENTS, 0, 0);
104}
105
106
107/**
108 * Write to the backdoor logger from ring 3 guest code.
109 *
110 * @returns IPRT status code.
111 *
112 * @param pch The string to log. Does not need to be terminated.
113 * @param cb The number of byte to log.
114 * @todo cb -> cch.
115 *
116 * @remarks This currently does not accept more than 255 bytes of data at
117 * one time. It should probably be rewritten to use pass a pointer
118 * in the IOCtl.
119 */
120VBGLR3DECL(int) VbglR3WriteLog(const char *pch, size_t cb)
121{
122 /*
123 * Quietly skip NULL strings.
124 * (Happens in the RTLogBackdoorPrintf case.)
125 */
126 if (!cb)
127 return VINF_SUCCESS;
128 if (!VALID_PTR(pch))
129 return VERR_INVALID_POINTER;
130
131#ifdef RT_OS_WINDOWS
132 /*
133 * Duplicate the string as it may be read only (a C string).
134 */
135 void *pvTmp = RTMemDup(pch, cb);
136 if (!pvTmp)
137 return VERR_NO_MEMORY;
138 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_LOG(cb), pvTmp, cb);
139 RTMemFree(pvTmp);
140 return rc;
141
142#elif 0 /** @todo Several OSes could take this route (solaris and freebsd for instance). */
143 /*
144 * Handle the entire request in one go.
145 */
146 return vbglR3DoIOCtl(VBOXGUEST_IOCTL_LOG(cb), pvTmp, cb);
147
148#else
149 /*
150 * *BSD does not accept more than 4KB per ioctl request, while
151 * Linux can't express sizes above 8KB, so, split it up into 2KB chunks.
152 */
153# define STEP 2048
154 int rc = VINF_SUCCESS;
155 for (size_t off = 0; off < cb && RT_SUCCESS(rc); off += STEP)
156 {
157 size_t cbStep = RT_MIN(cb - off, STEP);
158 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_LOG(cbStep), (char *)pch + off, cbStep);
159 }
160# undef STEP
161 return rc;
162#endif
163}
164
165
166/**
167 * Change the IRQ filter mask.
168 *
169 * @returns IPRT status code.
170 * @param fOr The OR mask.
171 * @param fNo The NOT mask.
172 */
173VBGLR3DECL(int) VbglR3CtlFilterMask(uint32_t fOr, uint32_t fNot)
174{
175 VBoxGuestFilterMaskInfo Info;
176 Info.u32OrMask = fOr;
177 Info.u32NotMask = fNot;
178 return vbglR3DoIOCtl(VBOXGUEST_IOCTL_CTL_FILTER_MASK, &Info, sizeof(Info));
179}
180
181
182/**
183 * Report a change in the capabilities that we support to the host.
184 *
185 * @returns IPRT status code.
186 * @param fOr Capabilities which have been added.
187 * @param fNot Capabilities which have been removed.
188 *
189 * @todo Move to a different file.
190 */
191VBGLR3DECL(int) VbglR3SetGuestCaps(uint32_t fOr, uint32_t fNot)
192{
193 VMMDevReqGuestCapabilities2 Req;
194
195 vmmdevInitRequest(&Req.header, VMMDevReq_SetGuestCapabilities);
196 Req.u32OrMask = fOr;
197 Req.u32NotMask = fNot;
198 int rc = vbglR3GRPerform(&Req.header);
199#if defined(DEBUG) && !defined(VBOX_VBGLR3_XFREE86)
200 if (RT_SUCCESS(rc))
201 LogRel(("Successfully changed guest capabilities: or mask 0x%x, not mask 0x%x.\n", fOr, fNot));
202 else
203 LogRel(("Failed to change guest capabilities: or mask 0x%x, not mask 0x%x. rc=%Rrc.\n", fOr, fNot, rc));
204#endif
205 return rc;
206}
207
208#ifndef VBOX_VBGLR3_XFREE86
209
210/**
211 * Query the current statistics update interval.
212 *
213 * @returns IPRT status code.
214 * @param pcMsInterval Update interval in ms (out).
215 */
216VBGLR3DECL(int) VbglR3StatQueryInterval(PRTMSINTERVAL pcMsInterval)
217{
218 VMMDevGetStatisticsChangeRequest Req;
219
220 vmmdevInitRequest(&Req.header, VMMDevReq_GetStatisticsChangeRequest);
221 Req.eventAck = VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST;
222 Req.u32StatInterval = 1;
223 int rc = vbglR3GRPerform(&Req.header);
224 if (RT_SUCCESS(rc))
225 {
226 *pcMsInterval = Req.u32StatInterval * 1000;
227 if (*pcMsInterval / 1000 != Req.u32StatInterval)
228 *pcMsInterval = ~(RTMSINTERVAL)0;
229 }
230 return rc;
231}
232
233
234/**
235 * Report guest statistics.
236 *
237 * @returns IPRT status code.
238 * @param pReq Request packet with statistics.
239 */
240VBGLR3DECL(int) VbglR3StatReport(VMMDevReportGuestStats *pReq)
241{
242 vmmdevInitRequest(&pReq->header, VMMDevReq_ReportGuestStats);
243 return vbglR3GRPerform(&pReq->header);
244}
245
246
247/**
248 * Refresh the memory balloon after a change.
249 *
250 * @returns IPRT status code.
251 * @param pcChunks The size of the balloon in chunks of 1MB (out).
252 * @param pfHandleInR3 Allocating of memory in R3 required (out).
253 */
254VBGLR3DECL(int) VbglR3MemBalloonRefresh(uint32_t *pcChunks, bool *pfHandleInR3)
255{
256 VBoxGuestCheckBalloonInfo Info;
257 int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_CHECK_BALLOON, &Info, sizeof(Info));
258 if (RT_SUCCESS(rc))
259 {
260 *pcChunks = Info.cBalloonChunks;
261 Assert(Info.fHandleInR3 == false || Info.fHandleInR3 == true || RT_FAILURE(rc));
262 *pfHandleInR3 = Info.fHandleInR3 != false;
263 }
264 return rc;
265}
266
267
268/**
269 * Change the memory by granting/reclaiming memory to/from R0.
270 *
271 * @returns IPRT status code.
272 * @param pv Memory chunk (1MB).
273 * @param fInflate true = inflate balloon (grant memory).
274 * false = deflate balloon (reclaim memory).
275 */
276VBGLR3DECL(int) VbglR3MemBalloonChange(void *pv, bool fInflate)
277{
278 VBoxGuestChangeBalloonInfo Info;
279 Info.u64ChunkAddr = (uint64_t)((uintptr_t)pv);
280 Info.fInflate = fInflate;
281 return vbglR3DoIOCtl(VBOXGUEST_IOCTL_CHANGE_BALLOON, &Info, sizeof(Info));
282}
283
284
285/**
286 * Fallback for vbglR3GetAdditionsVersion.
287 */
288static int vbglR3GetAdditionsCompileTimeVersion(char **ppszVer, char **ppszRev)
289{
290 if (ppszVer)
291 {
292 *ppszVer = RTStrDup(VBOX_VERSION_STRING);
293 if (!*ppszVer)
294 return VERR_NO_STR_MEMORY;
295 }
296
297 if (ppszRev)
298 {
299 char szRev[64];
300 RTStrPrintf(szRev, sizeof(szRev), "%d", VBOX_SVN_REV);
301 *ppszRev = RTStrDup(szRev);
302 if (!*ppszRev)
303 {
304 if (ppszVer)
305 {
306 RTStrFree(*ppszVer);
307 *ppszVer = NULL;
308 }
309 return VERR_NO_STR_MEMORY;
310 }
311 }
312
313 return VINF_SUCCESS;
314}
315
316#ifdef RT_OS_WINDOWS
317/**
318 * Looks up the storage path handle (registry).
319 *
320 * @returns IPRT status value
321 * @param hKey Receives pointer of allocated version string. NULL is
322 * accepted. The returned pointer must be closed by
323 * vbglR3CloseAdditionsWinStoragePath().
324 */
325static int vbglR3GetAdditionsWinStoragePath(PHKEY phKey)
326{
327 /*
328 * Try get the *installed* version first.
329 */
330 LONG r;
331
332 /* Check the new path first. */
333 r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Sun\\VirtualBox Guest Additions", 0, KEY_READ, phKey);
334# ifdef RT_ARCH_AMD64
335 if (r != ERROR_SUCCESS)
336 {
337 /* Check Wow6432Node (for new entries). */
338 r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432Node\\Sun\\VirtualBox Guest Additions", 0, KEY_READ, phKey);
339 }
340# endif
341
342 /* Still no luck? Then try the old xVM paths ... */
343 if (r != ERROR_SUCCESS)
344 {
345 r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Sun\\xVM VirtualBox Guest Additions", 0, KEY_READ, phKey);
346# ifdef RT_ARCH_AMD64
347 if (r != ERROR_SUCCESS)
348 {
349 /* Check Wow6432Node (for new entries). */
350 r = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432Node\\Sun\\xVM VirtualBox Guest Additions", 0, KEY_READ, phKey);
351 }
352# endif
353 }
354 return RTErrConvertFromWin32(r);
355}
356
357
358/**
359 * Closes the storage path handle (registry).
360 *
361 * @returns IPRT status value
362 * @param hKey Handle to close, retrieved by
363 * vbglR3GetAdditionsWinStoragePath().
364 */
365static int vbglR3CloseAdditionsWinStoragePath(HKEY hKey)
366{
367 return RTErrConvertFromWin32(RegCloseKey(hKey));
368}
369
370#endif /* RT_OS_WINDOWS */
371
372/**
373 * Retrieves the installed Guest Additions version and/or revision.
374 *
375 * @returns IPRT status value
376 * @param ppszVer Receives pointer of allocated version string. NULL is
377 * accepted. The returned pointer must be freed using
378 * RTStrFree().
379 * @param ppszRev Receives pointer of allocated revision string. NULL is
380 * accepted. The returned pointer must be freed using
381 * RTStrFree().
382 */
383VBGLR3DECL(int) VbglR3GetAdditionsVersion(char **ppszVer, char **ppszRev)
384{
385#ifdef RT_OS_WINDOWS
386 HKEY hKey;
387 int rc = vbglR3GetAdditionsWinStoragePath(&hKey);
388 if (RT_SUCCESS(rc))
389 {
390 /* Version. */
391 LONG l;
392 DWORD dwType;
393 DWORD dwSize = 32;
394 char *pszTmp;
395 if (ppszVer)
396 {
397 pszTmp = (char*)RTMemAlloc(dwSize);
398 if (pszTmp)
399 {
400 l = RegQueryValueEx(hKey, "Version", NULL, &dwType, (BYTE*)(LPCTSTR)pszTmp, &dwSize);
401 if (l == ERROR_SUCCESS)
402 {
403 if (dwType == REG_SZ)
404 rc = RTStrDupEx(ppszVer, pszTmp);
405 else
406 rc = VERR_INVALID_PARAMETER;
407 }
408 else
409 {
410 rc = RTErrConvertFromWin32(l);
411 }
412 RTMemFree(pszTmp);
413 }
414 else
415 rc = VERR_NO_MEMORY;
416 }
417 /* Revision. */
418 if (ppszRev)
419 {
420 dwSize = 32; /* Reset */
421 pszTmp = (char*)RTMemAlloc(dwSize);
422 if (pszTmp)
423 {
424 l = RegQueryValueEx(hKey, "Revision", NULL, &dwType, (BYTE*)(LPCTSTR)pszTmp, &dwSize);
425 if (l == ERROR_SUCCESS)
426 {
427 if (dwType == REG_SZ)
428 rc = RTStrDupEx(ppszRev, pszTmp);
429 else
430 rc = VERR_INVALID_PARAMETER;
431 }
432 else
433 {
434 rc = RTErrConvertFromWin32(l);
435 }
436 RTMemFree(pszTmp);
437 }
438 else
439 rc = VERR_NO_MEMORY;
440
441 if (RT_FAILURE(rc) && ppszVer)
442 {
443 RTStrFree(*ppszVer);
444 *ppszVer = NULL;
445 }
446 }
447 rc = vbglR3CloseAdditionsWinStoragePath(hKey);
448 }
449 else
450 {
451 /*
452 * No registry entries found, return the version string compiled
453 * into this binary.
454 */
455 rc = vbglR3GetAdditionsCompileTimeVersion(ppszVer, ppszRev);
456 }
457 return rc;
458
459#else /* !RT_OS_WINDOWS */
460 /*
461 * On non-Windows platforms just return the compile-time version string.
462 */
463 return vbglR3GetAdditionsCompileTimeVersion(ppszVer, ppszRev);
464#endif /* !RT_OS_WINDOWS */
465}
466
467
468/**
469 * Retrieves the installation path of Guest Additions.
470 *
471 * @returns IPRT status value
472 * @param ppszPath Receives pointer of allocated installation path string.
473 * The returned pointer must be freed using
474 * RTStrFree().
475 */
476VBGLR3DECL(int) VbglR3GetAdditionsInstallationPath(char **ppszPath)
477{
478 int rc;
479#ifdef RT_OS_WINDOWS
480 HKEY hKey;
481 rc = vbglR3GetAdditionsWinStoragePath(&hKey);
482 if (RT_SUCCESS(rc))
483 {
484 /* Installation directory. */
485 DWORD dwType;
486 DWORD dwSize = _MAX_PATH * sizeof(char);
487 char *pszTmp = (char*)RTMemAlloc(dwSize + 1);
488 if (pszTmp)
489 {
490 LONG l = RegQueryValueEx(hKey, "InstallDir", NULL, &dwType, (BYTE*)(LPCTSTR)pszTmp, &dwSize);
491 if ((l != ERROR_SUCCESS) && (l != ERROR_FILE_NOT_FOUND))
492 {
493 rc = RTErrConvertFromNtStatus(l);
494 }
495 else
496 {
497 if (dwType == REG_SZ)
498 rc = RTStrDupEx(ppszPath, pszTmp);
499 else
500 rc = VERR_INVALID_PARAMETER;
501 if (RT_SUCCESS(rc))
502 {
503 /* Flip slashes. */
504 for (char *pszTmp2 = ppszPath[0]; *pszTmp2; ++pszTmp2)
505 if (*pszTmp2 == '\\')
506 *pszTmp2 = '/';
507 }
508 }
509 RTMemFree(pszTmp);
510 }
511 else
512 rc = VERR_NO_MEMORY;
513 rc = vbglR3CloseAdditionsWinStoragePath(hKey);
514 }
515#else
516 /** @todo implement me */
517 rc = VERR_NOT_IMPLEMENTED;
518#endif
519 return rc;
520}
521
522#endif /* !VBOX_VBGLR3_XFREE86 */
523
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