VirtualBox

source: vbox/trunk/src/VBox/Devices/Bus/SrvPciRawR0.cpp@ 41661

Last change on this file since 41661 was 40806, checked in by vboxsync, 13 years ago

RTSpinlock: Redid the interface, eliminating NoInts and Tmp. Whether a spinlock is interrupt safe or not is now defined at creation time, preventing stupid bugs arrising from calling the wrong acquire and/or release methods somewhere. The saved flags are stored in the spinlock strucutre, eliminating the annoying Tmp variable. Needs testing on each platform before fixing the build burn.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.0 KB
Line 
1/* $Id: SrvPciRawR0.cpp 40806 2012-04-06 21:05:19Z vboxsync $ */
2/** @file
3 * PCI passthrough - The ring 0 service.
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
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#define LOG_GROUP LOG_GROUP_DEV_PCI_RAW
23#include <VBox/log.h>
24#include <VBox/sup.h>
25#include <VBox/rawpci.h>
26#include <VBox/vmm/pdmpci.h>
27#include <VBox/vmm/pdm.h>
28#include <VBox/vmm/gvm.h>
29#include <VBox/vmm/gvmm.h>
30#include <VBox/vmm/vm.h>
31
32#include <iprt/asm.h>
33#include <iprt/assert.h>
34#include <iprt/handletable.h>
35#include <iprt/mp.h>
36#include <iprt/mem.h>
37#include <iprt/semaphore.h>
38#include <iprt/spinlock.h>
39#include <iprt/string.h>
40#include <iprt/thread.h>
41#include <iprt/time.h>
42#include <iprt/asm-amd64-x86.h>
43
44
45/*******************************************************************************
46* Structures and Typedefs *
47*******************************************************************************/
48typedef struct PCIRAWSRVSTATE
49{
50 /** Structure lock. */
51 RTSPINLOCK hSpinlock;
52
53 /** Handle table for devices. */
54 RTHANDLETABLE hHtDevs;
55
56} PCIRAWSRVSTATE;
57typedef PCIRAWSRVSTATE *PPCIRAWSRVSTATE;
58
59typedef struct PCIRAWDEV
60{
61 /* Port pointer. */
62 PRAWPCIDEVPORT pPort;
63
64 /* Handle used by everybody else. */
65 PCIRAWDEVHANDLE hHandle;
66
67 /** The session this device is associated with. */
68 PSUPDRVSESSION pSession;
69
70 /** Structure lock. */
71 RTSPINLOCK hSpinlock;
72
73 /** Event for IRQ updates. */
74 RTSEMEVENT hIrqEvent;
75
76 /** Current pending IRQ for the device. */
77 int32_t iPendingIrq;
78
79 /** ISR handle. */
80 PCIRAWISRHANDLE hIsr;
81
82 /* If object is being destroyed. */
83 bool fTerminate;
84
85 /** The SUPR0 object. */
86 void *pvObj;
87} PCIRAWDEV;
88typedef PCIRAWDEV *PPCIRAWDEV;
89
90static PCIRAWSRVSTATE g_State;
91
92
93/** Interrupt handler. Could be called in the interrupt context,
94 * depending on host OS implmenetation. */
95static DECLCALLBACK(bool) pcirawr0Isr(void* pContext, int32_t iHostIrq)
96{
97 PPCIRAWDEV pThis = (PPCIRAWDEV)pContext;
98
99#ifdef VBOX_WITH_SHARED_PCI_INTERRUPTS
100 uint16_t uStatus;
101 PCIRAWMEMLOC Loc;
102 int rc;
103
104 Loc.cb = 2;
105 rc = pThis->pPort->pfnPciCfgRead(pThis->pPort, VBOX_PCI_STATUS, &Loc);
106 /* Cannot read, assume non-shared. */
107 if (RT_FAILURE(rc))
108 return false;
109
110 /* Check interrupt status bit. */
111 if ((Loc.u.u16 & (1 << 3)) == 0)
112 return false;
113#endif
114
115 RTSpinlockAcquire(pThis->hSpinlock);
116 pThis->iPendingIrq = iHostIrq;
117 RTSpinlockReleaseNoInts(pThis->hSpinlock);
118
119 /**
120 * @todo RTSemEventSignal() docs claims that it's platform-dependent
121 * if RTSemEventSignal() could be called from the ISR, but it seems IPRT
122 * doesn't provide primitives that guaranteed to work this way.
123 */
124 RTSemEventSignal(pThis->hIrqEvent);
125
126 return true;
127}
128
129static DECLCALLBACK(int) pcirawr0DevRetainHandle(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)
130{
131 NOREF(pvUser);
132 NOREF(hHandleTable);
133 PPCIRAWDEV pDev = (PPCIRAWDEV)pvObj;
134 if (pDev->hHandle != 0)
135 return SUPR0ObjAddRefEx(pDev->pvObj, (PSUPDRVSESSION)pvCtx, true /* fNoBlocking */);
136
137 return VINF_SUCCESS;
138}
139
140
141/**
142 * Initializes the raw PCI ring-0 service.
143 *
144 * @returns VBox status code.
145 */
146PCIRAWR0DECL(int) PciRawR0Init(void)
147{
148 LogFlow(("PciRawR0Init:\n"));
149 int rc = VINF_SUCCESS;
150
151 rc = RTHandleTableCreateEx(&g_State.hHtDevs, RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT,
152 UINT32_C(0xfefe0000), 4096, pcirawr0DevRetainHandle, NULL);
153
154 LogFlow(("PciRawR0Init: returns %Rrc\n", rc));
155 return rc;
156}
157
158/**
159 * Destroys raw PCI ring-0 service.
160 */
161PCIRAWR0DECL(void) PciRawR0Term(void)
162{
163 LogFlow(("PciRawR0Term:\n"));
164 RTHandleTableDestroy(g_State.hHtDevs, NULL, NULL);
165 g_State.hHtDevs = NIL_RTHANDLETABLE;
166}
167
168
169/**
170 * Per-VM R0 module init.
171 */
172PCIRAWR0DECL(int) PciRawR0InitVM(PVM pVM)
173{
174 PRAWPCIFACTORY pFactory = NULL;
175 int rc;
176
177 rc = SUPR0ComponentQueryFactory(pVM->pSession, "VBoxRawPci", RAWPCIFACTORY_UUID_STR, (void **)&pFactory);
178
179 if (RT_SUCCESS(rc))
180 {
181 if (pFactory)
182 {
183 PGVM pGVM = NULL;
184 rc = GVMMR0ByVM(pVM, &pGVM);
185 if (RT_SUCCESS(rc))
186 rc = pFactory->pfnInitVm(pFactory, pVM, &pGVM->rawpci.s);
187 pFactory->pfnRelease(pFactory);
188 }
189 }
190
191 return VINF_SUCCESS;
192}
193
194/**
195 * Per-VM R0 module termination routine.
196 */
197PCIRAWR0DECL(void) PciRawR0TermVM(PVM pVM)
198{
199 PRAWPCIFACTORY pFactory = NULL;
200 int rc;
201
202 rc = SUPR0ComponentQueryFactory(pVM->pSession, "VBoxRawPci", RAWPCIFACTORY_UUID_STR, (void **)&pFactory);
203
204 if (RT_SUCCESS(rc))
205 {
206 if (pFactory)
207 {
208 PGVM pGVM = NULL;
209 rc = GVMMR0ByVM(pVM, &pGVM);
210 if (RT_SUCCESS(rc))
211 pFactory->pfnDeinitVm(pFactory, pVM, &pGVM->rawpci.s);
212 pFactory->pfnRelease(pFactory);
213 }
214 }
215}
216
217static int pcirawr0DevTerm(PPCIRAWDEV pThis, int32_t fFlags)
218{
219 ASMAtomicWriteBool(&pThis->fTerminate, true);
220
221 if (pThis->hIrqEvent)
222 RTSemEventSignal(pThis->hIrqEvent);
223
224 /* Enable that, once figure our how to make sure
225 IRQ getter thread notified and woke up. */
226#if 0
227 if (pThis->hIrqEvent)
228 {
229 RTSemEventDestroy(pThis->hIrqEvent);
230 pThis->hIrqEvent = NIL_RTSEMEVENT;
231 }
232#endif
233
234 if (pThis->hSpinlock)
235 {
236 RTSpinlockDestroy(pThis->hSpinlock);
237 pThis->hSpinlock = NIL_RTSPINLOCK;
238 }
239
240 /* Forcefully deinit. */
241 return pThis->pPort->pfnDeinit(pThis->pPort, fFlags);
242}
243
244#define GET_PORT(hDev) \
245 PPCIRAWDEV pDev = (PPCIRAWDEV)RTHandleTableLookupWithCtx(g_State.hHtDevs, hDev, pSession); \
246 if (!pDev) \
247 return VERR_INVALID_HANDLE; \
248 PRAWPCIDEVPORT pDevPort = pDev->pPort; \
249 AssertReturn(pDevPort != NULL, VERR_INVALID_PARAMETER); \
250 AssertReturn(pDevPort->u32Version == RAWPCIDEVPORT_VERSION, VERR_INVALID_PARAMETER); \
251 AssertReturn(pDevPort->u32VersionEnd == RAWPCIDEVPORT_VERSION, VERR_INVALID_PARAMETER);
252
253#define PUT_PORT() if (pDev->pvObj) SUPR0ObjRelease(pDev->pvObj, pSession)
254
255#ifdef DEBUG_nike
256
257/* Code to perform debugging without host driver. */
258typedef struct DUMMYRAWPCIINS
259{
260 /* Host PCI address of this device. */
261 uint32_t HostPciAddress;
262 /* Padding */
263 uint32_t pad0;
264
265 uint8_t aPciCfg[256];
266
267 /** Port, given to the outside world. */
268 RAWPCIDEVPORT DevPort;
269} DUMMYRAWPCIINS;
270typedef struct DUMMYRAWPCIINS *PDUMMYRAWPCIINS;
271
272#define DEVPORT_2_DUMMYRAWPCIINS(pPort) \
273 ( (PDUMMYRAWPCIINS)((uint8_t *)pPort - RT_OFFSETOF(DUMMYRAWPCIINS, DevPort)) )
274
275static uint8_t dummyPciGetByte(PDUMMYRAWPCIINS pThis, uint32_t iRegister)
276{
277 return pThis->aPciCfg[iRegister];
278}
279
280static void dummyPciSetByte(PDUMMYRAWPCIINS pThis, uint32_t iRegister, uint8_t u8)
281{
282 pThis->aPciCfg[iRegister] = u8;
283}
284
285static uint16_t dummyPciGetWord(PDUMMYRAWPCIINS pThis, uint32_t iRegister)
286{
287 uint16_t u16Value = *(uint16_t*)&pThis->aPciCfg[iRegister];
288 return RT_H2LE_U16(u16Value);
289}
290
291static void dummyPciSetWord(PDUMMYRAWPCIINS pThis, uint32_t iRegister, uint16_t u16)
292{
293 *(uint16_t*)&pThis->aPciCfg[iRegister] = RT_H2LE_U16(u16);
294}
295
296static uint32_t dummyPciGetDWord(PDUMMYRAWPCIINS pThis, uint32_t iRegister)
297{
298 uint32_t u32Value = *(uint32_t*)&pThis->aPciCfg[iRegister];
299 return RT_H2LE_U32(u32Value);
300}
301
302static void dummyPciSetDWord(PDUMMYRAWPCIINS pThis, uint32_t iRegister, uint32_t u32)
303{
304 *(uint32_t*)&pThis->aPciCfg[iRegister] = RT_H2LE_U32(u32);
305}
306
307/**
308 * @copydoc RAWPCIDEVPORT:: pfnInit
309 */
310static DECLCALLBACK(int) dummyPciDevInit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
311{
312 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
313
314 dummyPciSetWord(pThis, VBOX_PCI_VENDOR_ID, 0xccdd);
315 dummyPciSetWord(pThis, VBOX_PCI_DEVICE_ID, 0xeeff);
316 dummyPciSetWord(pThis, VBOX_PCI_COMMAND, PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS | PCI_COMMAND_BUSMASTER);
317 dummyPciSetByte(pThis, VBOX_PCI_INTERRUPT_PIN, 1);
318
319 return VINF_SUCCESS;
320}
321
322/**
323 * @copydoc RAWPCIDEVPORT:: pfnDeinit
324 */
325static DECLCALLBACK(int) dummyPciDevDeinit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
326{
327 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
328
329 return VINF_SUCCESS;
330}
331
332/**
333 * @copydoc RAWPCIDEVPORT:: pfnDestroy
334 */
335static DECLCALLBACK(int) dummyPciDevDestroy(PRAWPCIDEVPORT pPort)
336{
337 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
338
339 RTMemFree(pThis);
340
341 return VINF_SUCCESS;
342}
343
344
345/**
346 * @copydoc RAWPCIDEVPORT:: pfnGetRegionInfo
347 */
348static DECLCALLBACK(int) dummyPciDevGetRegionInfo(PRAWPCIDEVPORT pPort,
349 int32_t iRegion,
350 RTHCPHYS *pRegionStart,
351 uint64_t *pu64RegionSize,
352 bool *pfPresent,
353 uint32_t *pfFlags)
354{
355 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
356
357 if (iRegion == 0)
358 {
359 *pfPresent = true;
360 *pRegionStart = 0xfef0;
361 *pu64RegionSize = 0x10;
362 *pfFlags = PCIRAW_ADDRESS_SPACE_IO;
363 }
364 else if (iRegion == 2)
365 {
366 *pfPresent = true;
367 *pRegionStart = 0xffff0000;
368 *pu64RegionSize = 0x1000;
369 *pfFlags = PCIRAW_ADDRESS_SPACE_BAR64 | PCIRAW_ADDRESS_SPACE_MEM;
370 }
371 else
372 *pfPresent = false;
373
374 return VINF_SUCCESS;
375}
376
377/**
378 * @copydoc RAWPCIDEVPORT:: pfnMapRegion
379 */
380static DECLCALLBACK(int) dummyPciDevMapRegion(PRAWPCIDEVPORT pPort,
381 int32_t iRegion,
382 RTHCPHYS HCRegionStart,
383 uint64_t u64RegionSize,
384 int32_t fFlags,
385 RTR0PTR *pRegionBase)
386{
387 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
388 return VINF_SUCCESS;
389}
390
391/**
392 * @copydoc RAWPCIDEVPORT:: pfnUnapRegion
393 */
394static DECLCALLBACK(int) dummyPciDevUnmapRegion(PRAWPCIDEVPORT pPort,
395 int32_t iRegion,
396 RTHCPHYS HCRegionStart,
397 uint64_t u64RegionSize,
398 RTR0PTR RegionBase)
399{
400 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
401 return VINF_SUCCESS;
402}
403
404/**
405 * @copydoc RAWPCIDEVPORT:: pfnPciCfgRead
406 */
407static DECLCALLBACK(int) dummyPciDevPciCfgRead(PRAWPCIDEVPORT pPort,
408 uint32_t Register,
409 PCIRAWMEMLOC *pValue)
410{
411 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
412
413 switch (pValue->cb)
414 {
415 case 1:
416 pValue->u.u8 = dummyPciGetByte(pThis, Register);
417 break;
418 case 2:
419 pValue->u.u16 = dummyPciGetWord(pThis, Register);
420 break;
421 case 4:
422 pValue->u.u32 = dummyPciGetDWord(pThis, Register);
423 break;
424 }
425
426 return VINF_SUCCESS;
427}
428
429/**
430 * @copydoc RAWPCIDEVPORT:: pfnPciCfgWrite
431 */
432static DECLCALLBACK(int) dummyPciDevPciCfgWrite(PRAWPCIDEVPORT pPort,
433 uint32_t Register,
434 PCIRAWMEMLOC *pValue)
435{
436 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
437
438 switch (pValue->cb)
439 {
440 case 1:
441 dummyPciSetByte(pThis, Register, pValue->u.u8);
442 break;
443 case 2:
444 dummyPciSetWord(pThis, Register, pValue->u.u16);
445 break;
446 case 4:
447 dummyPciSetDWord(pThis, Register, pValue->u.u32);
448 break;
449 }
450
451 return VINF_SUCCESS;
452}
453
454static DECLCALLBACK(int) dummyPciDevRegisterIrqHandler(PRAWPCIDEVPORT pPort,
455 PFNRAWPCIISR pfnHandler,
456 void* pIrqContext,
457 PCIRAWISRHANDLE *phIsr)
458{
459 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
460 return VINF_SUCCESS;
461}
462
463static DECLCALLBACK(int) dummyPciDevUnregisterIrqHandler(PRAWPCIDEVPORT pPort,
464 PCIRAWISRHANDLE hIsr)
465{
466 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
467 return VINF_SUCCESS;
468}
469
470static DECLCALLBACK(int) dummyPciDevPowerStateChange(PRAWPCIDEVPORT pPort,
471 PCIRAWPOWERSTATE aState,
472 uint64_t *pu64Param)
473{
474 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
475 return VINF_SUCCESS;
476}
477
478static PRAWPCIDEVPORT pcirawr0CreateDummyDevice(uint32_t HostDevice, uint32_t fFlags)
479{
480 PDUMMYRAWPCIINS pNew = (PDUMMYRAWPCIINS)RTMemAllocZ(sizeof(*pNew));
481 if (!pNew)
482 return NULL;
483
484 pNew->HostPciAddress = HostDevice;
485
486 pNew->DevPort.u32Version = RAWPCIDEVPORT_VERSION;
487 pNew->DevPort.pfnInit = dummyPciDevInit;
488 pNew->DevPort.pfnDeinit = dummyPciDevDeinit;
489 pNew->DevPort.pfnDestroy = dummyPciDevDestroy;
490 pNew->DevPort.pfnGetRegionInfo = dummyPciDevGetRegionInfo;
491 pNew->DevPort.pfnMapRegion = dummyPciDevMapRegion;
492 pNew->DevPort.pfnUnmapRegion = dummyPciDevUnmapRegion;
493 pNew->DevPort.pfnPciCfgRead = dummyPciDevPciCfgRead;
494 pNew->DevPort.pfnPciCfgWrite = dummyPciDevPciCfgWrite;
495 pNew->DevPort.pfnRegisterIrqHandler = dummyPciDevRegisterIrqHandler;
496 pNew->DevPort.pfnUnregisterIrqHandler = dummyPciDevUnregisterIrqHandler;
497 pNew->DevPort.pfnPowerStateChange = dummyPciDevPowerStateChange;
498
499 pNew->DevPort.u32VersionEnd = RAWPCIDEVPORT_VERSION;
500
501 return &pNew->DevPort;
502}
503#endif
504
505static DECLCALLBACK(void) pcirawr0DevObjDestructor(void *pvObj, void *pvIns, void *pvUnused)
506{
507 PPCIRAWDEV pThis = (PPCIRAWDEV)pvIns;
508 NOREF(pvObj); NOREF(pvUnused);
509
510 /* Forcefully deinit. */
511 pcirawr0DevTerm(pThis, 0);
512
513 /* And destroy. */
514 pThis->pPort->pfnDestroy(pThis->pPort);
515
516 RTMemFree(pThis);
517}
518
519
520static int pcirawr0OpenDevice(PSUPDRVSESSION pSession,
521 PVM pVM,
522 uint32_t HostDevice,
523 uint32_t fFlags,
524 PCIRAWDEVHANDLE *pHandle,
525 uint32_t *pfDevFlags)
526{
527 /*
528 * Query the factory we want, then use it create and connect the host device.
529 */
530 PRAWPCIFACTORY pFactory = NULL;
531 PRAWPCIDEVPORT pDevPort = NULL;
532 int rc;
533 PPCIRAWDEV pNew;
534
535 pNew = (PPCIRAWDEV)RTMemAllocZ(sizeof(*pNew));
536 if (!pNew)
537 return VERR_NO_MEMORY;
538
539
540 rc = SUPR0ComponentQueryFactory(pSession, "VBoxRawPci", RAWPCIFACTORY_UUID_STR, (void **)&pFactory);
541 /* No host driver registered, provide some fake implementation
542 for debugging purposes. */
543#ifdef DEBUG_nike
544 if (rc == VERR_SUPDRV_COMPONENT_NOT_FOUND)
545 {
546 pDevPort = pcirawr0CreateDummyDevice(HostDevice, fFlags);
547 if (pDevPort)
548 {
549 pDevPort->pfnInit(pDevPort, fFlags);
550 rc = VINF_SUCCESS;
551 }
552 else
553 rc = VERR_NO_MEMORY;
554 }
555#endif
556
557 if (RT_SUCCESS(rc))
558 {
559 if (pFactory)
560 {
561 PGVM pGVM = NULL;
562 rc = GVMMR0ByVM(pVM, &pGVM);
563
564 if (RT_SUCCESS(rc))
565 rc = pFactory->pfnCreateAndConnect(pFactory,
566 HostDevice,
567 fFlags,
568 &pGVM->rawpci.s,
569 &pDevPort,
570 pfDevFlags);
571 pFactory->pfnRelease(pFactory);
572 }
573
574 if (RT_SUCCESS(rc))
575 {
576 rc = RTSpinlockCreate(&pNew->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "PciRaw");
577 AssertRC(rc);
578 rc = RTSemEventCreate(&pNew->hIrqEvent);
579 AssertRC(rc);
580
581 pNew->pSession = pSession;
582 pNew->pPort = pDevPort;
583 pNew->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_RAW_PCI_DEVICE,
584 pcirawr0DevObjDestructor, pNew, NULL);
585
586 uint32_t hHandle = 0;
587 rc = RTHandleTableAllocWithCtx(g_State.hHtDevs, pNew, pSession, &hHandle);
588 if (RT_SUCCESS(rc))
589 {
590 pNew->hHandle = (PCIRAWDEVHANDLE)hHandle;
591 *pHandle = pNew->hHandle;
592 }
593 else
594 {
595 SUPR0ObjRelease(pNew->pvObj, pSession);
596 RTSpinlockDestroy(pNew->hSpinlock);
597 RTSemEventDestroy(pNew->hIrqEvent);
598 }
599 }
600 }
601
602 if (RT_FAILURE(rc))
603 RTMemFree(pNew);
604
605 return rc;
606}
607
608static int pcirawr0CloseDevice(PSUPDRVSESSION pSession,
609 PCIRAWDEVHANDLE TargetDevice,
610 uint32_t fFlags)
611{
612 GET_PORT(TargetDevice);
613 int rc;
614
615 pDevPort->pfnUnregisterIrqHandler(pDevPort, pDev->hIsr);
616 pDev->hIsr = 0;
617
618 rc = pcirawr0DevTerm(pDev, fFlags);
619
620 RTHandleTableFreeWithCtx(g_State.hHtDevs, TargetDevice, pSession);
621
622 PUT_PORT();
623
624 return rc;
625}
626
627/* We may want to call many functions here directly, so no static */
628static int pcirawr0GetRegionInfo(PSUPDRVSESSION pSession,
629 PCIRAWDEVHANDLE TargetDevice,
630 int32_t iRegion,
631 RTHCPHYS *pRegionStart,
632 uint64_t *pu64RegionSize,
633 bool *pfPresent,
634 uint32_t *pfFlags)
635{
636 LogFlow(("pcirawr0GetRegionInfo: %d\n", iRegion));
637 GET_PORT(TargetDevice);
638
639 int rc = pDevPort->pfnGetRegionInfo(pDevPort, iRegion, pRegionStart, pu64RegionSize, pfPresent, pfFlags);
640
641 PUT_PORT();
642
643 return rc;
644}
645
646static int pcirawr0MapRegion(PSUPDRVSESSION pSession,
647 PCIRAWDEVHANDLE TargetDevice,
648 int32_t iRegion,
649 RTHCPHYS HCRegionStart,
650 uint64_t u64RegionSize,
651 uint32_t fFlags,
652 RTR3PTR *ppvAddressR3,
653 RTR0PTR *ppvAddressR0)
654{
655 LogFlow(("pcirawr0MapRegion\n"));
656 GET_PORT(TargetDevice);
657 int rc;
658
659 rc = pDevPort->pfnMapRegion(pDevPort, iRegion, HCRegionStart, u64RegionSize, fFlags, ppvAddressR0);
660 if (RT_SUCCESS(rc))
661 {
662 Assert(*ppvAddressR0 != NULL);
663
664 /* Do we need to do something to help with R3 mapping, if ((fFlags & PCIRAWRFLAG_ALLOW_R3MAP) != 0) */
665 }
666
667 *ppvAddressR3 = 0;
668
669 PUT_PORT();
670
671 return rc;
672}
673
674static int pcirawr0UnmapRegion(PSUPDRVSESSION pSession,
675 PCIRAWDEVHANDLE TargetDevice,
676 int32_t iRegion,
677 RTHCPHYS HCRegionStart,
678 uint64_t u64RegionSize,
679 RTR3PTR pvAddressR3,
680 RTR0PTR pvAddressR0)
681{
682 LogFlow(("pcirawr0UnmapRegion\n"));
683 int rc;
684 NOREF(pSession); NOREF(pvAddressR3);
685
686 GET_PORT(TargetDevice);
687
688 rc = pDevPort->pfnUnmapRegion(pDevPort, iRegion, HCRegionStart, u64RegionSize, pvAddressR0);
689
690 PUT_PORT();
691
692 return rc;
693}
694
695static int pcirawr0PioWrite(PSUPDRVSESSION pSession,
696 PCIRAWDEVHANDLE TargetDevice,
697 uint16_t Port,
698 uint32_t u32,
699 unsigned cb)
700{
701 NOREF(pSession); NOREF(TargetDevice);
702 /// @todo add check that port fits into device range
703 switch (cb)
704 {
705 case 1:
706 ASMOutU8 (Port, u32);
707 break;
708 case 2:
709 ASMOutU16(Port, u32);
710 break;
711 case 4:
712 ASMOutU32(Port, u32);
713 break;
714 default:
715 AssertMsgFailed(("Unhandled port write: %d\n", cb));
716 }
717
718 return VINF_SUCCESS;
719}
720
721
722static int pcirawr0PioRead(PSUPDRVSESSION pSession,
723 PCIRAWDEVHANDLE TargetDevice,
724 uint16_t Port,
725 uint32_t *pu32,
726 unsigned cb)
727{
728 NOREF(pSession); NOREF(TargetDevice);
729 /// @todo add check that port fits into device range
730 switch (cb)
731 {
732 case 1:
733 *pu32 = ASMInU8 (Port);
734 break;
735 case 2:
736 *pu32 = ASMInU16(Port);
737 break;
738 case 4:
739 *pu32 = ASMInU32(Port);
740 break;
741 default:
742 AssertMsgFailed(("Unhandled port read: %d\n", cb));
743 }
744
745 return VINF_SUCCESS;
746}
747
748
749static int pcirawr0MmioRead(PSUPDRVSESSION pSession,
750 PCIRAWDEVHANDLE TargetDevice,
751 RTR0PTR Address,
752 PCIRAWMEMLOC *pValue)
753{
754 NOREF(pSession); NOREF(TargetDevice);
755 /// @todo add check that address fits into device range
756#if 1
757 switch (pValue->cb)
758 {
759 case 1:
760 pValue->u.u8 = *(uint8_t*)Address;
761 break;
762 case 2:
763 pValue->u.u16 = *(uint16_t*)Address;
764 break;
765 case 4:
766 pValue->u.u32 = *(uint32_t*)Address;
767 break;
768 case 8:
769 pValue->u.u64 = *(uint64_t*)Address;
770 break;
771 }
772#else
773 memset(&pValue->u.u64, 0, 8);
774#endif
775 return VINF_SUCCESS;
776}
777
778static int pcirawr0MmioWrite(PSUPDRVSESSION pSession,
779 PCIRAWDEVHANDLE TargetDevice,
780 RTR0PTR Address,
781 PCIRAWMEMLOC *pValue)
782{
783 NOREF(pSession); NOREF(TargetDevice);
784 /// @todo add check that address fits into device range
785#if 1
786 switch (pValue->cb)
787 {
788 case 1:
789 *(uint8_t*)Address = pValue->u.u8;
790 break;
791 case 2:
792 *(uint16_t*)Address = pValue->u.u16;
793 break;
794 case 4:
795 *(uint32_t*)Address = pValue->u.u32;
796 break;
797 case 8:
798 *(uint64_t*)Address = pValue->u.u64;
799 break;
800 }
801#endif
802 return VINF_SUCCESS;
803}
804
805static int pcirawr0PciCfgRead(PSUPDRVSESSION pSession,
806 PCIRAWDEVHANDLE TargetDevice,
807 uint32_t Register,
808 PCIRAWMEMLOC *pValue)
809{
810 GET_PORT(TargetDevice);
811
812 return pDevPort->pfnPciCfgRead(pDevPort, Register, pValue);
813}
814
815static int pcirawr0PciCfgWrite(PSUPDRVSESSION pSession,
816 PCIRAWDEVHANDLE TargetDevice,
817 uint32_t Register,
818 PCIRAWMEMLOC *pValue)
819{
820 int rc;
821
822 GET_PORT(TargetDevice);
823
824 rc = pDevPort->pfnPciCfgWrite(pDevPort, Register, pValue);
825
826 PUT_PORT();
827
828 return rc;
829}
830
831static int pcirawr0EnableIrq(PSUPDRVSESSION pSession,
832 PCIRAWDEVHANDLE TargetDevice)
833{
834 int rc = VINF_SUCCESS;
835 GET_PORT(TargetDevice);
836
837 rc = pDevPort->pfnRegisterIrqHandler(pDevPort, pcirawr0Isr, pDev,
838 &pDev->hIsr);
839
840 PUT_PORT();
841 return rc;
842}
843
844static int pcirawr0DisableIrq(PSUPDRVSESSION pSession,
845 PCIRAWDEVHANDLE TargetDevice)
846{
847 int rc = VINF_SUCCESS;
848 GET_PORT(TargetDevice);
849
850 rc = pDevPort->pfnUnregisterIrqHandler(pDevPort, pDev->hIsr);
851 pDev->hIsr = 0;
852
853 PUT_PORT();
854 return rc;
855}
856
857static int pcirawr0GetIrq(PSUPDRVSESSION pSession,
858 PCIRAWDEVHANDLE TargetDevice,
859 int64_t iTimeout,
860 int32_t *piIrq)
861{
862 int rc = VINF_SUCCESS;
863 bool fTerminate = false;
864 int32_t iPendingIrq = 0;
865
866 LogFlow(("pcirawr0GetIrq\n"));
867
868 GET_PORT(TargetDevice);
869
870 RTSpinlockAcquire(pDev->hSpinlock);
871 iPendingIrq = pDev->iPendingIrq;
872 pDev->iPendingIrq = 0;
873 fTerminate = pDev->fTerminate;
874 RTSpinlockReleaseNoInts(pDev->hSpinlock);
875
876 /* Block until new IRQs arrives */
877 if (!fTerminate)
878 {
879 if (iPendingIrq == 0)
880 {
881 rc = RTSemEventWaitNoResume(pDev->hIrqEvent, iTimeout);
882 if (RT_SUCCESS(rc))
883 {
884 /** @todo: racy */
885 if (!ASMAtomicReadBool(&pDev->fTerminate))
886 {
887 RTSpinlockAcquire(pDev->hSpinlock);
888 iPendingIrq = pDev->iPendingIrq;
889 pDev->iPendingIrq = 0;
890 RTSpinlockReleaseNoInts(pDev->hSpinlock);
891 }
892 else
893 rc = VERR_INTERRUPTED;
894 }
895 }
896
897 if (RT_SUCCESS(rc))
898 *piIrq = iPendingIrq;
899 }
900 else
901 rc = VERR_INTERRUPTED;
902
903 PUT_PORT();
904
905 return rc;
906}
907
908static int pcirawr0PowerStateChange(PSUPDRVSESSION pSession,
909 PCIRAWDEVHANDLE TargetDevice,
910 PCIRAWPOWERSTATE aState,
911 uint64_t *pu64Param)
912{
913 LogFlow(("pcirawr0PowerStateChange\n"));
914 GET_PORT(TargetDevice);
915
916 int rc = pDevPort->pfnPowerStateChange(pDevPort, aState, pu64Param);
917
918 PUT_PORT();
919
920 return rc;
921}
922
923/**
924 * Process PCI raw request
925 *
926 * @returns VBox status code.
927 */
928PCIRAWR0DECL(int) PciRawR0ProcessReq(PSUPDRVSESSION pSession, PVM pVM, PPCIRAWSENDREQ pReq)
929{
930 LogFlow(("PciRawR0ProcessReq: %d for %x\n", pReq->iRequest, pReq->TargetDevice));
931 int rc = VINF_SUCCESS;
932
933 /* Route request to the host driver */
934 switch (pReq->iRequest)
935 {
936 case PCIRAWR0_DO_OPEN_DEVICE:
937 rc = pcirawr0OpenDevice(pSession, pVM,
938 pReq->u.aOpenDevice.PciAddress,
939 pReq->u.aOpenDevice.fFlags,
940 &pReq->u.aOpenDevice.Device,
941 &pReq->u.aOpenDevice.fDevFlags);
942 break;
943 case PCIRAWR0_DO_CLOSE_DEVICE:
944 rc = pcirawr0CloseDevice(pSession,
945 pReq->TargetDevice,
946 pReq->u.aCloseDevice.fFlags);
947 break;
948 case PCIRAWR0_DO_GET_REGION_INFO:
949 rc = pcirawr0GetRegionInfo(pSession,
950 pReq->TargetDevice,
951 pReq->u.aGetRegionInfo.iRegion,
952 &pReq->u.aGetRegionInfo.RegionStart,
953 &pReq->u.aGetRegionInfo.u64RegionSize,
954 &pReq->u.aGetRegionInfo.fPresent,
955 &pReq->u.aGetRegionInfo.fFlags);
956 break;
957 case PCIRAWR0_DO_MAP_REGION:
958 rc = pcirawr0MapRegion(pSession,
959 pReq->TargetDevice,
960 pReq->u.aMapRegion.iRegion,
961 pReq->u.aMapRegion.StartAddress,
962 pReq->u.aMapRegion.iRegionSize,
963 pReq->u.aMapRegion.fFlags,
964 &pReq->u.aMapRegion.pvAddressR3,
965 &pReq->u.aMapRegion.pvAddressR0);
966 break;
967 case PCIRAWR0_DO_UNMAP_REGION:
968 rc = pcirawr0UnmapRegion(pSession,
969 pReq->TargetDevice,
970 pReq->u.aUnmapRegion.iRegion,
971 pReq->u.aUnmapRegion.StartAddress,
972 pReq->u.aUnmapRegion.iRegionSize,
973 pReq->u.aUnmapRegion.pvAddressR3,
974 pReq->u.aUnmapRegion.pvAddressR0);
975 break;
976 case PCIRAWR0_DO_PIO_WRITE:
977 rc = pcirawr0PioWrite(pSession,
978 pReq->TargetDevice,
979 pReq->u.aPioWrite.iPort,
980 pReq->u.aPioWrite.iValue,
981 pReq->u.aPioWrite.cb);
982 break;
983 case PCIRAWR0_DO_PIO_READ:
984 rc = pcirawr0PioRead(pSession,
985 pReq->TargetDevice,
986 pReq->u.aPioRead.iPort,
987 &pReq->u.aPioWrite.iValue,
988 pReq->u.aPioRead.cb);
989 break;
990 case PCIRAWR0_DO_MMIO_WRITE:
991 rc = pcirawr0MmioWrite(pSession,
992 pReq->TargetDevice,
993 pReq->u.aMmioWrite.Address,
994 &pReq->u.aMmioWrite.Value);
995 break;
996 case PCIRAWR0_DO_MMIO_READ:
997 rc = pcirawr0MmioRead(pSession,
998 pReq->TargetDevice,
999 pReq->u.aMmioRead.Address,
1000 &pReq->u.aMmioRead.Value);
1001 break;
1002 case PCIRAWR0_DO_PCICFG_WRITE:
1003 rc = pcirawr0PciCfgWrite(pSession,
1004 pReq->TargetDevice,
1005 pReq->u.aPciCfgWrite.iOffset,
1006 &pReq->u.aPciCfgWrite.Value);
1007 break;
1008 case PCIRAWR0_DO_PCICFG_READ:
1009 rc = pcirawr0PciCfgRead(pSession,
1010 pReq->TargetDevice,
1011 pReq->u.aPciCfgRead.iOffset,
1012 &pReq->u.aPciCfgRead.Value);
1013 break;
1014 case PCIRAWR0_DO_ENABLE_IRQ:
1015 rc = pcirawr0EnableIrq(pSession,
1016 pReq->TargetDevice);
1017 break;
1018 case PCIRAWR0_DO_DISABLE_IRQ:
1019 rc = pcirawr0DisableIrq(pSession,
1020 pReq->TargetDevice);
1021 break;
1022 case PCIRAWR0_DO_GET_IRQ:
1023 rc = pcirawr0GetIrq(pSession,
1024 pReq->TargetDevice,
1025 pReq->u.aGetIrq.iTimeout,
1026 &pReq->u.aGetIrq.iIrq);
1027 break;
1028 case PCIRAWR0_DO_POWER_STATE_CHANGE:
1029 rc = pcirawr0PowerStateChange(pSession,
1030 pReq->TargetDevice,
1031 (PCIRAWPOWERSTATE)pReq->u.aPowerStateChange.iState,
1032 &pReq->u.aPowerStateChange.u64Param);
1033 break;
1034 default:
1035 rc = VERR_NOT_SUPPORTED;
1036 }
1037
1038 LogFlow(("PciRawR0ProcessReq: returns %Rrc\n", rc));
1039 return rc;
1040}
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