VirtualBox

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

Last change on this file since 70873 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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