VirtualBox

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

Last change on this file since 100766 was 100766, checked in by vboxsync, 16 months ago

Devices/Bus/DevPciGenericEcam: Fixes for saved state loading, need to save and restore the PCI interrupt levels of course, bugref:10445

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