VirtualBox

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

Last change on this file since 36261 was 36260, checked in by vboxsync, 14 years ago

PCI: lifetime work, fixed issues with multiple PCI devices attached to one guest

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.0 KB
Line 
1/* $Id $ */
2/** @file
3 * VBoxPci - PCI card passthrough support (Host), Common Code.
4 */
5
6/*
7 * Copyright (C) 2011 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
18/** @page pg_rawpci VBoxPci - host PCI support
19 *
20 * This is a kernel module that works as host proxy between guest and
21 * PCI hardware.
22 *
23 */
24
25#define LOG_GROUP LOG_GROUP_DEV_PCI_RAW
26#include <VBox/log.h>
27#include <VBox/err.h>
28#include <VBox/sup.h>
29#include <VBox/version.h>
30
31#include <iprt/string.h>
32#include <iprt/assert.h>
33#include <iprt/spinlock.h>
34#include <iprt/uuid.h>
35#include <iprt/asm.h>
36#include <iprt/mem.h>
37
38#include "VBoxPciInternal.h"
39
40
41#define DEVPORT_2_VBOXRAWPCIINS(pPort) \
42 ( (PVBOXRAWPCIINS)((uint8_t *)pPort - RT_OFFSETOF(VBOXRAWPCIINS, DevPort)) )
43
44
45/**
46 * Implements the SUPDRV component factor interface query method.
47 *
48 * @returns Pointer to an interface. NULL if not supported.
49 *
50 * @param pSupDrvFactory Pointer to the component factory registration structure.
51 * @param pSession The session - unused.
52 * @param pszInterfaceUuid The factory interface id.
53 */
54static DECLCALLBACK(void *) vboxPciQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
55{
56 PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, SupDrvFactory));
57
58 /*
59 * Convert the UUID strings and compare them.
60 */
61 RTUUID UuidReq;
62 int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
63 if (RT_SUCCESS(rc))
64 {
65 if (!RTUuidCompareStr(&UuidReq, RAWPCIFACTORY_UUID_STR))
66 {
67 ASMAtomicIncS32(&pGlobals->cFactoryRefs);
68 return &pGlobals->RawPciFactory;
69 }
70 }
71 else
72 Log(("VBoxRawPci: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
73
74 return NULL;
75}
76
77DECLINLINE(int) vboxPciDevLock(PVBOXRAWPCIINS pThis)
78{
79 int rc = RTSemFastMutexRequest(pThis->hFastMtx);
80 AssertRC(rc);
81 return rc;
82}
83
84DECLINLINE(void) vboxPciDevUnlock(PVBOXRAWPCIINS pThis)
85{
86 RTSemFastMutexRelease(pThis->hFastMtx);
87}
88
89DECLINLINE(int) vboxPciGlobalsLock(PVBOXRAWPCIGLOBALS pGlobals)
90{
91 int rc = RTSemFastMutexRequest(pGlobals->hFastMtx);
92 AssertRC(rc);
93 return rc;
94}
95
96DECLINLINE(void) vboxPciGlobalsUnlock(PVBOXRAWPCIGLOBALS pGlobals)
97{
98 RTSemFastMutexRelease(pGlobals->hFastMtx);
99}
100
101static PVBOXRAWPCIINS vboxPciFindInstanceLocked(PVBOXRAWPCIGLOBALS pGlobals, uint32_t iHostAddress)
102{
103 PVBOXRAWPCIINS pCur;
104 for (pCur = pGlobals->pInstanceHead; pCur != NULL; pCur = pCur->pNext)
105 {
106 if (iHostAddress == pCur->HostPciAddress)
107 return pCur;
108 }
109 return NULL;
110}
111
112static void vboxPciUnlinkInstanceLocked(PVBOXRAWPCIGLOBALS pGlobals, PVBOXRAWPCIINS pToUnlink)
113{
114 if (pGlobals->pInstanceHead == pToUnlink)
115 pGlobals->pInstanceHead = pToUnlink->pNext;
116 else
117 {
118 PVBOXRAWPCIINS pCur;
119 for (pCur = pGlobals->pInstanceHead; pCur != NULL; pCur = pCur->pNext)
120 {
121 if (pCur->pNext == pToUnlink)
122 {
123 pCur->pNext = pToUnlink->pNext;
124 break;
125 }
126 }
127 }
128 pToUnlink->pNext = NULL;
129}
130
131
132DECLHIDDEN(void) vboxPciDevCleanup(PVBOXRAWPCIINS pThis)
133{
134 pThis->DevPort.pfnDeinit(&pThis->DevPort, 0);
135
136 if (pThis->hFastMtx)
137 {
138 RTSemFastMutexDestroy(pThis->hFastMtx);
139 pThis->hFastMtx = NIL_RTSEMFASTMUTEX;
140 }
141
142 if (pThis->hSpinlock)
143 {
144 RTSpinlockDestroy(pThis->hSpinlock);
145 pThis->hSpinlock = NIL_RTSPINLOCK;
146 }
147
148 vboxPciGlobalsLock(pThis->pGlobals);
149 vboxPciUnlinkInstanceLocked(pThis->pGlobals, pThis);
150 vboxPciGlobalsUnlock(pThis->pGlobals);
151}
152
153
154/**
155 * @copydoc RAWPCIDEVPORT:: pfnInit
156 */
157DECLHIDDEN(int) vboxPciDevInit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
158{
159 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
160 int rc;
161
162 vboxPciDevLock(pThis);
163
164 rc = vboxPciOsDevInit(pThis, fFlags);
165
166 vboxPciDevUnlock(pThis);
167
168 return rc;
169}
170
171/**
172 * @copydoc RAWPCIDEVPORT:: pfnDeinit
173 */
174DECLHIDDEN(int) vboxPciDevDeinit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
175{
176 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
177 int rc;
178
179 /* Bit racy, better check under lock. */
180 if (pThis->iHostIrq != -1)
181 {
182 pPort->pfnUnregisterIrqHandler(pPort, pThis->iHostIrq);
183 pThis->iHostIrq = -1;
184 }
185
186 vboxPciDevLock(pThis);
187
188 rc = vboxPciOsDevDeinit(pThis, fFlags);
189
190 vboxPciDevUnlock(pThis);
191
192 return rc;
193}
194
195
196/**
197 * @copydoc RAWPCIDEVPORT:: pfnDestroy
198 */
199DECLHIDDEN(int) vboxPciDevDestroy(PRAWPCIDEVPORT pPort)
200{
201 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
202 int rc;
203
204 rc = vboxPciOsDevDestroy(pThis);
205 if (rc == VINF_SUCCESS)
206 {
207 if (pThis->hFastMtx)
208 {
209 RTSemFastMutexDestroy(pThis->hFastMtx);
210 pThis->hFastMtx = NIL_RTSEMFASTMUTEX;
211 }
212
213 if (pThis->hSpinlock)
214 {
215 RTSpinlockDestroy(pThis->hSpinlock);
216 pThis->hSpinlock = NIL_RTSPINLOCK;
217 }
218
219 vboxPciGlobalsLock(pThis->pGlobals);
220 vboxPciUnlinkInstanceLocked(pThis->pGlobals, pThis);
221 vboxPciGlobalsUnlock(pThis->pGlobals);
222
223 RTMemFree(pThis);
224 }
225
226 return rc;
227}
228/**
229 * @copydoc RAWPCIDEVPORT:: pfnGetRegionInfo
230 */
231DECLHIDDEN(int) vboxPciDevGetRegionInfo(PRAWPCIDEVPORT pPort,
232 int32_t iRegion,
233 RTHCPHYS *pRegionStart,
234 uint64_t *pu64RegionSize,
235 bool *pfPresent,
236 uint32_t *pfFlags)
237{
238 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
239 int rc;
240
241 vboxPciDevLock(pThis);
242
243 rc = vboxPciOsDevGetRegionInfo(pThis, iRegion,
244 pRegionStart, pu64RegionSize,
245 pfPresent, pfFlags);
246 vboxPciDevUnlock(pThis);
247
248 return rc;
249}
250
251/**
252 * @copydoc RAWPCIDEVPORT:: pfnMapRegion
253 */
254DECLHIDDEN(int) vboxPciDevMapRegion(PRAWPCIDEVPORT pPort,
255 int32_t iRegion,
256 RTHCPHYS RegionStart,
257 uint64_t u64RegionSize,
258 int32_t fFlags,
259 RTR0PTR *pRegionBase)
260{
261 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
262 int rc;
263
264 vboxPciDevLock(pThis);
265
266 rc = vboxPciOsDevMapRegion(pThis, iRegion, RegionStart, u64RegionSize, fFlags, pRegionBase);
267
268 vboxPciDevUnlock(pThis);
269
270 return rc;
271}
272
273/**
274 * @copydoc RAWPCIDEVPORT:: pfnUnapRegion
275 */
276DECLHIDDEN(int) vboxPciDevUnmapRegion(PRAWPCIDEVPORT pPort,
277 int32_t iRegion,
278 RTHCPHYS RegionStart,
279 uint64_t u64RegionSize,
280 RTR0PTR RegionBase)
281{
282 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
283 int rc;
284
285 vboxPciDevLock(pThis);
286
287 rc = vboxPciOsDevUnmapRegion(pThis, iRegion, RegionStart, u64RegionSize, RegionBase);
288
289 vboxPciDevUnlock(pThis);
290
291 return rc;
292}
293
294/**
295 * @copydoc RAWPCIDEVPORT:: pfnPciCfgRead
296 */
297DECLHIDDEN(int) vboxPciDevPciCfgRead(PRAWPCIDEVPORT pPort, uint32_t Register, PCIRAWMEMLOC *pValue)
298{
299 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
300
301 int rc;
302
303 vboxPciDevLock(pThis);
304
305 rc = vboxPciOsDevPciCfgRead(pThis, Register, pValue);
306
307 vboxPciDevUnlock(pThis);
308
309 return rc;
310}
311
312/**
313 * @copydoc RAWPCIDEVPORT:: pfnPciCfgWrite
314 */
315DECLHIDDEN(int) vboxPciDevPciCfgWrite(PRAWPCIDEVPORT pPort, uint32_t Register, PCIRAWMEMLOC *pValue)
316{
317 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
318 int rc;
319
320 vboxPciDevLock(pThis);
321
322 rc = vboxPciOsDevPciCfgWrite(pThis, Register, pValue);
323
324 vboxPciDevUnlock(pThis);
325
326 return rc;
327}
328
329DECLHIDDEN(int) vboxPciDevRegisterIrqHandler(PRAWPCIDEVPORT pPort, PFNRAWPCIISR pfnHandler, void* pIrqContext, int32_t *piHostIrq)
330{
331 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
332 int rc;
333
334 vboxPciDevLock(pThis);
335
336 pThis->pfnIrqHandler = pfnHandler;
337 pThis->pIrqContext = pIrqContext;
338 rc = vboxPciOsDevRegisterIrqHandler(pThis, pfnHandler, pIrqContext, piHostIrq);
339 if (RT_FAILURE(rc))
340 {
341 pThis->pfnIrqHandler = NULL;
342 pThis->pIrqContext = NULL;
343 pThis->iHostIrq = -1;
344 *piHostIrq = -1;
345 }
346 else
347 pThis->iHostIrq = *piHostIrq;
348
349 vboxPciDevUnlock(pThis);
350
351 return rc;
352}
353
354DECLHIDDEN(int) vboxPciDevUnregisterIrqHandler(PRAWPCIDEVPORT pPort, int32_t iHostIrq)
355{
356 PVBOXRAWPCIINS pThis = DEVPORT_2_VBOXRAWPCIINS(pPort);
357 int rc;
358
359 vboxPciDevLock(pThis);
360
361 Assert(iHostIrq == pThis->iHostIrq);
362 rc = vboxPciOsDevUnregisterIrqHandler(pThis, iHostIrq);
363 if (RT_SUCCESS(rc))
364 {
365 pThis->pfnIrqHandler = NULL;
366 pThis->pIrqContext = NULL;
367 pThis->iHostIrq = -1;
368 }
369 vboxPciDevUnlock(pThis);
370
371 return rc;
372}
373
374/**
375 * Creates a new instance.
376 *
377 * @returns VBox status code.
378 * @param pGlobals The globals.
379 * @param pszName The instance name.
380 * @param ppDevPort Where to store the pointer to our port interface.
381 */
382static int vboxPciNewInstance(PVBOXRAWPCIGLOBALS pGlobals,
383 uint32_t u32HostAddress,
384 uint32_t fFlags,
385 PRAWPCIDEVPORT *ppDevPort)
386{
387 int rc;
388 PVBOXRAWPCIINS pNew = (PVBOXRAWPCIINS)RTMemAllocZ(sizeof(*pNew));
389 if (!pNew)
390 return VERR_NO_MEMORY;
391
392 pNew->pGlobals = pGlobals;
393 pNew->hSpinlock = NIL_RTSPINLOCK;
394 pNew->cRefs = 1;
395 pNew->pNext = NULL;
396 pNew->HostPciAddress = u32HostAddress;
397 pNew->iHostIrq = -1;
398
399 pNew->DevPort.u32Version = RAWPCIDEVPORT_VERSION;
400
401 pNew->DevPort.pfnInit = vboxPciDevInit;
402 pNew->DevPort.pfnDeinit = vboxPciDevDeinit;
403 pNew->DevPort.pfnDestroy = vboxPciDevDestroy;
404 pNew->DevPort.pfnGetRegionInfo = vboxPciDevGetRegionInfo;
405 pNew->DevPort.pfnMapRegion = vboxPciDevMapRegion;
406 pNew->DevPort.pfnUnmapRegion = vboxPciDevUnmapRegion;
407 pNew->DevPort.pfnPciCfgRead = vboxPciDevPciCfgRead;
408 pNew->DevPort.pfnPciCfgWrite = vboxPciDevPciCfgWrite;
409 pNew->DevPort.pfnPciCfgRead = vboxPciDevPciCfgRead;
410 pNew->DevPort.pfnPciCfgWrite = vboxPciDevPciCfgWrite;
411 pNew->DevPort.pfnRegisterIrqHandler = vboxPciDevRegisterIrqHandler;
412 pNew->DevPort.pfnUnregisterIrqHandler = vboxPciDevUnregisterIrqHandler;
413 pNew->DevPort.u32VersionEnd = RAWPCIDEVPORT_VERSION;
414
415 rc = RTSpinlockCreate(&pNew->hSpinlock);
416
417 if (RT_SUCCESS(rc))
418 {
419 rc = RTSemFastMutexCreate(&pNew->hFastMtx);
420 if (RT_SUCCESS(rc))
421 {
422 rc = pNew->DevPort.pfnInit(&pNew->DevPort, fFlags);
423 if (RT_SUCCESS(rc))
424 {
425 *ppDevPort = &pNew->DevPort;
426
427 pNew->pNext = pGlobals->pInstanceHead;
428 pGlobals->pInstanceHead = pNew;
429 }
430 else
431 {
432 RTSemFastMutexDestroy(pNew->hFastMtx);
433 RTSpinlockDestroy(pNew->hSpinlock);
434 RTMemFree(pNew);
435 }
436 return rc;
437 }
438 }
439
440 return rc;
441}
442
443/**
444 * @copydoc RAWPCIFACTORY::pfnCreateAndConnect
445 */
446static DECLCALLBACK(int) vboxPciFactoryCreateAndConnect(PRAWPCIFACTORY pFactory,
447 uint32_t u32HostAddress,
448 uint32_t fFlags,
449 PRAWPCIDEVPORT *ppDevPort)
450{
451 PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, RawPciFactory));
452 int rc;
453
454 LogFlow(("vboxPciFactoryCreateAndConnect: PCI=%x fFlags=%#x\n", u32HostAddress, fFlags));
455 Assert(pGlobals->cFactoryRefs > 0);
456 rc = vboxPciGlobalsLock(pGlobals);
457 AssertRCReturn(rc, rc);
458
459 /* First search if there's no existing instance with same host device
460 * address - if so - we cannot continue.
461 */
462 if (vboxPciFindInstanceLocked(pGlobals, u32HostAddress) != NULL)
463 {
464 rc = VERR_RESOURCE_BUSY;
465 goto unlock;
466 }
467
468 rc = vboxPciNewInstance(pGlobals, u32HostAddress, fFlags, ppDevPort);
469
470unlock:
471 vboxPciGlobalsUnlock(pGlobals);
472
473 return rc;
474}
475
476/**
477 * @copydoc RAWPCIFACTORY::pfnRelease
478 */
479static DECLCALLBACK(void) vboxPciFactoryRelease(PRAWPCIFACTORY pFactory)
480{
481 PVBOXRAWPCIGLOBALS pGlobals = (PVBOXRAWPCIGLOBALS)((uint8_t *)pFactory - RT_OFFSETOF(VBOXRAWPCIGLOBALS, RawPciFactory));
482
483 int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
484 Assert(cRefs >= 0); NOREF(cRefs);
485 LogFlow(("vboxPciFactoryRelease: cRefs=%d (new)\n", cRefs));
486}
487
488static DECLHIDDEN(bool) vboxPciCanUnload(PVBOXRAWPCIGLOBALS pGlobals)
489{
490 int rc = vboxPciGlobalsLock(pGlobals);
491 bool fRc = !pGlobals->pInstanceHead
492 && pGlobals->cFactoryRefs <= 0;
493 vboxPciGlobalsUnlock(pGlobals);
494 AssertRC(rc);
495 return fRc;
496}
497
498
499static DECLHIDDEN(int) vboxPciInitIdc(PVBOXRAWPCIGLOBALS pGlobals)
500{
501 int rc;
502 Assert(!pGlobals->fIDCOpen);
503
504 /*
505 * Establish a connection to SUPDRV and register our component factory.
506 */
507 rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
508 if (RT_SUCCESS(rc))
509 {
510 rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
511 if (RT_SUCCESS(rc))
512 {
513 pGlobals->fIDCOpen = true;
514 Log(("VBoxRawPci: pSession=%p\n", SUPR0IdcGetSession(&pGlobals->SupDrvIDC)));
515 return rc;
516 }
517
518 /* bail out. */
519 LogRel(("VBoxRawPci: Failed to register component factory, rc=%Rrc\n", rc));
520 SUPR0IdcClose(&pGlobals->SupDrvIDC);
521 }
522
523 return rc;
524}
525
526/**
527 * Try to close the IDC connection to SUPDRV if established.
528 *
529 * @returns VBox status code.
530 * @retval VINF_SUCCESS on success.
531 * @retval VERR_WRONG_ORDER if we're busy.
532 *
533 * @param pGlobals Pointer to the globals.
534 */
535DECLHIDDEN(int) vboxPciDeleteIdc(PVBOXRAWPCIGLOBALS pGlobals)
536{
537 int rc;
538
539 Assert(pGlobals->hFastMtx != NIL_RTSEMFASTMUTEX);
540
541 /*
542 * Check before trying to deregister the factory.
543 */
544 if (!vboxPciCanUnload(pGlobals))
545 return VERR_WRONG_ORDER;
546
547 if (!pGlobals->fIDCOpen)
548 rc = VINF_SUCCESS;
549 else
550 {
551 /*
552 * Disconnect from SUPDRV.
553 */
554 rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
555 AssertRC(rc);
556 SUPR0IdcClose(&pGlobals->SupDrvIDC);
557 pGlobals->fIDCOpen = false;
558 }
559
560 return rc;
561}
562
563
564/**
565 * Initializes the globals.
566 *
567 * @returns VBox status code.
568 * @param pGlobals Pointer to the globals.
569 */
570DECLHIDDEN(int) vboxPciInitGlobals(PVBOXRAWPCIGLOBALS pGlobals)
571{
572 /*
573 * Initialize the common portions of the structure.
574 */
575 int rc = RTSemFastMutexCreate(&pGlobals->hFastMtx);
576 if (RT_SUCCESS(rc))
577 {
578 pGlobals->pInstanceHead = NULL;
579 pGlobals->RawPciFactory.pfnRelease = vboxPciFactoryRelease;
580 pGlobals->RawPciFactory.pfnCreateAndConnect = vboxPciFactoryCreateAndConnect;
581 memcpy(pGlobals->SupDrvFactory.szName, "VBoxRawPci", sizeof("VBoxRawPci"));
582 pGlobals->SupDrvFactory.pfnQueryFactoryInterface = vboxPciQueryFactoryInterface;
583 pGlobals->fIDCOpen = false;
584 }
585 return rc;
586}
587
588
589/**
590 * Deletes the globals.
591 *
592 *
593 * @param pGlobals Pointer to the globals.
594 */
595DECLHIDDEN(void) vboxPciDeleteGlobals(PVBOXRAWPCIGLOBALS pGlobals)
596{
597 Assert(!pGlobals->fIDCOpen);
598
599 /*
600 * Release resources.
601 */
602 if (pGlobals->hFastMtx)
603 {
604 RTSemFastMutexDestroy(pGlobals->hFastMtx);
605 pGlobals->hFastMtx = NIL_RTSEMFASTMUTEX;
606 }
607}
608
609
610int vboxPciInit(PVBOXRAWPCIGLOBALS pGlobals)
611{
612
613 /*
614 * Initialize the common portions of the structure.
615 */
616 int rc = vboxPciInitGlobals(pGlobals);
617 if (RT_SUCCESS(rc))
618 {
619 rc = vboxPciInitIdc(pGlobals);
620 if (RT_SUCCESS(rc))
621 return rc;
622
623 /* bail out. */
624 vboxPciDeleteGlobals(pGlobals);
625 }
626
627 return rc;
628}
629
630void vboxPciShutdown(PVBOXRAWPCIGLOBALS pGlobals)
631{
632 int rc = vboxPciDeleteIdc(pGlobals);
633
634 if (RT_SUCCESS(rc))
635 vboxPciDeleteGlobals(pGlobals);
636}
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