]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - ubuntu/vbox/vboxguest/VBoxGuestR0LibInit.c
UBUNTU: ubuntu: vbox -- update to 5.2.2-dfsg-2
[mirror_ubuntu-bionic-kernel.git] / ubuntu / vbox / vboxguest / VBoxGuestR0LibInit.c
CommitLineData
6d209b23
SF
1/* $Id: VBoxGuestR0LibInit.cpp $ */
2/** @file
3 * VBoxGuestLibR0 - Library initialization.
4 */
5
6/*
26894aac 7 * Copyright (C) 2006-2017 Oracle Corporation
6d209b23
SF
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#include "VBoxGuestR0LibInternal.h"
32
33#include <iprt/string.h>
34#include <iprt/assert.h>
35#include <iprt/semaphore.h>
36
37
38/*********************************************************************************************************************************
39* Global Variables *
40*********************************************************************************************************************************/
41/** The global VBGL instance data. */
42VBGLDATA g_vbgldata;
43
44
45/**
46 * Used by vbglR0QueryDriverInfo and VbglInit to try get the host feature mask
47 * and version information (g_vbgldata::hostVersion).
48 *
49 * This was first implemented by the host in 3.1 and we quietly ignore failures
50 * for that reason.
51 */
52static void vbglR0QueryHostVersion(void)
53{
54 VMMDevReqHostVersion *pReq;
55 int rc = VbglR0GRAlloc((VMMDevRequestHeader **) &pReq, sizeof (*pReq), VMMDevReq_GetHostVersion);
56 if (RT_SUCCESS(rc))
57 {
58 rc = VbglR0GRPerform(&pReq->header);
59 if (RT_SUCCESS(rc))
60 {
61 g_vbgldata.hostVersion = *pReq;
62 Log(("vbglR0QueryHostVersion: %u.%u.%ur%u %#x\n",
63 pReq->major, pReq->minor, pReq->build, pReq->revision, pReq->features));
64 }
65
66 VbglR0GRFree(&pReq->header);
67 }
68}
69
70
71#ifndef VBGL_VBOXGUEST
72/**
73 * The guest library uses lazy initialization for VMMDev port and memory,
74 * because these values are provided by the VBoxGuest driver and it might
75 * be loaded later than other drivers.
76 *
77 * The VbglEnter checks the current library status, tries to retrieve these
78 * values and fails if they are unavailable.
79 */
80static void vbglR0QueryDriverInfo(void)
81{
82# ifdef VBGLDATA_USE_FAST_MUTEX
83 int rc = RTSemFastMutexRequest(g_vbgldata.hMtxIdcSetup);
84# else
85 int rc = RTSemMutexRequest(g_vbgldata.hMtxIdcSetup, RT_INDEFINITE_WAIT);
86# endif
87 if (RT_SUCCESS(rc))
88 {
89 if (g_vbgldata.status == VbglStatusReady)
90 { /* likely */ }
91 else
92 {
93 rc = VbglR0IdcOpen(&g_vbgldata.IdcHandle,
94 VBGL_IOC_VERSION /*uReqVersion*/,
95 VBGL_IOC_VERSION & UINT32_C(0xffff0000) /*uMinVersion*/,
96 NULL /*puSessionVersion*/, NULL /*puDriverVersion*/, NULL /*puDriverRevision*/);
97 if (RT_SUCCESS(rc))
98 {
99 /*
100 * Try query the port info.
101 */
102 VBGLIOCGETVMMDEVIOINFO PortInfo;
103 RT_ZERO(PortInfo);
104 VBGLREQHDR_INIT(&PortInfo.Hdr, GET_VMMDEV_IO_INFO);
105 rc = VbglR0IdcCall(&g_vbgldata.IdcHandle, VBGL_IOCTL_GET_VMMDEV_IO_INFO, &PortInfo.Hdr, sizeof(PortInfo));
106 if (RT_SUCCESS(rc))
107 {
108 dprintf(("Port I/O = 0x%04x, MMIO = %p\n", PortInfo.u.Out.IoPort, PortInfo.u.Out.pvVmmDevMapping));
109
110 g_vbgldata.portVMMDev = PortInfo.u.Out.IoPort;
111 g_vbgldata.pVMMDevMemory = (VMMDevMemory *)PortInfo.u.Out.pvVmmDevMapping;
112 g_vbgldata.status = VbglStatusReady;
113
114 vbglR0QueryHostVersion();
115 }
116 }
117
118 dprintf(("vbglQueryDriverInfo rc = %Rrc\n", rc));
119 }
120
121# ifdef VBGLDATA_USE_FAST_MUTEX
122 RTSemFastMutexRelease(g_vbgldata.hMtxIdcSetup);
123# else
124 RTSemMutexRelease(g_vbgldata.hMtxIdcSetup);
125# endif
126 }
127}
128#endif /* !VBGL_VBOXGUEST */
129
130/**
131 * Checks if VBGL has been initialized.
132 *
133 * The client library, this will lazily complete the initialization.
134 *
135 * @return VINF_SUCCESS or VERR_VBGL_NOT_INITIALIZED.
136 */
137int vbglR0Enter(void)
138{
139 if (g_vbgldata.status == VbglStatusReady)
140 return VINF_SUCCESS;
141
142#ifndef VBGL_VBOXGUEST
143 if (g_vbgldata.status == VbglStatusInitializing)
144 {
145 vbglR0QueryDriverInfo();
146 if (g_vbgldata.status == VbglStatusReady)
147 return VINF_SUCCESS;
148 }
149#endif
150 return VERR_VBGL_NOT_INITIALIZED;
151}
152
153
154static int vbglR0InitCommon(void)
155{
156 int rc;
157
158 RT_ZERO(g_vbgldata);
159 g_vbgldata.status = VbglStatusInitializing;
160
161 rc = VbglR0PhysHeapInit();
162 if (RT_SUCCESS(rc))
163 {
164 dprintf(("vbglR0InitCommon: returns rc = %d\n", rc));
165 return rc;
166 }
167
168 LogRel(("vbglR0InitCommon: VbglR0PhysHeapInit failed: rc=%Rrc\n", rc));
169 g_vbgldata.status = VbglStatusNotInitialized;
170 return rc;
171}
172
173
174static void vbglR0TerminateCommon(void)
175{
176 VbglR0PhysHeapTerminate();
177 g_vbgldata.status = VbglStatusNotInitialized;
178}
179
180#ifdef VBGL_VBOXGUEST
181
182DECLVBGL(int) VbglR0InitPrimary(RTIOPORT portVMMDev, VMMDevMemory *pVMMDevMemory)
183{
184 int rc;
185
186# ifdef RT_OS_WINDOWS /** @todo r=bird: this doesn't make sense. Is there something special going on on windows? */
187 dprintf(("vbglInit: starts g_vbgldata.status %d\n", g_vbgldata.status));
188
189 if ( g_vbgldata.status == VbglStatusInitializing
190 || g_vbgldata.status == VbglStatusReady)
191 {
192 /* Initialization is already in process. */
193 return VINF_SUCCESS;
194 }
195# else
196 dprintf(("vbglInit: starts\n"));
197# endif
198
199 rc = vbglR0InitCommon();
200 if (RT_SUCCESS(rc))
201 {
202 g_vbgldata.portVMMDev = portVMMDev;
203 g_vbgldata.pVMMDevMemory = pVMMDevMemory;
204 g_vbgldata.status = VbglStatusReady;
205
206 vbglR0QueryHostVersion();
207 return VINF_SUCCESS;
208 }
209
210 g_vbgldata.status = VbglStatusNotInitialized;
211 return rc;
212}
213
214DECLVBGL(void) VbglR0TerminatePrimary(void)
215{
216 vbglR0TerminateCommon();
217}
218
219
220#else /* !VBGL_VBOXGUEST */
221
222DECLVBGL(int) VbglR0InitClient(void)
223{
224 int rc;
225
226 /** @todo r=bird: explain why we need to be doing this, please... */
227 if ( g_vbgldata.status == VbglStatusInitializing
228 || g_vbgldata.status == VbglStatusReady)
229 {
230 /* Initialization is already in process. */
231 return VINF_SUCCESS;
232 }
233
234 rc = vbglR0InitCommon();
235 if (RT_SUCCESS(rc))
236 {
237# ifdef VBGLDATA_USE_FAST_MUTEX
238 rc = RTSemFastMutexCreate(&g_vbgldata.hMtxIdcSetup);
239# else
240 rc = RTSemMutexCreate(&g_vbgldata.hMtxIdcSetup);
241# endif
242 if (RT_SUCCESS(rc))
243 {
244 /* Try to obtain VMMDev port via IOCTL to VBoxGuest main driver. */
245 vbglR0QueryDriverInfo();
246
247# ifdef VBOX_WITH_HGCM
248 rc = VbglR0HGCMInit();
249# endif
250 if (RT_SUCCESS(rc))
251 return VINF_SUCCESS;
252
253# ifdef VBGLDATA_USE_FAST_MUTEX
254 RTSemFastMutexDestroy(g_vbgldata.hMtxIdcSetup);
255 g_vbgldata.hMtxIdcSetup = NIL_RTSEMFASTMUTEX;
256# else
257 RTSemMutexDestroy(g_vbgldata.hMtxIdcSetup);
258 g_vbgldata.hMtxIdcSetup = NIL_RTSEMMUTEX;
259# endif
260 }
261 vbglR0TerminateCommon();
262 }
263
264 return rc;
265}
266
267DECLVBGL(void) VbglR0TerminateClient(void)
268{
269# ifdef VBOX_WITH_HGCM
270 VbglR0HGCMTerminate();
271# endif
272
273 /* driver open could fail, which does not prevent VbglInit from succeeding,
274 * close the driver only if it is opened */
275 VbglR0IdcClose(&g_vbgldata.IdcHandle);
276# ifdef VBGLDATA_USE_FAST_MUTEX
277 RTSemFastMutexDestroy(g_vbgldata.hMtxIdcSetup);
278 g_vbgldata.hMtxIdcSetup = NIL_RTSEMFASTMUTEX;
279# else
280 RTSemMutexDestroy(g_vbgldata.hMtxIdcSetup);
281 g_vbgldata.hMtxIdcSetup = NIL_RTSEMMUTEX;
282# endif
283
284 /* note: do vbglR0TerminateCommon as a last step since it zeroez up the g_vbgldata
285 * conceptually, doing vbglR0TerminateCommon last is correct
286 * since this is the reverse order to how init is done */
287 vbglR0TerminateCommon();
288}
289
290
291int VBOXCALL vbglR0QueryIdcHandle(PVBGLIDCHANDLE *ppIdcHandle)
292{
293 if (g_vbgldata.status == VbglStatusReady)
294 { /* likely */ }
295 else
296 {
297 vbglR0QueryDriverInfo();
298 if (g_vbgldata.status != VbglStatusReady)
299 {
300 *ppIdcHandle = NULL;
301 return VERR_TRY_AGAIN;
302 }
303 }
304
305 *ppIdcHandle = &g_vbgldata.IdcHandle;
306 return VINF_SUCCESS;
307}
308
309#endif /* !VBGL_VBOXGUEST */
310