VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/VBoxPci/VBoxPci.c@ 107044

Last change on this file since 107044 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.7 KB
Line 
1/* $Id: VBoxPci.c 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VBoxPci - PCI card passthrough support (Host), Common Code.
4 */
5
6/*
7 * Copyright (C) 2011-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37/** @page pg_rawpci VBoxPci - host PCI support
38 *
39 * This is a kernel module that works as host proxy between guest and
40 * PCI hardware.
41 *
42 */
43
44#define LOG_GROUP LOG_GROUP_DEV_PCI_RAW
45#include <VBox/log.h>
46#include <VBox/err.h>
47#include <VBox/sup.h>
48#include <VBox/version.h>
49
50#include <iprt/string.h>
51#include <iprt/assert.h>
52#include <iprt/spinlock.h>
53#include <iprt/uuid.h>
54#include <iprt/asm.h>
55#include <iprt/mem.h>
56
57#include "VBoxPciInternal.h"
58
59
60#define DEVPORT_2_VBOXRAWPCIINS(pPort) \
61 ( (PVBOXRAWPCIINS)((uint8_t *)pPort - RT_OFFSETOF(VBOXRAWPCIINS, DevPort)) )
62
63
64/**
65 * Implements the SUPDRV component factor interface query method.
66 *
67 * @returns Pointer to an interface. NULL if not supported.
68 *
69 * @param pSupDrvFactory Pointer to the component factory registration structure.
70 * @param pSession The session - unused.
71 * @param pszInterfaceUuid The factory interface id.
72 */
73static DECLCALLBACK(void *) vboxPciQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
74{
75 PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, SupDrvFactory));
76
77 /*
78 * Convert the UUID strings and compare them.
79 */
80 RTUUID UuidReq;
81 int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
82 if (RT_SUCCESS(rc))
83 {
84 if (!RTUuidCompareStr(&UuidReq, RAWPCIFACTORY_UUID_STR))
85 {
86 ASMAtomicIncS32(&pGlobals->cFactoryRefs);
87 return &pGlobals->RawPciFactory;
88 }
89 }
90 else
91 Log(("VBoxRawPci: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
92
93 return NULL;
94}
95DECLINLINE(int) vboxPciDevLock(PVBOXRAWPCIINS pThis)
96{
97#ifdef VBOX_WITH_SHARED_PCI_INTERRUPTS
98 RTSpinlockAcquire(pThis->hSpinlock);
99 return VINF_SUCCESS;
100#else
101 int rc = RTSemFastMutexRequest(pThis->hFastMtx);
102
103 AssertRC(rc);
104 return rc;
105#endif
106}
107
108DECLINLINE(void) vboxPciDevUnlock(PVBOXRAWPCIINS pThis)
109{
110#ifdef VBOX_WITH_SHARED_PCI_INTERRUPTS
111 RTSpinlockRelease(pThis->hSpinlock);
112#else
113 RTSemFastMutexRelease(pThis->hFastMtx);
114#endif
115}
116
117DECLINLINE(int) vboxPciVmLock(PVBOXRAWPCIDRVVM pThis)
118{
119 int rc = RTSemFastMutexRequest(pThis->hFastMtx);
120 AssertRC(rc);
121 return rc;
122}
123
124DECLINLINE(void) vboxPciVmUnlock(PVBOXRAWPCIDRVVM pThis)
125{
126 RTSemFastMutexRelease(pThis->hFastMtx);
127}
128
129DECLINLINE(int) vboxPciGlobalsLock(PVBOXRAWPCIGLOBALS pGlobals)
130{
131 int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
132 AssertRC(rc);
133 return rc;
134}
135
136DECLINLINE(void) vboxPciGlobalsUnlock(PVBOXRAWPCIGLOBALS pGlobals)
137{
138 RTSemFastMutexRelease(pGlobals->hFastMtx);
139}
140
141static PVBOXRAWPCIINS vboxPciFindInstanceLocked(PVBOXRAWPCIGLOBALS pGlobals, uint32_t iHostAddress)
142{
143 PVBOXRAWPCIINS pCur;
144 for (pCur = pGlobals->pInstanceHead; pCur != NULL; pCur = pCur->pNext)
145 {
146 if (iHostAddress == pCur->HostPciAddress)
147 return pCur;
148 }
149 return NULL;
150}
151
152static void vboxPciUnlinkInstanceLocked(PVBOXRAWPCIGLOBALS pGlobals, PVBOXRAWPCIINS pToUnlink)
153{
154 if (pGlobals->pInstanceHead == pToUnlink)
155 pGlobals->pInstanceHead = pToUnlink->pNext;
156 else
157 {
158 PVBOXRAWPCIINS pCur;
159 for (pCur = pGlobals->pInstanceHead; pCur != NULL; pCur = pCur->pNext)
160 {
161 if (pCur->pNext == pToUnlink)
162 {
163 pCur->pNext = pToUnlink->pNext;
164 break;
165 }
166 }
167 }
168 pToUnlink->pNext = NULL;
169}
170
171
172#if 0 /** @todo r=bird: Who the heck is supposed to call this?!? */
173DECLHIDDEN(void) vboxPciDevCleanup(PVBOXRAWPCIINS pThis)
174{
175 pThis->DevPort.pfnDeinit(&pThis->DevPort, 0);
176
177 if (pThis->hFastMtx)
178 {
179 RTSemFastMutexDestroy(pThis->hFastMtx);
180 pThis->hFastMtx = NIL_RTSEMFASTMUTEX;
181 }
182
183 if (pThis->hSpinlock)
184 {
185 RTSpinlockDestroy(pThis->hSpinlock);
186 pThis->hSpinlock = NIL_RTSPINLOCK;
187 }
188
189 vboxPciGlobalsLock(pThis->pGlobals);
190 vboxPciUnlinkInstanceLocked(pThis->pGlobals, pThis);
191 vboxPciGlobalsUnlock(pThis->pGlobals);
192}
193#endif
194
195
196/**
197 * @interface_method_impl{RAWPCIDEVPORT,pfnInit}
198 */
199static DECLCALLBACK(int) vboxPciDevInit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
200{
201 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
202 int rc;
203
204 vboxPciDevLock(pThis);
205
206 rc = vboxPciOsDevInit(pThis, fFlags);
207
208 vboxPciDevUnlock(pThis);
209
210 return rc;
211}
212
213/**
214 * @interface_method_impl{RAWPCIDEVPORT,pfnDeinit}
215 */
216static DECLCALLBACK(int) vboxPciDevDeinit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
217{
218 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
219 int rc;
220
221 vboxPciDevLock(pThis);
222
223 if (pThis->IrqHandler.pfnIrqHandler)
224 {
225 vboxPciOsDevUnregisterIrqHandler(pThis, pThis->IrqHandler.iHostIrq);
226 pThis->IrqHandler.iHostIrq = 0;
227 pThis->IrqHandler.pfnIrqHandler = NULL;
228 }
229
230 rc = vboxPciOsDevDeinit(pThis, fFlags);
231
232 vboxPciDevUnlock(pThis);
233
234 return rc;
235}
236
237
238/**
239 * @interface_method_impl{RAWPCIDEVPORT,pfnDestroy}
240 */
241static DECLCALLBACK(int) vboxPciDevDestroy(PRAWPCIDEVPORT pPort)
242{
243 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
244 int rc;
245
246 rc = vboxPciOsDevDestroy(pThis);
247 if (rc == VINF_SUCCESS)
248 {
249 if (pThis->hFastMtx)
250 {
251 RTSemFastMutexDestroy(pThis->hFastMtx);
252 pThis->hFastMtx = NIL_RTSEMFASTMUTEX;
253 }
254
255 if (pThis->hSpinlock)
256 {
257 RTSpinlockDestroy(pThis->hSpinlock);
258 pThis->hSpinlock = NIL_RTSPINLOCK;
259 }
260
261 vboxPciGlobalsLock(pThis->pGlobals);
262 vboxPciUnlinkInstanceLocked(pThis->pGlobals, pThis);
263 vboxPciGlobalsUnlock(pThis->pGlobals);
264
265 RTMemFree(pThis);
266 }
267
268 return rc;
269}
270/**
271 * @interface_method_impl{RAWPCIDEVPORT,pfnGetRegionInfo}
272 */
273static DECLCALLBACK(int) vboxPciDevGetRegionInfo(PRAWPCIDEVPORT pPort,
274 int32_t iRegion,
275 RTHCPHYS *pRegionStart,
276 uint64_t *pu64RegionSize,
277 bool *pfPresent,
278 uint32_t *pfFlags)
279{
280 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
281 int rc;
282
283 vboxPciDevLock(pThis);
284
285 rc = vboxPciOsDevGetRegionInfo(pThis, iRegion,
286 pRegionStart, pu64RegionSize,
287 pfPresent, pfFlags);
288 vboxPciDevUnlock(pThis);
289
290 return rc;
291}
292
293/**
294 * @interface_method_impl{RAWPCIDEVPORT,pfnMapRegion}
295 */
296static DECLCALLBACK(int) vboxPciDevMapRegion(PRAWPCIDEVPORT pPort,
297 int32_t iRegion,
298 RTHCPHYS RegionStart,
299 uint64_t u64RegionSize,
300 int32_t fFlags,
301 RTR0PTR *pRegionBaseR0)
302{
303 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
304 int rc;
305
306 vboxPciDevLock(pThis);
307
308 rc = vboxPciOsDevMapRegion(pThis, iRegion, RegionStart, u64RegionSize, fFlags, pRegionBaseR0);
309
310 vboxPciDevUnlock(pThis);
311
312 return rc;
313}
314
315/**
316 * @interface_method_impl{RAWPCIDEVPORT,pfnUnmapRegion}
317 */
318static DECLCALLBACK(int) vboxPciDevUnmapRegion(PRAWPCIDEVPORT pPort,
319 int32_t iRegion,
320 RTHCPHYS RegionStart,
321 uint64_t u64RegionSize,
322 RTR0PTR RegionBase)
323{
324 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
325 int rc;
326
327 vboxPciDevLock(pThis);
328
329 rc = vboxPciOsDevUnmapRegion(pThis, iRegion, RegionStart, u64RegionSize, RegionBase);
330
331 vboxPciDevUnlock(pThis);
332
333 return rc;
334}
335
336/**
337 * @interface_method_impl{RAWPCIDEVPORT,pfnPciCfgRead}
338 */
339static DECLCALLBACK(int) vboxPciDevPciCfgRead(PRAWPCIDEVPORT pPort,
340 uint32_t Register,
341 PCIRAWMEMLOC *pValue)
342{
343 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
344 int rc;
345
346 vboxPciDevLock(pThis);
347
348 rc = vboxPciOsDevPciCfgRead(pThis, Register, pValue);
349
350 vboxPciDevUnlock(pThis);
351
352 return rc;
353}
354
355/**
356 * @interface_method_impl{RAWPCIDEVPORT,pfnPciCfgWrite}
357 */
358static DECLCALLBACK(int) vboxPciDevPciCfgWrite(PRAWPCIDEVPORT pPort,
359 uint32_t Register,
360 PCIRAWMEMLOC *pValue)
361{
362 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
363 int rc;
364
365 vboxPciDevLock(pThis);
366
367 rc = vboxPciOsDevPciCfgWrite(pThis, Register, pValue);
368
369 vboxPciDevUnlock(pThis);
370
371 return rc;
372}
373
374static DECLCALLBACK(int) vboxPciDevRegisterIrqHandler(PRAWPCIDEVPORT pPort,
375 PFNRAWPCIISR pfnHandler,
376 void* pIrqContext,
377 PCIRAWISRHANDLE *phIsr)
378{
379 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
380 int rc;
381 int32_t iHostIrq = 0;
382
383 if (pfnHandler == NULL)
384 return VERR_INVALID_PARAMETER;
385
386 vboxPciDevLock(pThis);
387
388 if (pThis->IrqHandler.pfnIrqHandler)
389 {
390 rc = VERR_ALREADY_EXISTS;
391 }
392 else
393 {
394 rc = vboxPciOsDevRegisterIrqHandler(pThis, pfnHandler, pIrqContext, &iHostIrq);
395 if (RT_SUCCESS(rc))
396 {
397 *phIsr = 0xcafe0000;
398 pThis->IrqHandler.iHostIrq = iHostIrq;
399 pThis->IrqHandler.pfnIrqHandler = pfnHandler;
400 pThis->IrqHandler.pIrqContext = pIrqContext;
401 }
402 }
403
404 vboxPciDevUnlock(pThis);
405
406 return rc;
407}
408
409static DECLCALLBACK(int) vboxPciDevUnregisterIrqHandler(PRAWPCIDEVPORT pPort,
410 PCIRAWISRHANDLE hIsr)
411{
412 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
413 int rc;
414
415 if (hIsr != 0xcafe0000)
416 return VERR_INVALID_PARAMETER;
417
418 vboxPciDevLock(pThis);
419
420 rc = vboxPciOsDevUnregisterIrqHandler(pThis, pThis->IrqHandler.iHostIrq);
421 if (RT_SUCCESS(rc))
422 {
423 pThis->IrqHandler.pfnIrqHandler = NULL;
424 pThis->IrqHandler.pIrqContext = NULL;
425 pThis->IrqHandler.iHostIrq = 0;
426 }
427 vboxPciDevUnlock(pThis);
428
429 return rc;
430}
431
432static DECLCALLBACK(int) vboxPciDevPowerStateChange(PRAWPCIDEVPORT pPort,
433 PCIRAWPOWERSTATE aState,
434 uint64_t *pu64Param)
435{
436 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
437 int rc;
438
439 vboxPciDevLock(pThis);
440
441 rc = vboxPciOsDevPowerStateChange(pThis, aState);
442
443 switch (aState)
444 {
445 case PCIRAW_POWER_ON:
446 /*
447 * Let virtual device know about VM caps.
448 */
449 *pu64Param = VBOX_DRV_VMDATA(pThis)->pPerVmData->fVmCaps;
450 break;
451 default:
452 pu64Param = 0;
453 break;
454 }
455
456
457 vboxPciDevUnlock(pThis);
458
459 return rc;
460}
461
462/**
463 * Creates a new instance.
464 *
465 * @returns VBox status code.
466 * @param pGlobals The globals.
467 * @param u32HostAddress Host address.
468 * @param fFlags Flags.
469 * @param pVmCtx VM context.
470 * @param ppDevPort Where to store the pointer to our port interface.
471 * @param pfDevFlags The device flags.
472 */
473static int vboxPciNewInstance(PVBOXRAWPCIGLOBALS pGlobals,
474 uint32_t u32HostAddress,
475 uint32_t fFlags,
476 PRAWPCIPERVM pVmCtx,
477 PRAWPCIDEVPORT *ppDevPort,
478 uint32_t *pfDevFlags)
479{
480 int rc;
481 PVBOXRAWPCIINS pNew = (PVBOXRAWPCIINS)RTMemAllocZ(sizeof(*pNew));
482 if (!pNew)
483 return VERR_NO_MEMORY;
484
485 pNew->pGlobals = pGlobals;
486 pNew->hSpinlock = NIL_RTSPINLOCK;
487 pNew->cRefs = 1;
488 pNew->pNext = NULL;
489 pNew->HostPciAddress = u32HostAddress;
490 pNew->pVmCtx = pVmCtx;
491
492 pNew->DevPort.u32Version = RAWPCIDEVPORT_VERSION;
493
494 pNew->DevPort.pfnInit = vboxPciDevInit;
495 pNew->DevPort.pfnDeinit = vboxPciDevDeinit;
496 pNew->DevPort.pfnDestroy = vboxPciDevDestroy;
497 pNew->DevPort.pfnGetRegionInfo = vboxPciDevGetRegionInfo;
498 pNew->DevPort.pfnMapRegion = vboxPciDevMapRegion;
499 pNew->DevPort.pfnUnmapRegion = vboxPciDevUnmapRegion;
500 pNew->DevPort.pfnPciCfgRead = vboxPciDevPciCfgRead;
501 pNew->DevPort.pfnPciCfgWrite = vboxPciDevPciCfgWrite;
502 pNew->DevPort.pfnPciCfgRead = vboxPciDevPciCfgRead;
503 pNew->DevPort.pfnPciCfgWrite = vboxPciDevPciCfgWrite;
504 pNew->DevPort.pfnRegisterIrqHandler = vboxPciDevRegisterIrqHandler;
505 pNew->DevPort.pfnUnregisterIrqHandler = vboxPciDevUnregisterIrqHandler;
506 pNew->DevPort.pfnPowerStateChange = vboxPciDevPowerStateChange;
507 pNew->DevPort.u32VersionEnd = RAWPCIDEVPORT_VERSION;
508
509 rc = RTSpinlockCreate(&pNew->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "VBoxPCI");
510 if (RT_SUCCESS(rc))
511 {
512 rc = RTSemFastMutexCreate(&pNew->hFastMtx);
513 if (RT_SUCCESS(rc))
514 {
515 rc = pNew->DevPort.pfnInit(&pNew->DevPort, fFlags);
516 if (RT_SUCCESS(rc))
517 {
518 *ppDevPort = &pNew->DevPort;
519
520 pNew->pNext = pGlobals->pInstanceHead;
521 pGlobals->pInstanceHead = pNew;
522 }
523 else
524 {
525 RTSemFastMutexDestroy(pNew->hFastMtx);
526 RTSpinlockDestroy(pNew->hSpinlock);
527 RTMemFree(pNew);
528 }
529 }
530 }
531
532 return rc;
533}
534
535/**
536 * @interface_method_impl{RAWPCIFACTORY,pfnCreateAndConnect}
537 */
538static DECLCALLBACK(int) vboxPciFactoryCreateAndConnect(PRAWPCIFACTORY pFactory,
539 uint32_t u32HostAddress,
540 uint32_t fFlags,
541 PRAWPCIPERVM pVmCtx,
542 PRAWPCIDEVPORT *ppDevPort,
543 uint32_t *pfDevFlags)
544{
545 PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, RawPciFactory));
546 int rc;
547
548 LogFlow(("vboxPciFactoryCreateAndConnect: PCI=%x fFlags=%#x\n", u32HostAddress, fFlags));
549 Assert(pGlobals->cFactoryRefs > 0);
550 rc = vboxPciGlobalsLock(pGlobals);
551 AssertRCReturn(rc, rc);
552
553 /* First search if there's no existing instance with same host device
554 * address - if so - we cannot continue.
555 */
556 if (vboxPciFindInstanceLocked(pGlobals, u32HostAddress) != NULL)
557 {
558 rc = VERR_RESOURCE_BUSY;
559 goto unlock;
560 }
561
562 rc = vboxPciNewInstance(pGlobals, u32HostAddress, fFlags, pVmCtx, ppDevPort, pfDevFlags);
563
564unlock:
565 vboxPciGlobalsUnlock(pGlobals);
566
567 return rc;
568}
569
570/**
571 * @interface_method_impl{RAWPCIFACTORY,pfnRelease}
572 */
573static DECLCALLBACK(void) vboxPciFactoryRelease(PRAWPCIFACTORY pFactory)
574{
575 PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, RawPciFactory));
576
577 int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
578 Assert(cRefs >= 0); NOREF(cRefs);
579 LogFlow(("vboxPciFactoryRelease: cRefs=%d (new)\n", cRefs));
580}
581
582/**
583 * @interface_method_impl{RAWPCIFACTORY,pfnInitVm}
584 */
585static DECLCALLBACK(int) vboxPciFactoryInitVm(PRAWPCIFACTORY pFactory,
586 PVM pVM,
587 PRAWPCIPERVM pVmData)
588{
589 PVBOXRAWPCIDRVVM pThis = (PVBOXRAWPCIDRVVM)RTMemAllocZ(sizeof(VBOXRAWPCIDRVVM));
590 int rc;
591
592 if (!pThis)
593 return VERR_NO_MEMORY;
594
595 rc = RTSemFastMutexCreate(&pThis->hFastMtx);
596 if (RT_SUCCESS(rc))
597 {
598 rc = vboxPciOsInitVm(pThis, pVM, pVmData);
599
600 if (RT_SUCCESS(rc))
601 {
602#ifdef VBOX_WITH_IOMMU
603 /* If IOMMU notification routine in pVmData->pfnContigMemInfo
604 is set - we have functional IOMMU hardware. */
605 if (pVmData->pfnContigMemInfo)
606 pVmData->fVmCaps |= PCIRAW_VMFLAGS_HAS_IOMMU;
607#endif
608 pThis->pPerVmData = pVmData;
609 pVmData->pDriverData = pThis;
610 return VINF_SUCCESS;
611 }
612
613 RTSemFastMutexDestroy(pThis->hFastMtx);
614 pThis->hFastMtx = NIL_RTSEMFASTMUTEX;
615 RTMemFree(pThis);
616 }
617
618 return rc;
619}
620
621/**
622 * @interface_method_impl{RAWPCIFACTORY,pfnDeinitVm}
623 */
624static DECLCALLBACK(void) vboxPciFactoryDeinitVm(PRAWPCIFACTORY pFactory,
625 PVM pVM,
626 PRAWPCIPERVM pVmData)
627{
628 if (pVmData->pDriverData)
629 {
630 PVBOXRAWPCIDRVVM pThis = (PVBOXRAWPCIDRVVM)pVmData->pDriverData;
631
632#ifdef VBOX_WITH_IOMMU
633 /* If we have IOMMU, need to unmap all guest's physical pages from IOMMU on VM termination. */
634#endif
635
636 vboxPciOsDeinitVm(pThis, pVM);
637
638 if (pThis->hFastMtx)
639 {
640 RTSemFastMutexDestroy(pThis->hFastMtx);
641 pThis->hFastMtx = NIL_RTSEMFASTMUTEX;
642 }
643
644 RTMemFree(pThis);
645 pVmData->pDriverData = NULL;
646 }
647}
648
649
650static bool vboxPciCanUnload(PVBOXRAWPCIGLOBALS pGlobals)
651{
652 int rc = vboxPciGlobalsLock(pGlobals);
653 bool fRc = !pGlobals->pInstanceHead
654 && pGlobals->cFactoryRefs <= 0;
655 vboxPciGlobalsUnlock(pGlobals);
656 AssertRC(rc);
657 return fRc;
658}
659
660
661static int vboxPciInitIdc(PVBOXRAWPCIGLOBALS pGlobals)
662{
663 int rc;
664 Assert(!pGlobals->fIDCOpen);
665
666 /*
667 * Establish a connection to SUPDRV and register our component factory.
668 */
669 rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
670 if (RT_SUCCESS(rc))
671 {
672 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
673 if (RT_SUCCESS(rc))
674 {
675 pGlobals->fIDCOpen = true;
676 Log(("VBoxRawPci: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
677 return rc;
678 }
679
680 /* bail out. */
681 LogRel(("VBoxRawPci: Failed to register component factory, rc=%Rrc\n", rc));
682 SUPR0IdcClose(&pGlobals->SupDrvIDC);
683 }
684
685 return rc;
686}
687
688
689/**
690 * Try to close the IDC connection to SUPDRV if established.
691 *
692 * @returns VBox status code.
693 * @retval VINF_SUCCESS on success.
694 * @retval VERR_WRONG_ORDER if we're busy.
695 *
696 * @param pGlobals Pointer to the globals.
697 */
698static int vboxPciDeleteIdc(PVBOXRAWPCIGLOBALS pGlobals)
699{
700 int rc;
701
702 Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
703
704 /*
705 * Check before trying to deregister the factory.
706 */
707 if (!vboxPciCanUnload(pGlobals))
708 return VERR_WRONG_ORDER;
709
710 if (!pGlobals->fIDCOpen)
711 rc = VINF_SUCCESS;
712 else
713 {
714 /*
715 * Disconnect from SUPDRV.
716 */
717 rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
718 AssertRC(rc);
719 SUPR0IdcClose(&pGlobals->SupDrvIDC);
720 pGlobals->fIDCOpen = false;
721 }
722
723 return rc;
724}
725
726
727/**
728 * Initializes the globals.
729 *
730 * @returns VBox status code.
731 * @param pGlobals Pointer to the globals.
732 */
733static int vboxPciInitGlobals(PVBOXRAWPCIGLOBALS pGlobals)
734{
735 /*
736 * Initialize the common portions of the structure.
737 */
738 int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
739 if (RT_SUCCESS(rc))
740 {
741 pGlobals->pInstanceHead = NULL;
742 pGlobals->RawPciFactory.pfnRelease = vboxPciFactoryRelease;
743 pGlobals->RawPciFactory.pfnCreateAndConnect = vboxPciFactoryCreateAndConnect;
744 pGlobals->RawPciFactory.pfnInitVm = vboxPciFactoryInitVm;
745 pGlobals->RawPciFactory.pfnDeinitVm = vboxPciFactoryDeinitVm;
746 memcpy(pGlobals->SupDrvFactory.szName, "VBoxRawPci", sizeof("VBoxRawPci"));
747 pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxPciQueryFactoryInterface;
748 pGlobals->fIDCOpen = false;
749 }
750 return rc;
751}
752
753
754/**
755 * Deletes the globals.
756 *
757 * @param pGlobals Pointer to the globals.
758 */
759static void vboxPciDeleteGlobals(PVBOXRAWPCIGLOBALS pGlobals)
760{
761 Assert(!pGlobals->fIDCOpen);
762
763 /*
764 * Release resources.
765 */
766 if (pGlobals->hFastMtx)
767 {
768 RTSemFastMutexDestroy(pGlobals->hFastMtx);
769 pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
770 }
771}
772
773
774int vboxPciInit(PVBOXRAWPCIGLOBALS pGlobals)
775{
776
777 /*
778 * Initialize the common portions of the structure.
779 */
780 int rc = vboxPciInitGlobals(pGlobals);
781 if (RT_SUCCESS(rc))
782 {
783 rc = vboxPciInitIdc(pGlobals);
784 if (RT_SUCCESS(rc))
785 return rc;
786
787 /* bail out. */
788 vboxPciDeleteGlobals(pGlobals);
789 }
790
791 return rc;
792}
793
794void vboxPciShutdown(PVBOXRAWPCIGLOBALS pGlobals)
795{
796 int rc = vboxPciDeleteIdc(pGlobals);
797 if (RT_SUCCESS(rc))
798 vboxPciDeleteGlobals(pGlobals);
799}
800
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