VirtualBox

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

Last change on this file since 75803 was 75705, checked in by vboxsync, 6 years ago

VBoxGuest/darwin: Implemented straight forward interrupt handling. Enabled test signing. Adjustments. bugref:4686

  • 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 75705 2018-11-25 01:44:41Z 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 /* IOKit */
222 mach_port_t MasterPort;
223 kern_return_t kr = IOMasterPort(MACH_PORT_NULL, &MasterPort);
224 if (kr != kIOReturnSuccess)
225 {
226 LogRel(("IOMasterPort -> %d\n", kr));
227 return VERR_GENERAL_FAILURE;
228 }
229
230 CFDictionaryRef ClassToMatch = IOServiceMatching("org_virtualbox_VBoxGuest");
231 if (!ClassToMatch)
232 {
233 LogRel(("IOServiceMatching(\"org_virtualbox_VBoxGuest\") failed.\n"));
234 return VERR_GENERAL_FAILURE;
235 }
236
237 io_service_t ServiceObject = IOServiceGetMatchingService(kIOMasterPortDefault, ClassToMatch);
238 if (!ServiceObject)
239 {
240 LogRel(("IOServiceGetMatchingService returned NULL\n"));
241 return VERR_NOT_FOUND;
242 }
243
244 io_connect_t uConnection;
245 kr = IOServiceOpen(ServiceObject, mach_task_self(), VBOXGUEST_DARWIN_IOSERVICE_COOKIE, &uConnection);
246 IOObjectRelease(ServiceObject);
247 if (kr != kIOReturnSuccess)
248 {
249 LogRel(("IOServiceOpen returned %d. Driver open failed.\n", kr));
250 return VERR_OPEN_FAILED;
251 }
252
253 /* Regular unix FD. */
254 RTFILE hFile;
255 int rc = RTFileOpen(&hFile, pszDeviceName, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
256 if (RT_FAILURE(rc))
257 {
258 LogRel(("RTFileOpen(%s) returned %Rrc. Driver open failed.\n", pszDeviceName, rc));
259 IOServiceClose(uConnection);
260 return rc;
261 }
262 g_File = hFile;
263 g_uConnection = uConnection;
264
265#elif defined(VBOX_VBGLR3_XSERVER)
266 int File = xf86open(pszDeviceName, XF86_O_RDWR);
267 if (File == -1)
268 return VERR_OPEN_FAILED;
269 g_File = File;
270
271#else
272
273 /* The default implementation. (linux, solaris, freebsd, netbsd, haiku) */
274 RTFILE File;
275 int rc = RTFileOpen(&File, pszDeviceName, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
276 if (RT_FAILURE(rc))
277 return rc;
278 g_File = File;
279
280#endif
281
282 /*
283 * Adjust the I/O control interface version.
284 */
285 {
286 VBGLIOCDRIVERVERSIONINFO VerInfo;
287 VBGLREQHDR_INIT(&VerInfo.Hdr, DRIVER_VERSION_INFO);
288 VerInfo.u.In.uMinVersion = VBGL_IOC_VERSION & UINT32_C(0xffff0000);
289 VerInfo.u.In.uReqVersion = VBGL_IOC_VERSION;
290 VerInfo.u.In.uReserved1 = 0;
291 VerInfo.u.In.uReserved2 = 0;
292 rc2 = vbglR3DoIOCtl(VBGL_IOCTL_DRIVER_VERSION_INFO, &VerInfo.Hdr, sizeof(VerInfo));
293#ifndef VBOX_VBGLR3_XSERVER
294 AssertRC(rc2); /* otherwise ignored for now*/
295#endif
296 }
297
298
299#ifndef VBOX_VBGLR3_XSERVER
300 /*
301 * Create release logger
302 */
303 PRTLOGGER pReleaseLogger;
304 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
305 rc2 = RTLogCreate(&pReleaseLogger, 0, "all", "VBOX_RELEASE_LOG",
306 RT_ELEMENTS(s_apszGroups), &s_apszGroups[0], RTLOGDEST_USER, NULL);
307 /* This may legitimately fail if we are using the mini-runtime. */
308 if (RT_SUCCESS(rc2))
309 RTLogRelSetDefaultInstance(pReleaseLogger);
310#endif
311
312 return VINF_SUCCESS;
313}
314
315
316/**
317 * Open the VBox R3 Guest Library. This should be called by system daemons
318 * and processes.
319 */
320VBGLR3DECL(int) VbglR3Init(void)
321{
322 return vbglR3Init(VBOXGUEST_DEVICE_NAME);
323}
324
325
326/**
327 * Open the VBox R3 Guest Library. Equivalent to VbglR3Init, but for user
328 * session processes.
329 */
330VBGLR3DECL(int) VbglR3InitUser(void)
331{
332 return vbglR3Init(VBOXGUEST_USER_DEVICE_NAME);
333}
334
335
336VBGLR3DECL(void) VbglR3Term(void)
337{
338 /*
339 * Decrement the reference count and see if we're the last one out.
340 */
341 uint32_t cInits = ASMAtomicDecU32(&g_cInits);
342 if (cInits > 0)
343 return;
344#if !defined(VBOX_VBGLR3_XSERVER)
345 AssertReturnVoid(!cInits);
346
347# if defined(RT_OS_WINDOWS)
348 HANDLE hFile = g_hFile;
349 g_hFile = INVALID_HANDLE_VALUE;
350 AssertReturnVoid(hFile != INVALID_HANDLE_VALUE);
351 BOOL fRc = CloseHandle(hFile);
352 Assert(fRc); NOREF(fRc);
353
354# elif defined(RT_OS_OS2)
355 RTFILE File = g_File;
356 g_File = NIL_RTFILE;
357 AssertReturnVoid(File != NIL_RTFILE);
358 APIRET rc = DosClose((uintptr_t)File);
359 AssertMsg(!rc, ("%ld\n", rc));
360
361#elif defined(RT_OS_DARWIN)
362 io_connect_t uConnection = g_uConnection;
363 RTFILE hFile = g_File;
364 g_uConnection = 0;
365 g_File = NIL_RTFILE;
366 kern_return_t kr = IOServiceClose(uConnection);
367 AssertMsg(kr == kIOReturnSuccess, ("%#x (%d)\n", kr, kr)); NOREF(kr);
368 int rc = RTFileClose(hFile);
369 AssertRC(rc);
370
371# else /* The IPRT case. */
372 RTFILE File = g_File;
373 g_File = NIL_RTFILE;
374 AssertReturnVoid(File != NIL_RTFILE);
375 int rc = RTFileClose(File);
376 AssertRC(rc);
377# endif
378
379#else /* VBOX_VBGLR3_XSERVER */
380 int File = g_File;
381 g_File = -1;
382 if (File == -1)
383 return;
384 xf86close(File);
385#endif /* VBOX_VBGLR3_XSERVER */
386}
387
388
389/**
390 * Internal wrapper around various OS specific ioctl implementations.
391 *
392 * @returns VBox status code as returned by VBoxGuestCommonIOCtl, or
393 * an failure returned by the OS specific ioctl APIs.
394 *
395 * @param uFunction The requested function.
396 * @param pHdr The input and output request buffer.
397 * @param cbReq The size of the request buffer.
398 */
399int vbglR3DoIOCtlRaw(uintptr_t uFunction, PVBGLREQHDR pHdr, size_t cbReq)
400{
401 Assert(cbReq == RT_MAX(pHdr->cbIn, pHdr->cbOut)); RT_NOREF1(cbReq);
402 Assert(pHdr->cbOut != 0);
403
404#if defined(RT_OS_WINDOWS)
405# if 0 /*def USE_NT_DEVICE_IO_CONTROL_FILE*/
406 IO_STATUS_BLOCK Ios;
407 Ios.Status = -1;
408 Ios.Information = 0;
409 NTSTATUS rcNt = NtDeviceIoControlFile(g_hFile, NULL /*hEvent*/, NULL /*pfnApc*/, NULL /*pvApcCtx*/, &Ios,
410 (ULONG)uFunction,
411 pHdr /*pvInput */, pHdr->cbIn /* cbInput */,
412 pHdr /*pvOutput*/, pHdr->cbOut /* cbOutput */);
413 if (NT_SUCCESS(rcNt))
414 {
415 if (NT_SUCCESS(Ios.Status))
416 return VINF_SUCCESS;
417 rcNt = Ios.Status;
418 }
419 return RTErrConvertFromNtStatus(rcNt);
420
421# else
422 DWORD cbReturned = (ULONG)pHdr->cbOut;
423 if (DeviceIoControl(g_hFile, uFunction, pHdr, pHdr->cbIn, pHdr, cbReturned, &cbReturned, NULL))
424 return 0;
425 return RTErrConvertFromWin32(GetLastError());
426# endif
427
428#elif defined(RT_OS_OS2)
429 ULONG cbOS2Parm = cbReq;
430 APIRET rc = DosDevIOCtl((uintptr_t)g_File, VBGL_IOCTL_CATEGORY, uFunction, pHdr, cbReq, &cbOS2Parm, NULL, 0, NULL);
431 if (RT_LIKELY(rc == NO_ERROR))
432 return VINF_SUCCESS;
433 return RTErrConvertFromOS2(rc);
434
435#elif defined(VBOX_VBGLR3_XSERVER)
436 if (g_File != -1)
437 {
438 if (RT_LIKELY(xf86ioctl((int)g_File, uFunction, pHdr) >= 0))
439 return VINF_SUCCESS;
440 return VERR_FILE_IO_ERROR;
441 }
442 return VERR_INVALID_HANDLE;
443
444#else
445 if (g_File != NIL_RTFILE)
446 {
447 if (RT_LIKELY(ioctl((int)(intptr_t)g_File, uFunction, pHdr) >= 0))
448 return VINF_SUCCESS;
449 return RTErrConvertFromErrno(errno);
450 }
451 return VERR_INVALID_HANDLE;
452#endif
453}
454
455
456/**
457 * Internal wrapper around various OS specific ioctl implementations, that
458 * returns the status from the header.
459 *
460 * @returns VBox status code as returned by VBoxGuestCommonIOCtl, or
461 * an failure returned by the OS specific ioctl APIs.
462 *
463 * @param uFunction The requested function.
464 * @param pHdr The input and output request buffer.
465 * @param cbReq The size of the request buffer.
466 */
467int vbglR3DoIOCtl(uintptr_t uFunction, PVBGLREQHDR pHdr, size_t cbReq)
468{
469 int rc = vbglR3DoIOCtlRaw(uFunction, pHdr, cbReq);
470 if (RT_SUCCESS(rc))
471 rc = pHdr->rc;
472 return rc;
473}
474
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