VirtualBox

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

Last change on this file since 69162 was 69124, checked in by vboxsync, 7 years ago

Devices/Bus: (C) year + keywords

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