VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3Lib.cpp@ 85584

Last change on this file since 85584 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keyword set to Id
  • Property svn:keywords set to Id Revision
File size: 14.5 KB
Line 
1/* $Id: VBoxGuestR3Lib.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Core.
4 */
5
6/*
7 * Copyright (C) 2007-2020 Oracle Corporation
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
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#if defined(RT_OS_WINDOWS)
32# include <iprt/nt/nt-and-windows.h>
33
34#elif defined(RT_OS_OS2)
35# define INCL_BASE
36# define INCL_ERRORS
37# include <os2.h>
38
39#elif defined(RT_OS_DARWIN) \
40 || defined(RT_OS_FREEBSD) \
41 || defined(RT_OS_HAIKU) \
42 || defined(RT_OS_LINUX) \
43 || defined(RT_OS_NETBSD) \
44 || defined(RT_OS_SOLARIS)
45# include <sys/types.h>
46# include <sys/stat.h>
47# if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX) || defined(RT_OS_NETBSD)
48 /** @todo check this on solaris+freebsd as well. */
49# include <sys/ioctl.h>
50# endif
51# if defined(RT_OS_DARWIN)
52# include <mach/mach_port.h>
53# include <IOKit/IOKitLib.h>
54# endif
55# include <errno.h>
56# include <unistd.h>
57#endif
58
59#include <iprt/assert.h>
60#include <iprt/asm.h>
61#include <iprt/err.h>
62#include <iprt/file.h>
63#include <iprt/time.h>
64#include <iprt/string.h>
65#include <iprt/thread.h>
66#include <VBox/log.h>
67#include "VBoxGuestR3LibInternal.h"
68
69#ifdef VBOX_VBGLR3_XFREE86
70/* Rather than try to resolve all the header file conflicts, I will just
71 prototype what we need here. */
72# define XF86_O_RDWR 0x0002
73typedef void *pointer;
74extern "C" int xf86open(const char *, int, ...);
75extern "C" int xf86close(int);
76extern "C" int xf86ioctl(int, unsigned long, pointer);
77# define VBOX_VBGLR3_XSERVER
78#elif defined(VBOX_VBGLR3_XORG)
79# include <sys/stat.h>
80# include <fcntl.h>
81# include <unistd.h>
82# include <sys/ioctl.h>
83# define xf86open open
84# define xf86close close
85# define xf86ioctl ioctl
86# define XF86_O_RDWR O_RDWR
87# define VBOX_VBGLR3_XSERVER
88#endif
89
90
91/*********************************************************************************************************************************
92* Global Variables *
93*********************************************************************************************************************************/
94/** The VBoxGuest device handle. */
95#ifdef VBOX_VBGLR3_XSERVER
96static int g_File = -1;
97#elif defined(RT_OS_WINDOWS)
98static HANDLE g_hFile = INVALID_HANDLE_VALUE;
99#else
100static RTFILE g_File = NIL_RTFILE;
101#endif
102/** User counter.
103 * A counter of the number of times the library has been initialised, for use with
104 * X.org drivers, where the library may be shared by multiple independent modules
105 * inside a single process space.
106 */
107static uint32_t volatile g_cInits = 0;
108#ifdef RT_OS_DARWIN
109/** I/O Kit connection handle. */
110static io_connect_t g_uConnection = 0;
111#endif
112
113
114
115/**
116 * Implementation of VbglR3Init and VbglR3InitUser
117 */
118static int vbglR3Init(const char *pszDeviceName)
119{
120 int rc2;
121 uint32_t cInits = ASMAtomicIncU32(&g_cInits);
122 Assert(cInits > 0);
123 if (cInits > 1)
124 {
125 /*
126 * This will fail if two (or more) threads race each other calling VbglR3Init.
127 * However it will work fine for single threaded or otherwise serialized
128 * processed calling us more than once.
129 */
130#ifdef RT_OS_WINDOWS
131 if (g_hFile == INVALID_HANDLE_VALUE)
132#elif !defined (VBOX_VBGLR3_XSERVER)
133 if (g_File == NIL_RTFILE)
134#else
135 if (g_File == -1)
136#endif
137 return VERR_INTERNAL_ERROR;
138 return VINF_SUCCESS;
139 }
140#if defined(RT_OS_WINDOWS)
141 if (g_hFile != INVALID_HANDLE_VALUE)
142#elif !defined(VBOX_VBGLR3_XSERVER)
143 if (g_File != NIL_RTFILE)
144#else
145 if (g_File != -1)
146#endif
147 return VERR_INTERNAL_ERROR;
148
149#if defined(RT_OS_WINDOWS)
150 /*
151 * Have to use CreateFile here as we want to specify FILE_FLAG_OVERLAPPED
152 * and possible some other bits not available thru iprt/file.h.
153 */
154 HANDLE hFile = CreateFile(pszDeviceName,
155 GENERIC_READ | GENERIC_WRITE,
156 FILE_SHARE_READ | FILE_SHARE_WRITE,
157 NULL,
158 OPEN_EXISTING,
159 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
160 NULL);
161
162 if (hFile == INVALID_HANDLE_VALUE)
163 return VERR_OPEN_FAILED;
164 g_hFile = hFile;
165
166#elif defined(RT_OS_OS2)
167 /*
168 * We might wish to compile this with Watcom, so stick to
169 * the OS/2 APIs all the way. And in any case we have to use
170 * DosDevIOCtl for the requests, why not use Dos* for everything.
171 */
172 HFILE hf = NULLHANDLE;
173 ULONG ulAction = 0;
174 APIRET rc = DosOpen((PCSZ)pszDeviceName, &hf, &ulAction, 0, FILE_NORMAL,
175 OPEN_ACTION_OPEN_IF_EXISTS,
176 OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NOINHERIT | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READWRITE,
177 NULL);
178 if (rc)
179 return RTErrConvertFromOS2(rc);
180
181 if (hf < 16)
182 {
183 HFILE ahfs[16];
184 unsigned i;
185 for (i = 0; i < RT_ELEMENTS(ahfs); i++)
186 {
187 ahfs[i] = 0xffffffff;
188 rc = DosDupHandle(hf, &ahfs[i]);
189 if (rc)
190 break;
191 }
192
193 if (i-- > 1)
194 {
195 ULONG fulState = 0;
196 rc = DosQueryFHState(ahfs[i], &fulState);
197 if (!rc)
198 {
199 fulState |= OPEN_FLAGS_NOINHERIT;
200 fulState &= OPEN_FLAGS_WRITE_THROUGH | OPEN_FLAGS_FAIL_ON_ERROR | OPEN_FLAGS_NO_CACHE | OPEN_FLAGS_NOINHERIT; /* Turn off non-participating bits. */
201 rc = DosSetFHState(ahfs[i], fulState);
202 }
203 if (!rc)
204 {
205 rc = DosClose(hf);
206 AssertMsg(!rc, ("%ld\n", rc));
207 hf = ahfs[i];
208 }
209 else
210 i++;
211 while (i-- > 0)
212 DosClose(ahfs[i]);
213 }
214 }
215 g_File = (RTFILE)hf;
216
217#elif defined(RT_OS_DARWIN)
218 /*
219 * Darwin is kind of special we need to engage the device via I/O first
220 * before we open it via the BSD device node.
221 */
222 /* IOKit */
223 mach_port_t MasterPort;
224 kern_return_t kr = IOMasterPort(MACH_PORT_NULL, &MasterPort);
225 if (kr != kIOReturnSuccess)
226 {
227 LogRel(("IOMasterPort -> %d\n", kr));
228 return VERR_GENERAL_FAILURE;
229 }
230
231 CFDictionaryRef ClassToMatch = IOServiceMatching("org_virtualbox_VBoxGuest");
232 if (!ClassToMatch)
233 {
234 LogRel(("IOServiceMatching(\"org_virtualbox_VBoxGuest\") failed.\n"));
235 return VERR_GENERAL_FAILURE;
236 }
237
238 io_service_t ServiceObject = IOServiceGetMatchingService(kIOMasterPortDefault, ClassToMatch);
239 if (!ServiceObject)
240 {
241 LogRel(("IOServiceGetMatchingService returned NULL\n"));
242 return VERR_NOT_FOUND;
243 }
244
245 io_connect_t uConnection;
246 kr = IOServiceOpen(ServiceObject, mach_task_self(), VBOXGUEST_DARWIN_IOSERVICE_COOKIE, &uConnection);
247 IOObjectRelease(ServiceObject);
248 if (kr != kIOReturnSuccess)
249 {
250 LogRel(("IOServiceOpen returned %d. Driver open failed.\n", kr));
251 return VERR_OPEN_FAILED;
252 }
253
254 /* Regular unix FD. */
255 RTFILE hFile;
256 int rc = RTFileOpen(&hFile, pszDeviceName, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
257 if (RT_FAILURE(rc))
258 {
259 LogRel(("RTFileOpen(%s) returned %Rrc. Driver open failed.\n", pszDeviceName, rc));
260 IOServiceClose(uConnection);
261 return rc;
262 }
263 g_File = hFile;
264 g_uConnection = uConnection;
265
266#elif defined(VBOX_VBGLR3_XSERVER)
267 int File = xf86open(pszDeviceName, XF86_O_RDWR);
268 if (File == -1)
269 return VERR_OPEN_FAILED;
270 g_File = File;
271
272#else
273
274 /* The default implementation. (linux, solaris, freebsd, netbsd, haiku) */
275 RTFILE File;
276 int rc = RTFileOpen(&File, pszDeviceName, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
277 if (RT_FAILURE(rc))
278 return rc;
279 g_File = File;
280
281#endif
282
283 /*
284 * Adjust the I/O control interface version.
285 */
286 {
287 VBGLIOCDRIVERVERSIONINFO VerInfo;
288 VBGLREQHDR_INIT(&VerInfo.Hdr, DRIVER_VERSION_INFO);
289 VerInfo.u.In.uMinVersion = VBGL_IOC_VERSION & UINT32_C(0xffff0000);
290 VerInfo.u.In.uReqVersion = VBGL_IOC_VERSION;
291 VerInfo.u.In.uReserved1 = 0;
292 VerInfo.u.In.uReserved2 = 0;
293 rc2 = vbglR3DoIOCtl(VBGL_IOCTL_DRIVER_VERSION_INFO, &VerInfo.Hdr, sizeof(VerInfo));
294#ifndef VBOX_VBGLR3_XSERVER
295 AssertRC(rc2); /* otherwise ignored for now*/
296#endif
297 }
298
299
300#ifndef VBOX_VBGLR3_XSERVER
301 /*
302 * Create release logger
303 */
304 PRTLOGGER pReleaseLogger;
305 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
306 rc2 = RTLogCreate(&pReleaseLogger, 0, "all", "VBOX_RELEASE_LOG",
307 RT_ELEMENTS(s_apszGroups), &s_apszGroups[0], RTLOGDEST_USER, NULL);
308 /* This may legitimately fail if we are using the mini-runtime. */
309 if (RT_SUCCESS(rc2))
310 RTLogRelSetDefaultInstance(pReleaseLogger);
311#endif
312
313 return VINF_SUCCESS;
314}
315
316
317/**
318 * Open the VBox R3 Guest Library. This should be called by system daemons
319 * and processes.
320 */
321VBGLR3DECL(int) VbglR3Init(void)
322{
323 return vbglR3Init(VBOXGUEST_DEVICE_NAME);
324}
325
326
327/**
328 * Open the VBox R3 Guest Library. Equivalent to VbglR3Init, but for user
329 * session processes.
330 */
331VBGLR3DECL(int) VbglR3InitUser(void)
332{
333 return vbglR3Init(VBOXGUEST_USER_DEVICE_NAME);
334}
335
336
337VBGLR3DECL(void) VbglR3Term(void)
338{
339 /*
340 * Decrement the reference count and see if we're the last one out.
341 */
342 uint32_t cInits = ASMAtomicDecU32(&g_cInits);
343 if (cInits > 0)
344 return;
345#if !defined(VBOX_VBGLR3_XSERVER)
346 AssertReturnVoid(!cInits);
347
348# if defined(RT_OS_WINDOWS)
349 HANDLE hFile = g_hFile;
350 g_hFile = INVALID_HANDLE_VALUE;
351 AssertReturnVoid(hFile != INVALID_HANDLE_VALUE);
352 BOOL fRc = CloseHandle(hFile);
353 Assert(fRc); NOREF(fRc);
354
355# elif defined(RT_OS_OS2)
356 RTFILE File = g_File;
357 g_File = NIL_RTFILE;
358 AssertReturnVoid(File != NIL_RTFILE);
359 APIRET rc = DosClose((uintptr_t)File);
360 AssertMsg(!rc, ("%ld\n", rc));
361
362#elif defined(RT_OS_DARWIN)
363 io_connect_t uConnection = g_uConnection;
364 RTFILE hFile = g_File;
365 g_uConnection = 0;
366 g_File = NIL_RTFILE;
367 kern_return_t kr = IOServiceClose(uConnection);
368 AssertMsg(kr == kIOReturnSuccess, ("%#x (%d)\n", kr, kr)); NOREF(kr);
369 int rc = RTFileClose(hFile);
370 AssertRC(rc);
371
372# else /* The IPRT case. */
373 RTFILE File = g_File;
374 g_File = NIL_RTFILE;
375 AssertReturnVoid(File != NIL_RTFILE);
376 int rc = RTFileClose(File);
377 AssertRC(rc);
378# endif
379
380#else /* VBOX_VBGLR3_XSERVER */
381 int File = g_File;
382 g_File = -1;
383 if (File == -1)
384 return;
385 xf86close(File);
386#endif /* VBOX_VBGLR3_XSERVER */
387}
388
389
390/**
391 * Internal wrapper around various OS specific ioctl implementations.
392 *
393 * @returns VBox status code as returned by VBoxGuestCommonIOCtl, or
394 * an failure returned by the OS specific ioctl APIs.
395 *
396 * @param uFunction The requested function.
397 * @param pHdr The input and output request buffer.
398 * @param cbReq The size of the request buffer.
399 */
400int vbglR3DoIOCtlRaw(uintptr_t uFunction, PVBGLREQHDR pHdr, size_t cbReq)
401{
402 Assert(cbReq == RT_MAX(pHdr->cbIn, pHdr->cbOut)); RT_NOREF1(cbReq);
403 Assert(pHdr->cbOut != 0);
404
405#if defined(RT_OS_WINDOWS)
406# if 0 /*def USE_NT_DEVICE_IO_CONTROL_FILE*/
407 IO_STATUS_BLOCK Ios;
408 Ios.Status = -1;
409 Ios.Information = 0;
410 NTSTATUS rcNt = NtDeviceIoControlFile(g_hFile, NULL /*hEvent*/, NULL /*pfnApc*/, NULL /*pvApcCtx*/, &Ios,
411 (ULONG)uFunction,
412 pHdr /*pvInput */, pHdr->cbIn /* cbInput */,
413 pHdr /*pvOutput*/, pHdr->cbOut /* cbOutput */);
414 if (NT_SUCCESS(rcNt))
415 {
416 if (NT_SUCCESS(Ios.Status))
417 return VINF_SUCCESS;
418 rcNt = Ios.Status;
419 }
420 return RTErrConvertFromNtStatus(rcNt);
421
422# else
423 DWORD cbReturned = (ULONG)pHdr->cbOut;
424 if (DeviceIoControl(g_hFile, uFunction, pHdr, pHdr->cbIn, pHdr, cbReturned, &cbReturned, NULL))
425 return 0;
426 return RTErrConvertFromWin32(GetLastError());
427# endif
428
429#elif defined(RT_OS_OS2)
430 ULONG cbOS2Parm = cbReq;
431 APIRET rc = DosDevIOCtl((uintptr_t)g_File, VBGL_IOCTL_CATEGORY, uFunction, pHdr, cbReq, &cbOS2Parm, NULL, 0, NULL);
432 if (RT_LIKELY(rc == NO_ERROR))
433 return VINF_SUCCESS;
434 return RTErrConvertFromOS2(rc);
435
436#elif defined(VBOX_VBGLR3_XSERVER)
437 if (g_File != -1)
438 {
439 if (RT_LIKELY(xf86ioctl((int)g_File, uFunction, pHdr) >= 0))
440 return VINF_SUCCESS;
441 return VERR_FILE_IO_ERROR;
442 }
443 return VERR_INVALID_HANDLE;
444
445#else
446 if (g_File != NIL_RTFILE)
447 {
448 if (RT_LIKELY(ioctl((int)(intptr_t)g_File, uFunction, pHdr) >= 0))
449 return VINF_SUCCESS;
450 return RTErrConvertFromErrno(errno);
451 }
452 return VERR_INVALID_HANDLE;
453#endif
454}
455
456
457/**
458 * Internal wrapper around various OS specific ioctl implementations, that
459 * returns the status from the header.
460 *
461 * @returns VBox status code as returned by VBoxGuestCommonIOCtl, or
462 * an failure returned by the OS specific ioctl APIs.
463 *
464 * @param uFunction The requested function.
465 * @param pHdr The input and output request buffer.
466 * @param cbReq The size of the request buffer.
467 */
468int vbglR3DoIOCtl(uintptr_t uFunction, PVBGLREQHDR pHdr, size_t cbReq)
469{
470 int rc = vbglR3DoIOCtlRaw(uFunction, pHdr, cbReq);
471 if (RT_SUCCESS(rc))
472 rc = pHdr->rc;
473 return rc;
474}
475
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