VirtualBox

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

Last change on this file since 94369 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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