VirtualBox

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

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

Dis,SrvPciRaw,Sup: warning fixes.

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