VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.5 KB
Line 
1/* $Id: SrvPciRawR0.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * PCI passthrough - The ring 0 service.
4 */
5
6/*
7 * Copyright (C) 2011-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DEV_PCI_RAW
33#include <VBox/log.h>
34#include <VBox/sup.h>
35#include <VBox/rawpci.h>
36#include <VBox/vmm/pdmpci.h>
37#include <VBox/vmm/pdm.h>
38#include <VBox/vmm/gvm.h>
39#include <VBox/vmm/gvmm.h>
40#include <VBox/vmm/vmcc.h>
41
42#include <iprt/asm.h>
43#include <iprt/assert.h>
44#include <iprt/handletable.h>
45#include <iprt/mp.h>
46#include <iprt/mem.h>
47#include <iprt/semaphore.h>
48#include <iprt/spinlock.h>
49#include <iprt/string.h>
50#include <iprt/thread.h>
51#include <iprt/time.h>
52#include <iprt/asm-amd64-x86.h>
53
54
55/*********************************************************************************************************************************
56* Structures and Typedefs *
57*********************************************************************************************************************************/
58typedef struct PCIRAWSRVSTATE
59{
60 /** Structure lock. */
61 RTSPINLOCK hSpinlock;
62
63 /** Handle table for devices. */
64 RTHANDLETABLE hHtDevs;
65
66} PCIRAWSRVSTATE;
67typedef PCIRAWSRVSTATE *PPCIRAWSRVSTATE;
68
69typedef struct PCIRAWDEV
70{
71 /* Port pointer. */
72 PRAWPCIDEVPORT pPort;
73
74 /* Handle used by everybody else. */
75 PCIRAWDEVHANDLE hHandle;
76
77 /** The session this device is associated with. */
78 PSUPDRVSESSION pSession;
79
80 /** Structure lock. */
81 RTSPINLOCK hSpinlock;
82
83 /** Event for IRQ updates. */
84 RTSEMEVENT hIrqEvent;
85
86 /** Current pending IRQ for the device. */
87 int32_t iPendingIrq;
88
89 /** ISR handle. */
90 PCIRAWISRHANDLE hIsr;
91
92 /* If object is being destroyed. */
93 bool fTerminate;
94
95 /** The SUPR0 object. */
96 void *pvObj;
97} PCIRAWDEV;
98typedef PCIRAWDEV *PPCIRAWDEV;
99
100static PCIRAWSRVSTATE g_State;
101
102
103/** Interrupt handler. Could be called in the interrupt context,
104 * depending on host OS implmenetation. */
105static DECLCALLBACK(bool) pcirawr0Isr(void* pContext, int32_t iHostIrq)
106{
107 PPCIRAWDEV pThis = (PPCIRAWDEV)pContext;
108
109#ifdef VBOX_WITH_SHARED_PCI_INTERRUPTS
110 uint16_t uStatus;
111 PCIRAWMEMLOC Loc;
112 int rc;
113
114 Loc.cb = 2;
115 rc = pThis->pPort->pfnPciCfgRead(pThis->pPort, VBOX_PCI_STATUS, &Loc);
116 /* Cannot read, assume non-shared. */
117 if (RT_FAILURE(rc))
118 return false;
119
120 /* Check interrupt status bit. */
121 if ((Loc.u.u16 & (1 << 3)) == 0)
122 return false;
123#endif
124
125 RTSpinlockAcquire(pThis->hSpinlock);
126 pThis->iPendingIrq = iHostIrq;
127 RTSpinlockRelease(pThis->hSpinlock);
128
129 /**
130 * @todo RTSemEventSignal() docs claims that it's platform-dependent
131 * if RTSemEventSignal() could be called from the ISR, but it seems IPRT
132 * doesn't provide primitives that guaranteed to work this way.
133 */
134 RTSemEventSignal(pThis->hIrqEvent);
135
136 return true;
137}
138
139static DECLCALLBACK(int) pcirawr0DevRetainHandle(RTHANDLETABLE hHandleTable, void *pvObj, void *pvCtx, void *pvUser)
140{
141 NOREF(pvUser);
142 NOREF(hHandleTable);
143 PPCIRAWDEV pDev = (PPCIRAWDEV)pvObj;
144 if (pDev->hHandle != 0)
145 return SUPR0ObjAddRefEx(pDev->pvObj, (PSUPDRVSESSION)pvCtx, true /* fNoBlocking */);
146
147 return VINF_SUCCESS;
148}
149
150
151/**
152 * Initializes the raw PCI ring-0 service.
153 *
154 * @returns VBox status code.
155 */
156PCIRAWR0DECL(int) PciRawR0Init(void)
157{
158 LogFlow(("PciRawR0Init:\n"));
159 int rc = VINF_SUCCESS;
160
161 rc = RTHandleTableCreateEx(&g_State.hHtDevs, RTHANDLETABLE_FLAGS_LOCKED | RTHANDLETABLE_FLAGS_CONTEXT,
162 UINT32_C(0xfefe0000), 4096, pcirawr0DevRetainHandle, NULL);
163
164 LogFlow(("PciRawR0Init: returns %Rrc\n", rc));
165 return rc;
166}
167
168/**
169 * Destroys raw PCI ring-0 service.
170 */
171PCIRAWR0DECL(void) PciRawR0Term(void)
172{
173 LogFlow(("PciRawR0Term:\n"));
174 RTHandleTableDestroy(g_State.hHtDevs, NULL, NULL);
175 g_State.hHtDevs = NIL_RTHANDLETABLE;
176}
177
178
179/**
180 * Per-VM R0 module init.
181 */
182PCIRAWR0DECL(int) PciRawR0InitVM(PGVM pGVM)
183{
184 PRAWPCIFACTORY pFactory = NULL;
185 int rc = SUPR0ComponentQueryFactory(pGVM->pSession, "VBoxRawPci", RAWPCIFACTORY_UUID_STR, (void **)&pFactory);
186 if (RT_SUCCESS(rc))
187 {
188 if (pFactory)
189 {
190 rc = pFactory->pfnInitVm(pFactory, pGVM, &pGVM->rawpci.s);
191 pFactory->pfnRelease(pFactory);
192 }
193 }
194 return VINF_SUCCESS;
195}
196
197/**
198 * Per-VM R0 module termination routine.
199 */
200PCIRAWR0DECL(void) PciRawR0TermVM(PGVM pGVM)
201{
202 PRAWPCIFACTORY pFactory = NULL;
203 int rc = SUPR0ComponentQueryFactory(pGVM->pSession, "VBoxRawPci", RAWPCIFACTORY_UUID_STR, (void **)&pFactory);
204 if (RT_SUCCESS(rc))
205 {
206 if (pFactory)
207 {
208 pFactory->pfnDeinitVm(pFactory, pGVM, &pGVM->rawpci.s);
209 pFactory->pfnRelease(pFactory);
210 }
211 }
212}
213
214static int pcirawr0DevTerm(PPCIRAWDEV pThis, int32_t fFlags)
215{
216 ASMAtomicWriteBool(&pThis->fTerminate, true);
217
218 if (pThis->hIrqEvent)
219 RTSemEventSignal(pThis->hIrqEvent);
220
221 /* Enable that, once figure our how to make sure
222 IRQ getter thread notified and woke up. */
223#if 0
224 if (pThis->hIrqEvent)
225 {
226 RTSemEventDestroy(pThis->hIrqEvent);
227 pThis->hIrqEvent = NIL_RTSEMEVENT;
228 }
229#endif
230
231 if (pThis->hSpinlock)
232 {
233 RTSpinlockDestroy(pThis->hSpinlock);
234 pThis->hSpinlock = NIL_RTSPINLOCK;
235 }
236
237 /* Forcefully deinit. */
238 return pThis->pPort->pfnDeinit(pThis->pPort, fFlags);
239}
240
241#define GET_PORT(hDev) \
242 PPCIRAWDEV pDev = (PPCIRAWDEV)RTHandleTableLookupWithCtx(g_State.hHtDevs, hDev, pSession); \
243 if (!pDev) \
244 return VERR_INVALID_HANDLE; \
245 PRAWPCIDEVPORT pDevPort = pDev->pPort; \
246 AssertReturn(pDevPort != NULL, VERR_INVALID_PARAMETER); \
247 AssertReturn(pDevPort->u32Version == RAWPCIDEVPORT_VERSION, VERR_INVALID_PARAMETER); \
248 AssertReturn(pDevPort->u32VersionEnd == RAWPCIDEVPORT_VERSION, VERR_INVALID_PARAMETER);
249
250#define PUT_PORT() if (pDev->pvObj) SUPR0ObjRelease(pDev->pvObj, pSession)
251
252#ifdef DEBUG_nike
253
254/* Code to perform debugging without host driver. */
255typedef struct DUMMYRAWPCIINS
256{
257 /* Host PCI address of this device. */
258 uint32_t HostPciAddress;
259 /* Padding */
260 uint32_t pad0;
261
262 uint8_t aPciCfg[256];
263
264 /** Port, given to the outside world. */
265 RAWPCIDEVPORT DevPort;
266} DUMMYRAWPCIINS;
267typedef struct DUMMYRAWPCIINS *PDUMMYRAWPCIINS;
268
269#define DEVPORT_2_DUMMYRAWPCIINS(pPort) \
270 ( (PDUMMYRAWPCIINS)((uint8_t *)pPort - RT_UOFFSETOF(DUMMYRAWPCIINS, DevPort)) )
271
272static uint8_t dummyPciGetByte(PDUMMYRAWPCIINS pThis, uint32_t iRegister)
273{
274 return pThis->aPciCfg[iRegister];
275}
276
277static void dummyPciSetByte(PDUMMYRAWPCIINS pThis, uint32_t iRegister, uint8_t u8)
278{
279 pThis->aPciCfg[iRegister] = u8;
280}
281
282static uint16_t dummyPciGetWord(PDUMMYRAWPCIINS pThis, uint32_t iRegister)
283{
284 uint16_t u16Value = *(uint16_t*)&pThis->aPciCfg[iRegister];
285 return RT_H2LE_U16(u16Value);
286}
287
288static void dummyPciSetWord(PDUMMYRAWPCIINS pThis, uint32_t iRegister, uint16_t u16)
289{
290 *(uint16_t*)&pThis->aPciCfg[iRegister] = RT_H2LE_U16(u16);
291}
292
293static uint32_t dummyPciGetDWord(PDUMMYRAWPCIINS pThis, uint32_t iRegister)
294{
295 uint32_t u32Value = *(uint32_t*)&pThis->aPciCfg[iRegister];
296 return RT_H2LE_U32(u32Value);
297}
298
299static void dummyPciSetDWord(PDUMMYRAWPCIINS pThis, uint32_t iRegister, uint32_t u32)
300{
301 *(uint32_t*)&pThis->aPciCfg[iRegister] = RT_H2LE_U32(u32);
302}
303
304/**
305 * @copydoc RAWPCIDEVPORT:: pfnInit
306 */
307static DECLCALLBACK(int) dummyPciDevInit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
308{
309 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
310
311 dummyPciSetWord(pThis, VBOX_PCI_VENDOR_ID, 0xccdd);
312 dummyPciSetWord(pThis, VBOX_PCI_DEVICE_ID, 0xeeff);
313 dummyPciSetWord(pThis, VBOX_PCI_COMMAND, PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS | PCI_COMMAND_BUSMASTER);
314 dummyPciSetByte(pThis, VBOX_PCI_INTERRUPT_PIN, 1);
315
316 return VINF_SUCCESS;
317}
318
319/**
320 * @copydoc RAWPCIDEVPORT:: pfnDeinit
321 */
322static DECLCALLBACK(int) dummyPciDevDeinit(PRAWPCIDEVPORT pPort, uint32_t fFlags)
323{
324 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
325
326 return VINF_SUCCESS;
327}
328
329/**
330 * @copydoc RAWPCIDEVPORT:: pfnDestroy
331 */
332static DECLCALLBACK(int) dummyPciDevDestroy(PRAWPCIDEVPORT pPort)
333{
334 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
335
336 RTMemFree(pThis);
337
338 return VINF_SUCCESS;
339}
340
341
342/**
343 * @copydoc RAWPCIDEVPORT:: pfnGetRegionInfo
344 */
345static DECLCALLBACK(int) dummyPciDevGetRegionInfo(PRAWPCIDEVPORT pPort,
346 int32_t iRegion,
347 RTHCPHYS *pRegionStart,
348 uint64_t *pu64RegionSize,
349 bool *pfPresent,
350 uint32_t *pfFlags)
351{
352 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
353
354 if (iRegion == 0)
355 {
356 *pfPresent = true;
357 *pRegionStart = 0xfef0;
358 *pu64RegionSize = 0x10;
359 *pfFlags = PCIRAW_ADDRESS_SPACE_IO;
360 }
361 else if (iRegion == 2)
362 {
363 *pfPresent = true;
364 *pRegionStart = 0xffff0000;
365 *pu64RegionSize = 0x1000;
366 *pfFlags = PCIRAW_ADDRESS_SPACE_BAR64 | PCIRAW_ADDRESS_SPACE_MEM;
367 }
368 else
369 *pfPresent = false;
370
371 return VINF_SUCCESS;
372}
373
374/**
375 * @copydoc RAWPCIDEVPORT:: pfnMapRegion
376 */
377static DECLCALLBACK(int) dummyPciDevMapRegion(PRAWPCIDEVPORT pPort,
378 int32_t iRegion,
379 RTHCPHYS HCRegionStart,
380 uint64_t u64RegionSize,
381 int32_t fFlags,
382 RTR0PTR *pRegionBase)
383{
384 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
385 return VINF_SUCCESS;
386}
387
388/**
389 * @copydoc RAWPCIDEVPORT:: pfnUnapRegion
390 */
391static DECLCALLBACK(int) dummyPciDevUnmapRegion(PRAWPCIDEVPORT pPort,
392 int32_t iRegion,
393 RTHCPHYS HCRegionStart,
394 uint64_t u64RegionSize,
395 RTR0PTR RegionBase)
396{
397 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
398 return VINF_SUCCESS;
399}
400
401/**
402 * @copydoc RAWPCIDEVPORT:: pfnPciCfgRead
403 */
404static DECLCALLBACK(int) dummyPciDevPciCfgRead(PRAWPCIDEVPORT pPort,
405 uint32_t Register,
406 PCIRAWMEMLOC *pValue)
407{
408 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
409
410 switch (pValue->cb)
411 {
412 case 1:
413 pValue->u.u8 = dummyPciGetByte(pThis, Register);
414 break;
415 case 2:
416 pValue->u.u16 = dummyPciGetWord(pThis, Register);
417 break;
418 case 4:
419 pValue->u.u32 = dummyPciGetDWord(pThis, Register);
420 break;
421 }
422
423 return VINF_SUCCESS;
424}
425
426/**
427 * @copydoc RAWPCIDEVPORT:: pfnPciCfgWrite
428 */
429static DECLCALLBACK(int) dummyPciDevPciCfgWrite(PRAWPCIDEVPORT pPort,
430 uint32_t Register,
431 PCIRAWMEMLOC *pValue)
432{
433 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
434
435 switch (pValue->cb)
436 {
437 case 1:
438 dummyPciSetByte(pThis, Register, pValue->u.u8);
439 break;
440 case 2:
441 dummyPciSetWord(pThis, Register, pValue->u.u16);
442 break;
443 case 4:
444 dummyPciSetDWord(pThis, Register, pValue->u.u32);
445 break;
446 }
447
448 return VINF_SUCCESS;
449}
450
451static DECLCALLBACK(int) dummyPciDevRegisterIrqHandler(PRAWPCIDEVPORT pPort,
452 PFNRAWPCIISR pfnHandler,
453 void* pIrqContext,
454 PCIRAWISRHANDLE *phIsr)
455{
456 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
457 return VINF_SUCCESS;
458}
459
460static DECLCALLBACK(int) dummyPciDevUnregisterIrqHandler(PRAWPCIDEVPORT pPort,
461 PCIRAWISRHANDLE hIsr)
462{
463 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
464 return VINF_SUCCESS;
465}
466
467static DECLCALLBACK(int) dummyPciDevPowerStateChange(PRAWPCIDEVPORT pPort,
468 PCIRAWPOWERSTATE aState,
469 uint64_t *pu64Param)
470{
471 PDUMMYRAWPCIINS pThis = DEVPORT_2_DUMMYRAWPCIINS(pPort);
472 return VINF_SUCCESS;
473}
474
475static PRAWPCIDEVPORT pcirawr0CreateDummyDevice(uint32_t HostDevice, uint32_t fFlags)
476{
477 PDUMMYRAWPCIINS pNew = (PDUMMYRAWPCIINS)RTMemAllocZ(sizeof(*pNew));
478 if (!pNew)
479 return NULL;
480
481 pNew->HostPciAddress = HostDevice;
482
483 pNew->DevPort.u32Version = RAWPCIDEVPORT_VERSION;
484 pNew->DevPort.pfnInit = dummyPciDevInit;
485 pNew->DevPort.pfnDeinit = dummyPciDevDeinit;
486 pNew->DevPort.pfnDestroy = dummyPciDevDestroy;
487 pNew->DevPort.pfnGetRegionInfo = dummyPciDevGetRegionInfo;
488 pNew->DevPort.pfnMapRegion = dummyPciDevMapRegion;
489 pNew->DevPort.pfnUnmapRegion = dummyPciDevUnmapRegion;
490 pNew->DevPort.pfnPciCfgRead = dummyPciDevPciCfgRead;
491 pNew->DevPort.pfnPciCfgWrite = dummyPciDevPciCfgWrite;
492 pNew->DevPort.pfnRegisterIrqHandler = dummyPciDevRegisterIrqHandler;
493 pNew->DevPort.pfnUnregisterIrqHandler = dummyPciDevUnregisterIrqHandler;
494 pNew->DevPort.pfnPowerStateChange = dummyPciDevPowerStateChange;
495
496 pNew->DevPort.u32VersionEnd = RAWPCIDEVPORT_VERSION;
497
498 return &pNew->DevPort;
499}
500
501#endif /* DEBUG_nike */
502
503static DECLCALLBACK(void) pcirawr0DevObjDestructor(void *pvObj, void *pvIns, void *pvUnused)
504{
505 PPCIRAWDEV pThis = (PPCIRAWDEV)pvIns;
506 NOREF(pvObj); NOREF(pvUnused);
507
508 /* Forcefully deinit. */
509 pcirawr0DevTerm(pThis, 0);
510
511 /* And destroy. */
512 pThis->pPort->pfnDestroy(pThis->pPort);
513
514 RTMemFree(pThis);
515}
516
517
518static int pcirawr0OpenDevice(PGVM pGVM, PSUPDRVSESSION pSession,
519 uint32_t HostDevice,
520 uint32_t fFlags,
521 PCIRAWDEVHANDLE *pHandle,
522 uint32_t *pfDevFlags)
523{
524
525 int rc = GVMMR0ValidateGVMandEMT(pGVM, 0 /*idCpu*/);
526 if (RT_FAILURE(rc))
527 return rc;
528
529 /*
530 * Query the factory we want, then use it create and connect the host device.
531 */
532 PPCIRAWDEV pNew = (PPCIRAWDEV)RTMemAllocZ(sizeof(*pNew));
533 if (!pNew)
534 return VERR_NO_MEMORY;
535
536 PRAWPCIFACTORY pFactory = NULL;
537 rc = SUPR0ComponentQueryFactory(pSession, "VBoxRawPci", RAWPCIFACTORY_UUID_STR, (void **)&pFactory);
538 /* No host driver registered, provide some fake implementation
539 for debugging purposes. */
540 PRAWPCIDEVPORT pDevPort = NULL;
541#ifdef DEBUG_nike
542 if (rc == VERR_SUPDRV_COMPONENT_NOT_FOUND)
543 {
544 pDevPort = pcirawr0CreateDummyDevice(HostDevice, fFlags);
545 if (pDevPort)
546 {
547 pDevPort->pfnInit(pDevPort, fFlags);
548 rc = VINF_SUCCESS;
549 }
550 else
551 rc = VERR_NO_MEMORY;
552 }
553#endif
554
555 if (RT_SUCCESS(rc))
556 {
557 if (pFactory)
558 {
559 rc = pFactory->pfnCreateAndConnect(pFactory,
560 HostDevice,
561 fFlags,
562 &pGVM->rawpci.s,
563 &pDevPort,
564 pfDevFlags);
565 pFactory->pfnRelease(pFactory);
566 }
567
568 if (RT_SUCCESS(rc))
569 {
570 rc = RTSpinlockCreate(&pNew->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "PciRaw");
571 AssertRC(rc);
572 if (RT_SUCCESS(rc))
573 {
574 rc = RTSemEventCreate(&pNew->hIrqEvent);
575 AssertRC(rc);
576 if (RT_SUCCESS(rc))
577 {
578 pNew->pSession = pSession;
579 pNew->pPort = pDevPort;
580 pNew->pvObj = SUPR0ObjRegister(pSession, SUPDRVOBJTYPE_RAW_PCI_DEVICE,
581 pcirawr0DevObjDestructor, pNew, NULL);
582 if (pNew->pvObj)
583 {
584
585 uint32_t hHandle = 0;
586 rc = RTHandleTableAllocWithCtx(g_State.hHtDevs, pNew, pSession, &hHandle);
587 if (RT_SUCCESS(rc))
588 {
589 pNew->hHandle = (PCIRAWDEVHANDLE)hHandle;
590 *pHandle = pNew->hHandle;
591 return rc;
592 }
593 SUPR0ObjRelease(pNew->pvObj, pSession);
594 }
595 RTSemEventDestroy(pNew->hIrqEvent);
596 }
597 RTSpinlockDestroy(pNew->hSpinlock);
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 RTSpinlockRelease(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 RTSpinlockRelease(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(PGVM pGVM, PSUPDRVSESSION pSession, 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(pGVM, pSession,
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}
1041
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