VirtualBox

source: vbox/trunk/src/VBox/Devices/Bus/DevPciGenericEcam.cpp@ 99897

Last change on this file since 99897 was 99823, checked in by vboxsync, 18 months ago

Devices/Bus: Implement interrupt forwarding for the PCIe bus, bugref:10445 [fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.5 KB
Line 
1/* $Id: DevPciGenericEcam.cpp 99823 2023-05-17 07:53:16Z vboxsync $ */
2/** @file
3 * DevPciGeneric - Generic host to PCIe bridge emulation.
4 */
5
6/*
7 * Copyright (C) 2023 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
33#define PDMPCIDEV_INCLUDE_PRIVATE /* Hack to get pdmpcidevint.h included at the right point. */
34#include <VBox/vmm/pdmpcidev.h>
35
36#include <VBox/AssertGuest.h>
37#include <VBox/msi.h>
38#include <VBox/vmm/pdmdev.h>
39#include <VBox/vmm/mm.h>
40#include <iprt/asm.h>
41#include <iprt/assert.h>
42#include <iprt/string.h>
43#ifdef IN_RING3
44# include <iprt/mem.h>
45# include <iprt/uuid.h>
46#endif
47
48#include "PciInline.h"
49#include "VBoxDD.h"
50#include "MsiCommon.h"
51#include "DevPciInternal.h"
52
53
54/*********************************************************************************************************************************
55* Structures and Typedefs *
56*********************************************************************************************************************************/
57
58
59/*********************************************************************************************************************************
60* Defined Constants And Macros *
61*********************************************************************************************************************************/
62/** Saved state version of the generic ECAM PCI bus device. */
63#define VBOX_PCIGENECAM_SAVED_STATE_VERSION 1
64
65
66/*********************************************************************************************************************************
67* Internal Functions *
68*********************************************************************************************************************************/
69
70/**
71 * Returns the interrupt pin for a given device slot on the root port
72 * due to swizzeling.
73 *
74 * @returns Interrupt pin on the root port.
75 * @param uDevFn The device.
76 * @param uPin The interrupt pin on the device.
77 */
78DECLINLINE(uint8_t) pciGenEcamGetPirq(uint8_t uDevFn, uint8_t uPin)
79{
80 uint8_t uSlot = (uDevFn >> 3) - 1;
81 return (uPin + uSlot) & 3;
82}
83
84
85/**
86 * Returns whether the interrupt line is asserted on the PCI root for the given pin.
87 *
88 * @returns Flag whther the interrupt line is asserted (true) or not (false).
89 * @param pPciRoot The PCI root bus.
90 * @param u8IrqPin The IRQ pin being checked.
91 */
92DECLINLINE(bool) pciGenEcamGetIrqLvl(PDEVPCIROOT pPciRoot, uint8_t u8IrqPin)
93{
94 return (pPciRoot->u.GenericEcam.auPciIrqLevels[u8IrqPin] != 0);
95}
96
97
98/**
99 * @interface_method_impl{PDMPCIBUSREGCC,pfnSetIrqR3}
100 */
101static DECLCALLBACK(void) pciGenEcamSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
102{
103 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
104 PDEVPCIBUS pBus = &pPciRoot->PciBus;
105 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
106 uint8_t uDevFn = pPciDev->uDevFn;
107 uint16_t const uBusDevFn = PCIBDF_MAKE(pBus->iBus, uDevFn);
108
109 LogFlowFunc(("invoked by %p/%d: iIrq=%d iLevel=%d uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, iIrq, iLevel, uTagSrc));
110
111 /* If MSI or MSI-X is enabled, PCI INTx# signals are disabled regardless of the PCI command
112 * register interrupt bit state.
113 * PCI 3.0 (section 6.8) forbids MSI and MSI-X to be enabled at the same time and makes
114 * that undefined behavior. We check for MSI first, then MSI-X.
115 */
116 if (MsiIsEnabled(pPciDev))
117 {
118 Assert(!MsixIsEnabled(pPciDev)); /* Not allowed -- see note above. */
119 LogFlowFunc(("PCI Dev %p : MSI\n", pPciDev));
120 MsiNotify(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel, uTagSrc);
121 return;
122 }
123
124 if (MsixIsEnabled(pPciDev))
125 {
126 LogFlowFunc(("PCI Dev %p : MSI-X\n", pPciDev));
127 MsixNotify(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel, uTagSrc);
128 return;
129 }
130
131 LogFlowFunc(("PCI Dev %p : IRQ\n", pPciDev));
132
133 /* Check if the state changed. */
134 if (pPciDev->Int.s.uIrqPinState != iLevel)
135 {
136 pPciDev->Int.s.uIrqPinState = (iLevel & PDM_IRQ_LEVEL_HIGH);
137
138 /* Get the pin. */
139 uint8_t uIrqPin = devpciR3GetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN);
140 uint8_t uIrq = pciGenEcamGetPirq(pPciDev->uDevFn, uIrqPin);
141
142 if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_HIGH)
143 ASMAtomicIncU32(&pPciRoot->u.GenericEcam.auPciIrqLevels[uIrq]);
144 else if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_LOW)
145 ASMAtomicDecU32(&pPciRoot->u.GenericEcam.auPciIrqLevels[uIrq]);
146
147 bool fIrqLvl = pciGenEcamGetIrqLvl(pPciRoot, uIrq);
148 uint32_t u32IrqNr = pPciRoot->u.GenericEcam.auPciIrqNr[uIrq];
149
150 Log3Func(("%s: uIrqPin=%u uIrqRoot=%u fIrqLvl=%RTbool uIrqNr=%u\n",
151 R3STRING(pPciDev->pszNameR3), uIrqPin, uIrq, fIrqLvl, u32IrqNr));
152 pBusCC->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pDevIns, uBusDevFn, u32IrqNr, fIrqLvl, uTagSrc);
153
154 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) {
155 ASMAtomicDecU32(&pPciRoot->u.GenericEcam.auPciIrqLevels[uIrq]);
156 pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
157 fIrqLvl = pciGenEcamGetIrqLvl(pPciRoot, uIrq);
158 Log3Func(("%s: uIrqPin=%u uIrqRoot=%u fIrqLvl=%RTbool uIrqNr=%u\n",
159 R3STRING(pPciDev->pszNameR3), uIrqPin, uIrq, fIrqLvl, u32IrqNr));
160 pBusCC->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pDevIns, uBusDevFn, u32IrqNr, fIrqLvl, uTagSrc);
161 }
162 }
163}
164
165
166/**
167 * @callback_method_impl{FNIOMMMIONEWWRITE,
168 * Emulates writes to PIO space.}
169 */
170static DECLCALLBACK(VBOXSTRICTRC) pciHostR3MmioPioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
171{
172 Log2Func(("%RGp LB %d\n", off, cb));
173 RT_NOREF(pvUser);
174
175 AssertReturn(off < _64K, VERR_INVALID_PARAMETER);
176 AssertReturn(cb <= 4, VERR_INVALID_PARAMETER);
177
178 /* Get the value. */
179 uint32_t u32;
180 switch (cb)
181 {
182 case 1:
183 u32 = *(uint8_t const *)pv;
184 break;
185 case 2:
186 u32 = *(uint16_t const *)pv;
187 break;
188 case 4:
189 u32 = *(uint32_t const *)pv;
190 break;
191 default:
192 ASSERT_GUEST_MSG_FAILED(("cb=%u off=%RGp\n", cb, off)); /** @todo how the heck should this work? Split it, right? */
193 u32 = 0;
194 break;
195 }
196
197 return PDMDevHlpIoPortWrite(pDevIns, (RTIOPORT)off, u32, cb);
198}
199
200
201/**
202 * @callback_method_impl{FNIOMMMIONEWWRITE,
203 * Emulates reads from PIO space.}
204 */
205static DECLCALLBACK(VBOXSTRICTRC) pciHostR3MmioPioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
206{
207 LogFlowFunc(("%RGp LB %u\n", off, cb));
208 RT_NOREF(pvUser);
209
210 AssertReturn(off < _64K, VERR_INVALID_PARAMETER);
211 AssertReturn(cb <= 4, VERR_INVALID_PARAMETER);
212
213 /* Perform PIO space read */
214 uint32_t u32Value = 0;
215 VBOXSTRICTRC rcStrict = PDMDevHlpIoPortRead(pDevIns, (RTIOPORT)off, &u32Value, cb);
216
217 if (RT_SUCCESS(rcStrict))
218 {
219 switch (cb)
220 {
221 case 1:
222 *(uint8_t *)pv = (uint8_t)u32Value;
223 break;
224 case 2:
225 *(uint16_t *)pv = (uint16_t)u32Value;
226 break;
227 case 4:
228 *(uint32_t *)pv = u32Value;
229 break;
230 default:
231 ASSERT_GUEST_MSG_FAILED(("cb=%u off=%RGp\n", cb, off)); /** @todo how the heck should this work? Split it, right? */
232 break;
233 }
234 }
235
236 return rcStrict;
237}
238
239
240#ifdef IN_RING3
241
242/* -=-=-=-=-=- PCI Config Space -=-=-=-=-=- */
243
244
245/**
246 * @interface_method_impl{PDMDEVREG,pfnConstruct}
247 */
248static DECLCALLBACK(int) pciGenEcamR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
249{
250 RT_NOREF1(iInstance);
251 Assert(iInstance == 0);
252 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
253
254 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
255 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
256 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3;
257 PDEVPCIBUS pBus = &pPciRoot->PciBus;
258
259 /*
260 * Validate and read configuration.
261 */
262 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "MmioEcamBase"
263 "|MmioEcamLength"
264 "|MmioPioBase"
265 "|MmioPioSize"
266 "|IntPinA"
267 "|IntPinB"
268 "|IntPinC"
269 "|IntPinD", "");
270
271 int rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioEcamBase", &pPciRoot->u64PciConfigMMioAddress, 0);
272 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"McfgBase\"")));
273
274 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioEcamLength", &pPciRoot->u64PciConfigMMioLength, 0);
275 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"McfgLength\"")));
276
277 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioPioBase", &pPciRoot->GCPhysMmioPioEmuBase, 0);
278 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"MmioPioBase\"")));
279
280 rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioPioSize", &pPciRoot->GCPhysMmioPioEmuSize, 0);
281 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"MmioPioSize\"")));
282
283 rc = pHlp->pfnCFGMQueryU32(pCfg, "IntPinA", &pPciRoot->u.GenericEcam.auPciIrqNr[0]);
284 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"IntPinA\"")));
285
286 rc = pHlp->pfnCFGMQueryU32(pCfg, "IntPinB", &pPciRoot->u.GenericEcam.auPciIrqNr[1]);
287 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"IntPinB\"")));
288
289 rc = pHlp->pfnCFGMQueryU32(pCfg, "IntPinC", &pPciRoot->u.GenericEcam.auPciIrqNr[2]);
290 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"IntPinC\"")));
291
292 rc = pHlp->pfnCFGMQueryU32(pCfg, "IntPinD", &pPciRoot->u.GenericEcam.auPciIrqNr[3]);
293 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"IntPinD\"")));
294
295 Log(("PCI: fUseIoApic=%RTbool McfgBase=%#RX64 McfgLength=%#RX64 fR0Enabled=%RTbool fRCEnabled=%RTbool\n", pPciRoot->fUseIoApic,
296 pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength, pDevIns->fR0Enabled, pDevIns->fRCEnabled));
297 Log(("PCI: IntPinA=%u IntPinB=%u IntPinC=%u IntPinD=%u\n", pPciRoot->u.GenericEcam.auPciIrqNr[0],
298 pPciRoot->u.GenericEcam.auPciIrqNr[1], pPciRoot->u.GenericEcam.auPciIrqNr[2], pPciRoot->u.GenericEcam.auPciIrqNr[3]));
299
300 /*
301 * Init data.
302 */
303 /* And fill values */
304 pBusCC->pDevInsR3 = pDevIns;
305 pPciRoot->hIoPortAddress = NIL_IOMIOPORTHANDLE;
306 pPciRoot->hIoPortData = NIL_IOMIOPORTHANDLE;
307 pPciRoot->hIoPortMagic = NIL_IOMIOPORTHANDLE;
308 pPciRoot->hMmioMcfg = NIL_IOMMMIOHANDLE;
309 pPciRoot->hMmioPioEmu = NIL_IOMMMIOHANDLE;
310 pPciRoot->PciBus.enmType = DEVPCIBUSTYPE_GENERIC_ECAM;
311 pPciRoot->PciBus.fPureBridge = false;
312 pPciRoot->PciBus.papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pPciRoot->PciBus.apDevices));
313 AssertLogRelReturn(pPciRoot->PciBus.papBridgesR3, VERR_NO_MEMORY);
314
315 /*
316 * Disable default device locking.
317 */
318 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
319 AssertRCReturn(rc, rc);
320
321 /*
322 * Register bus
323 */
324 PDMPCIBUSREGCC PciBusReg;
325 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
326 PciBusReg.pfnRegisterR3 = devpciR3CommonRegisterDevice;
327 PciBusReg.pfnRegisterMsiR3 = NULL;
328 PciBusReg.pfnIORegionRegisterR3 = devpciR3CommonIORegionRegister;
329 PciBusReg.pfnInterceptConfigAccesses = devpciR3CommonInterceptConfigAccesses;
330 PciBusReg.pfnConfigRead = devpciR3CommonConfigRead;
331 PciBusReg.pfnConfigWrite = devpciR3CommonConfigWrite;
332 PciBusReg.pfnSetIrqR3 = pciGenEcamSetIrq;
333 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
334 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBusCC->pPciHlpR3, &pBus->iBus);
335 if (RT_FAILURE(rc))
336 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as a PCI Bus"));
337 Assert(pBus->iBus == 0);
338 if (pBusCC->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
339 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
340 N_("PCI helper version mismatch; got %#x expected %#x"),
341 pBusCC->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
342
343 /*
344 * Fill in PCI configs and add them to the bus.
345 */
346#if 0
347 /* Host bridge device */
348 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
349 AssertPtr(pPciDev);
350 PDMPciDevSetVendorId( pPciDev, 0x8086); /** @todo Intel */
351 PDMPciDevSetDeviceId( pPciDev, 0x29e0); /** @todo Desktop */
352 PDMPciDevSetRevisionId(pPciDev, 0x01); /* rev. 01 */
353 PDMPciDevSetClassBase( pPciDev, 0x06); /* bridge */
354 PDMPciDevSetClassSub( pPciDev, 0x00); /* Host/PCI bridge */
355 PDMPciDevSetClassProg( pPciDev, 0x00); /* Host/PCI bridge */
356 PDMPciDevSetHeaderType(pPciDev, 0x00); /* bridge */
357 PDMPciDevSetWord(pPciDev, VBOX_PCI_SEC_STATUS, 0x0280); /* secondary status */
358
359 rc = PDMDevHlpPCIRegisterEx(pDevIns, pPciDev, 0 /*fFlags*/, 0 /*uPciDevNo*/, 0 /*uPciFunNo*/, "Host");
360 AssertLogRelRCReturn(rc, rc);
361#endif
362
363 /*
364 * MMIO handlers.
365 */
366 if (pPciRoot->u64PciConfigMMioAddress != 0)
367 {
368 rc = PDMDevHlpMmioCreateAndMap(pDevIns, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength,
369 devpciCommonMcfgMmioWrite, devpciCommonMcfgMmioRead,
370 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
371 "ECAM window", &pPciRoot->hMmioMcfg);
372 AssertMsgRCReturn(rc, ("rc=%Rrc %#RX64/%#RX64\n", rc, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength), rc);
373 }
374
375 if (pPciRoot->GCPhysMmioPioEmuBase != 0)
376 {
377 rc = PDMDevHlpMmioCreateAndMap(pDevIns, pPciRoot->GCPhysMmioPioEmuBase, pPciRoot->GCPhysMmioPioEmuSize,
378 pciHostR3MmioPioWrite, pciHostR3MmioPioRead,
379 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
380 "PIO range", &pPciRoot->hMmioPioEmu);
381 AssertMsgRCReturn(rc, ("rc=%Rrc %#RGp/%#RGp\n", rc, pPciRoot->GCPhysMmioPioEmuBase, pPciRoot->GCPhysMmioPioEmuSize), rc);
382 }
383
384 /*
385 * Saved state and info handlers.
386 */
387 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_PCIGENECAM_SAVED_STATE_VERSION,
388 sizeof(*pBus) + 16*128, "pgm",
389 NULL, NULL, NULL,
390 NULL, devpciR3CommonSaveExec, NULL,
391 NULL, devpciR3CommonLoadExec, NULL);
392 AssertRCReturn(rc, rc);
393
394 PDMDevHlpDBGFInfoRegister(pDevIns, "pci",
395 "Display PCI bus status. Recognizes 'basic' or 'verbose' as arguments, defaults to 'basic'.",
396 devpciR3InfoPci);
397 PDMDevHlpDBGFInfoRegister(pDevIns, "pciirq", "Display PCI IRQ state. (no arguments)", devpciR3InfoPciIrq);
398
399 return VINF_SUCCESS;
400}
401
402
403/**
404 * @interface_method_impl{PDMDEVREG,pfnDestruct}
405 */
406static DECLCALLBACK(int) pciGenEcamR3Destruct(PPDMDEVINS pDevIns)
407{
408 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
409 if (pPciRoot->PciBus.papBridgesR3)
410 {
411 PDMDevHlpMMHeapFree(pDevIns, pPciRoot->PciBus.papBridgesR3);
412 pPciRoot->PciBus.papBridgesR3 = NULL;
413 }
414 return VINF_SUCCESS;
415}
416
417
418/**
419 * @interface_method_impl{PDMDEVREG,pfnReset}
420 */
421static DECLCALLBACK(void) pciGenEcamR3Reset(PPDMDEVINS pDevIns)
422{
423 /* Reset everything under the root bridge. */
424 devpciR3CommonResetBridge(pDevIns);
425}
426
427#else /* !IN_RING3 */
428
429/**
430 * @interface_method_impl{PDMDEVREGR0,pfnConstruct}
431 */
432DECLCALLBACK(int) pciGenEcamRZConstruct(PPDMDEVINS pDevIns)
433{
434 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
435 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
436 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
437
438 /* Mirror the ring-3 device lock disabling: */
439 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
440 AssertRCReturn(rc, rc);
441
442 /* Set up the RZ PCI bus callbacks: */
443 PDMPCIBUSREGCC PciBusReg;
444 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
445 PciBusReg.iBus = pPciRoot->PciBus.iBus;
446 PciBusReg.pfnSetIrq = pciGenEcamSetIrq;
447 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
448 rc = PDMDevHlpPCIBusSetUpContext(pDevIns, &PciBusReg, &pBusCC->CTX_SUFF(pPciHlp));
449 AssertRCReturn(rc, rc);
450
451 /* Set up MMIO callbacks: */
452 if (pPciRoot->hMmioMcfg != NIL_IOMMMIOHANDLE)
453 {
454 rc = PDMDevHlpMmioSetUpContext(pDevIns, pPciRoot->hMmioMcfg, devpciCommonMcfgMmioWrite, devpciCommonMcfgMmioRead, NULL /*pvUser*/);
455 AssertLogRelRCReturn(rc, rc);
456 }
457
458 return rc;
459}
460
461#endif /* !IN_RING3 */
462
463/**
464 * The PCI bus device registration structure.
465 */
466const PDMDEVREG g_DevicePciGenericEcam =
467{
468 /* .u32Version = */ PDM_DEVREG_VERSION,
469 /* .uReserved0 = */ 0,
470 /* .szName = */ "pci-generic-ecam",
471 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
472 /* .fClass = */ PDM_DEVREG_CLASS_BUS_PCI,
473 /* .cMaxInstances = */ 1,
474 /* .uSharedVersion = */ 42,
475 /* .cbInstanceShared = */ sizeof(DEVPCIROOT),
476 /* .cbInstanceCC = */ sizeof(CTX_SUFF(DEVPCIBUS)),
477 /* .cbInstanceRC = */ sizeof(DEVPCIBUSRC),
478 /* .cMaxPciDevices = */ 1,
479 /* .cMaxMsixVectors = */ 0,
480 /* .pszDescription = */ "Generic PCI host bridge (working with pci-host-ecam-generic driver)",
481#if defined(IN_RING3)
482 /* .pszRCMod = */ "VBoxDDRC.rc",
483 /* .pszR0Mod = */ "VBoxDDR0.r0",
484 /* .pfnConstruct = */ pciGenEcamR3Construct,
485 /* .pfnDestruct = */ pciGenEcamR3Destruct,
486 /* .pfnRelocate = */ NULL,
487 /* .pfnMemSetup = */ NULL,
488 /* .pfnPowerOn = */ NULL,
489 /* .pfnReset = */ pciGenEcamR3Reset,
490 /* .pfnSuspend = */ NULL,
491 /* .pfnResume = */ NULL,
492 /* .pfnAttach = */ NULL,
493 /* .pfnDetach = */ NULL,
494 /* .pfnQueryInterface = */ NULL,
495 /* .pfnInitComplete = */ NULL,
496 /* .pfnPowerOff = */ NULL,
497 /* .pfnSoftReset = */ NULL,
498 /* .pfnReserved0 = */ NULL,
499 /* .pfnReserved1 = */ NULL,
500 /* .pfnReserved2 = */ NULL,
501 /* .pfnReserved3 = */ NULL,
502 /* .pfnReserved4 = */ NULL,
503 /* .pfnReserved5 = */ NULL,
504 /* .pfnReserved6 = */ NULL,
505 /* .pfnReserved7 = */ NULL,
506#elif defined(IN_RING0)
507 /* .pfnEarlyConstruct = */ NULL,
508 /* .pfnConstruct = */ pciGenEcamRZConstruct,
509 /* .pfnDestruct = */ NULL,
510 /* .pfnFinalDestruct = */ NULL,
511 /* .pfnRequest = */ NULL,
512 /* .pfnReserved0 = */ NULL,
513 /* .pfnReserved1 = */ NULL,
514 /* .pfnReserved2 = */ NULL,
515 /* .pfnReserved3 = */ NULL,
516 /* .pfnReserved4 = */ NULL,
517 /* .pfnReserved5 = */ NULL,
518 /* .pfnReserved6 = */ NULL,
519 /* .pfnReserved7 = */ NULL,
520#elif defined(IN_RC)
521 /* .pfnConstruct = */ pciGenEcamRZConstruct,
522 /* .pfnReserved0 = */ NULL,
523 /* .pfnReserved1 = */ NULL,
524 /* .pfnReserved2 = */ NULL,
525 /* .pfnReserved3 = */ NULL,
526 /* .pfnReserved4 = */ NULL,
527 /* .pfnReserved5 = */ NULL,
528 /* .pfnReserved6 = */ NULL,
529 /* .pfnReserved7 = */ NULL,
530#else
531# error "Not in IN_RING3, IN_RING0 or IN_RC!"
532#endif
533 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
534};
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