VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR0LibInit.cpp

Last change on this file was 100360, checked in by vboxsync, 11 months ago

Additions/VBoxGuest/VBoxGuestR0LibPhysHeap: Make use of the RTR0MemObjContAlloc() API and support allocating memory above 4GiB, bugref:10457

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.0 KB
Line 
1/* $Id: VBoxGuestR0LibInit.cpp 100360 2023-07-04 07:09:24Z vboxsync $ */
2/** @file
3 * VBoxGuestLibR0 - Library initialization.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#include "VBoxGuestR0LibInternal.h"
36
37#include <iprt/string.h>
38#include <iprt/assert.h>
39#include <iprt/semaphore.h>
40#include <VBox/err.h>
41
42
43/*********************************************************************************************************************************
44* Global Variables *
45*********************************************************************************************************************************/
46/** The global VBGL instance data. */
47VBGLDATA g_vbgldata;
48
49
50/**
51 * Used by vbglR0QueryDriverInfo and VbglInit to try get the host feature mask
52 * and version information (g_vbgldata::hostVersion).
53 *
54 * This was first implemented by the host in 3.1 and we quietly ignore failures
55 * for that reason.
56 */
57static void vbglR0QueryHostVersion(void)
58{
59 VMMDevReqHostVersion *pReq;
60 int rc = VbglR0GRAlloc((VMMDevRequestHeader **) &pReq, sizeof (*pReq), VMMDevReq_GetHostVersion);
61 if (RT_SUCCESS(rc))
62 {
63 rc = VbglR0GRPerform(&pReq->header);
64 if (RT_SUCCESS(rc))
65 {
66 g_vbgldata.hostVersion = *pReq;
67 Log(("vbglR0QueryHostVersion: %u.%u.%ur%u %#x\n",
68 pReq->major, pReq->minor, pReq->build, pReq->revision, pReq->features));
69 }
70
71 VbglR0GRFree(&pReq->header);
72 }
73}
74
75
76#ifndef VBGL_VBOXGUEST
77/**
78 * The guest library uses lazy initialization for VMMDev port and memory,
79 * because these values are provided by the VBoxGuest driver and it might
80 * be loaded later than other drivers.
81 *
82 * The VbglEnter checks the current library status, tries to retrieve these
83 * values and fails if they are unavailable.
84 */
85static int vbglR0QueryDriverInfo(void)
86{
87# ifdef VBGLDATA_USE_FAST_MUTEX
88 int rc = RTSemFastMutexRequest(g_vbgldata.hMtxIdcSetup);
89# else
90 int rc = RTSemMutexRequest(g_vbgldata.hMtxIdcSetup, RT_INDEFINITE_WAIT);
91# endif
92 if (RT_SUCCESS(rc))
93 {
94 if (g_vbgldata.status == VbglStatusReady)
95 { /* likely */ }
96 else
97 {
98 rc = VbglR0IdcOpen(&g_vbgldata.IdcHandle,
99 VBGL_IOC_VERSION /*uReqVersion*/,
100 VBGL_IOC_VERSION & UINT32_C(0xffff0000) /*uMinVersion*/,
101 NULL /*puSessionVersion*/, NULL /*puDriverVersion*/, NULL /*puDriverRevision*/);
102 if (RT_SUCCESS(rc))
103 {
104 /*
105 * Try query the port info.
106 */
107 VBGLIOCGETVMMDEVIOINFO PortInfo;
108 RT_ZERO(PortInfo);
109 VBGLREQHDR_INIT(&PortInfo.Hdr, GET_VMMDEV_IO_INFO);
110 rc = VbglR0IdcCall(&g_vbgldata.IdcHandle, VBGL_IOCTL_GET_VMMDEV_IO_INFO, &PortInfo.Hdr, sizeof(PortInfo));
111 if (RT_SUCCESS(rc))
112 {
113 dprintf(("Port I/O = 0x%04x, MMIO = %p\n", PortInfo.u.Out.IoPort, PortInfo.u.Out.pvVmmDevMapping));
114
115 g_vbgldata.portVMMDev = PortInfo.u.Out.IoPort;
116 g_vbgldata.pVMMDevMemory = (VMMDevMemory *)PortInfo.u.Out.pvVmmDevMapping;
117 g_vbgldata.pMmioReq = PortInfo.u.Out.pMmioReq;
118
119 /*
120 * Initialize the physical heap, only allocate memory below 4GiB if the new
121 * MMIO interface isn't available and we are using a 32-bit OUT instruction to pass a block
122 * physical address to the host.
123 */
124 rc = VbglR0PhysHeapInit(g_vbgldata.pMmioReq == NULL ? _4G - 1 : NIL_RTHCPHYS /*HCPhysMax*/);
125 if (RT_SUCCESS(rc))
126 {
127 g_vbgldata.status = VbglStatusReady;
128 vbglR0QueryHostVersion();
129 }
130 else
131 {
132 LogRel(("vbglR0QueryDriverInfo: VbglR0PhysHeapInit() -> %Rrc\n", rc));
133 g_vbgldata.status = VbglStatusNotInitialized;
134 }
135 }
136 }
137
138 dprintf(("vbglQueryDriverInfo rc = %Rrc\n", rc));
139 }
140
141# ifdef VBGLDATA_USE_FAST_MUTEX
142 RTSemFastMutexRelease(g_vbgldata.hMtxIdcSetup);
143# else
144 RTSemMutexRelease(g_vbgldata.hMtxIdcSetup);
145# endif
146 }
147 return rc;
148}
149#endif /* !VBGL_VBOXGUEST */
150
151/**
152 * Checks if VBGL has been initialized.
153 *
154 * The client library, this will lazily complete the initialization.
155 *
156 * @return VINF_SUCCESS or VERR_VBGL_NOT_INITIALIZED.
157 */
158int vbglR0Enter(void)
159{
160 if (g_vbgldata.status == VbglStatusReady)
161 return VINF_SUCCESS;
162
163#ifndef VBGL_VBOXGUEST
164 if (g_vbgldata.status == VbglStatusInitializing)
165 {
166 vbglR0QueryDriverInfo();
167 if (g_vbgldata.status == VbglStatusReady)
168 return VINF_SUCCESS;
169 }
170#endif
171 return VERR_VBGL_NOT_INITIALIZED;
172}
173
174
175static int vbglR0InitCommon(void)
176{
177 RT_ZERO(g_vbgldata);
178 g_vbgldata.status = VbglStatusInitializing;
179 return VINF_SUCCESS;
180}
181
182
183static void vbglR0TerminateCommon(void)
184{
185 VbglR0PhysHeapTerminate();
186 g_vbgldata.status = VbglStatusNotInitialized;
187}
188
189#ifdef VBGL_VBOXGUEST
190
191DECLR0VBGL(int) VbglR0InitPrimary(RTIOPORT portVMMDev, uintptr_t volatile *pMmioReq, VMMDevMemory *pVMMDevMemory, uint32_t *pfFeatures)
192{
193 int rc;
194
195# ifdef RT_OS_WINDOWS /** @todo r=bird: this doesn't make sense. Is there something special going on on windows? */
196 dprintf(("vbglInit: starts g_vbgldata.status %d\n", g_vbgldata.status));
197
198 if ( g_vbgldata.status == VbglStatusInitializing
199 || g_vbgldata.status == VbglStatusReady)
200 {
201 /* Initialization is already in process. */
202 return VINF_SUCCESS;
203 }
204# else
205 dprintf(("vbglInit: starts\n"));
206# endif
207
208 rc = vbglR0InitCommon();
209 if (RT_SUCCESS(rc))
210 {
211 g_vbgldata.portVMMDev = portVMMDev;
212 g_vbgldata.pVMMDevMemory = pVMMDevMemory;
213 g_vbgldata.pMmioReq = pMmioReq;
214
215 /*
216 * Initialize the physical heap, only allocate memory below 4GiB if the new
217 * MMIO interface isn't available and we are using a 32-bit OUT instruction to pass a block
218 * physical address to the host.
219 */
220 rc = VbglR0PhysHeapInit(g_vbgldata.pMmioReq == NULL ? _4G - 1 : NIL_RTHCPHYS /*HCPhysMax*/);
221 if (RT_SUCCESS(rc))
222 {
223 g_vbgldata.status = VbglStatusReady;
224
225 vbglR0QueryHostVersion();
226 *pfFeatures = g_vbgldata.hostVersion.features;
227 return VINF_SUCCESS;
228 }
229 else
230 {
231 LogRel(("VbglR0InitPrimary: VbglR0PhysHeapInit() -> %Rrc\n", rc));
232 g_vbgldata.status = VbglStatusNotInitialized;
233 }
234 }
235
236 g_vbgldata.status = VbglStatusNotInitialized;
237 return rc;
238}
239
240DECLR0VBGL(void) VbglR0TerminatePrimary(void)
241{
242 vbglR0TerminateCommon();
243}
244
245
246#else /* !VBGL_VBOXGUEST */
247
248DECLR0VBGL(int) VbglR0InitClient(void)
249{
250 int rc;
251
252 /** @todo r=bird: explain why we need to be doing this, please... */
253 if ( g_vbgldata.status == VbglStatusInitializing
254 || g_vbgldata.status == VbglStatusReady)
255 {
256 /* Initialization is already in process. */
257 return VINF_SUCCESS;
258 }
259
260 rc = vbglR0InitCommon();
261 if (RT_SUCCESS(rc))
262 {
263# ifdef VBGLDATA_USE_FAST_MUTEX
264 rc = RTSemFastMutexCreate(&g_vbgldata.hMtxIdcSetup);
265# else
266 rc = RTSemMutexCreate(&g_vbgldata.hMtxIdcSetup);
267# endif
268 if (RT_SUCCESS(rc))
269 {
270 /* Try to obtain VMMDev port via IOCTL to VBoxGuest main driver. */
271 vbglR0QueryDriverInfo();
272
273# ifdef VBOX_WITH_HGCM
274 rc = VbglR0HGCMInit();
275# endif
276 if (RT_SUCCESS(rc))
277 return VINF_SUCCESS;
278
279# ifdef VBGLDATA_USE_FAST_MUTEX
280 RTSemFastMutexDestroy(g_vbgldata.hMtxIdcSetup);
281 g_vbgldata.hMtxIdcSetup = NIL_RTSEMFASTMUTEX;
282# else
283 RTSemMutexDestroy(g_vbgldata.hMtxIdcSetup);
284 g_vbgldata.hMtxIdcSetup = NIL_RTSEMMUTEX;
285# endif
286 }
287 vbglR0TerminateCommon();
288 }
289
290 return rc;
291}
292
293DECLR0VBGL(void) VbglR0TerminateClient(void)
294{
295# ifdef VBOX_WITH_HGCM
296 VbglR0HGCMTerminate();
297# endif
298
299 /* driver open could fail, which does not prevent VbglInit from succeeding,
300 * close the driver only if it is opened */
301 VbglR0IdcClose(&g_vbgldata.IdcHandle);
302# ifdef VBGLDATA_USE_FAST_MUTEX
303 RTSemFastMutexDestroy(g_vbgldata.hMtxIdcSetup);
304 g_vbgldata.hMtxIdcSetup = NIL_RTSEMFASTMUTEX;
305# else
306 RTSemMutexDestroy(g_vbgldata.hMtxIdcSetup);
307 g_vbgldata.hMtxIdcSetup = NIL_RTSEMMUTEX;
308# endif
309
310 /* note: do vbglR0TerminateCommon as a last step since it zeroez up the g_vbgldata
311 * conceptually, doing vbglR0TerminateCommon last is correct
312 * since this is the reverse order to how init is done */
313 vbglR0TerminateCommon();
314}
315
316
317int VBOXCALL vbglR0QueryIdcHandle(PVBGLIDCHANDLE *ppIdcHandle)
318{
319 if (g_vbgldata.status == VbglStatusReady)
320 { /* likely */ }
321 else
322 {
323 vbglR0QueryDriverInfo();
324 if (g_vbgldata.status != VbglStatusReady)
325 {
326 *ppIdcHandle = NULL;
327 return VERR_TRY_AGAIN;
328 }
329 }
330
331 *ppIdcHandle = &g_vbgldata.IdcHandle;
332 return VINF_SUCCESS;
333}
334
335
336DECLR0VBGL(int) VbglR0QueryHostFeatures(uint32_t *pfHostFeatures)
337{
338 if (g_vbgldata.status == VbglStatusReady)
339 *pfHostFeatures = g_vbgldata.hostVersion.features;
340 else
341 {
342 int rc = vbglR0QueryDriverInfo();
343 if (g_vbgldata.status != VbglStatusReady)
344 return rc;
345 *pfHostFeatures = g_vbgldata.hostVersion.features;
346 }
347
348 return VINF_SUCCESS;
349}
350
351#endif /* !VBGL_VBOXGUEST */
352
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use