VirtualBox

source: vbox/trunk/src/VBox/Devices/Bus/DevPciIch9.cpp@ 85726

Last change on this file since 85726 was 85490, checked in by vboxsync, 4 years ago

DevPciIch9.cpp: indent fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 168.6 KB
Line 
1/* $Id: DevPciIch9.cpp 85490 2020-07-28 15:57:10Z vboxsync $ */
2/** @file
3 * DevPCI - ICH9 southbridge PCI bus emulation device.
4 *
5 * @remarks We'll be slowly promoting the code in this file to common PCI bus
6 * code. Function without 'static' and using 'devpci' as prefix is
7 * also used by DevPCI.cpp and have a prototype in DevPciInternal.h.
8 *
9 * For the time being the DevPciMerge1.cpp.h file will remain separate,
10 * due to 5.1. We can merge it into this one later in the dev cycle.
11 *
12 * DO NOT use the PDMPciDev* or PCIDev* family of functions in this
13 * file except in the two callbacks for config space access (and the
14 * functions which are used exclusively by that code) and the two
15 * device constructors when setting up the config space for the
16 * bridges. Everything else need extremely careful review. Using
17 * them elsewhere (especially in the init code) causes weird failures
18 * with PCI passthrough, as it would only update the array of
19 * (emulated) config space, but not talk to the actual device (needs
20 * invoking the respective callback).
21 */
22
23/*
24 * Copyright (C) 2010-2020 Oracle Corporation
25 *
26 * This file is part of VirtualBox Open Source Edition (OSE), as
27 * available from http://www.virtualbox.org. This file is free software;
28 * you can redistribute it and/or modify it under the terms of the GNU
29 * General Public License (GPL) as published by the Free Software
30 * Foundation, in version 2 as it comes in the "COPYING" file of the
31 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
32 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
33 */
34
35
36/*********************************************************************************************************************************
37* Header Files *
38*********************************************************************************************************************************/
39#define LOG_GROUP LOG_GROUP_DEV_PCI
40#define PDMPCIDEV_INCLUDE_PRIVATE /* Hack to get pdmpcidevint.h included at the right point. */
41#include <VBox/vmm/pdmpcidev.h>
42
43#include <VBox/AssertGuest.h>
44#include <VBox/msi.h>
45#include <VBox/vmm/pdmdev.h>
46#include <VBox/vmm/mm.h>
47#include <iprt/asm.h>
48#include <iprt/assert.h>
49#include <iprt/string.h>
50#ifdef IN_RING3
51# include <iprt/mem.h>
52# include <iprt/uuid.h>
53#endif
54
55#include "PciInline.h"
56#include "VBoxDD.h"
57#include "MsiCommon.h"
58#include "DevPciInternal.h"
59
60
61/*********************************************************************************************************************************
62* Structures and Typedefs *
63*********************************************************************************************************************************/
64/**
65 * PCI configuration space address.
66 */
67typedef struct
68{
69 uint8_t iBus;
70 uint8_t iDeviceFunc;
71 uint16_t iRegister;
72} PciAddress;
73
74
75/*********************************************************************************************************************************
76* Defined Constants And Macros *
77*********************************************************************************************************************************/
78/** Saved state version of the ICH9 PCI bus device. */
79#define VBOX_ICH9PCI_SAVED_STATE_VERSION VBOX_ICH9PCI_SAVED_STATE_VERSION_4KB_CFG_SPACE
80/** 4KB config space */
81#define VBOX_ICH9PCI_SAVED_STATE_VERSION_4KB_CFG_SPACE 4
82/** Adds I/O region types and sizes for dealing changes in resource regions. */
83#define VBOX_ICH9PCI_SAVED_STATE_VERSION_REGION_SIZES 3
84/** This appears to be the first state we need to care about. */
85#define VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI 2
86/** This is apparently not supported or has a grossly incomplete state, juding
87 * from hints in the code. */
88#define VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI 1
89
90/** Invalid PCI region mapping address. */
91#define INVALID_PCI_ADDRESS UINT32_MAX
92
93
94/*********************************************************************************************************************************
95* Internal Functions *
96*********************************************************************************************************************************/
97/* Prototypes */
98static void ich9pciSetIrqInternal(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUSCC pBusCC,
99 uint8_t uDevFn, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc);
100#ifdef IN_RING3
101static int ich9pciFakePCIBIOS(PPDMDEVINS pDevIns);
102DECLINLINE(PPDMPCIDEV) ich9pciFindBridge(PDEVPCIBUS pBus, uint8_t uBus);
103static void ich9pciBiosInitAllDevicesOnBus(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus);
104static bool ich9pciBiosInitAllDevicesPrefetchableOnBus(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus, bool fUse64Bit, bool fDryrun);
105#endif
106
107
108/**
109 * See 7.2.2. PCI Express Enhanced Configuration Mechanism for details of address
110 * mapping, we take n=6 approach
111 */
112DECLINLINE(void) ich9pciPhysToPciAddr(PDEVPCIROOT pPciRoot, RTGCPHYS off, PciAddress *pPciAddr)
113{
114 NOREF(pPciRoot);
115 pPciAddr->iBus = (off >> 20) & ((1<<6) - 1);
116 pPciAddr->iDeviceFunc = (off >> 12) & ((1<<(5+3)) - 1); // 5 bits - device, 3 bits - function
117 pPciAddr->iRegister = (off >> 0) & ((1<<(6+4+2)) - 1); // 6 bits - register, 4 bits - extended register, 2 bits -Byte Enable
118 RT_UNTRUSTED_VALIDATED_FENCE(); /* paranoia */
119}
120
121DECLINLINE(void) ich9pciStateToPciAddr(PDEVPCIROOT pPciRoot, RTGCPHYS addr, PciAddress *pPciAddr)
122{
123 pPciAddr->iBus = (pPciRoot->uConfigReg >> 16) & 0xff;
124 pPciAddr->iDeviceFunc = (pPciRoot->uConfigReg >> 8) & 0xff;
125 pPciAddr->iRegister = (pPciRoot->uConfigReg & 0xfc) | (addr & 3);
126 RT_UNTRUSTED_VALIDATED_FENCE(); /* paranoia */
127}
128
129static DECLCALLBACK(void) ich9pciSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
130{
131 LogFlowFunc(("invoked by %p/%d: iIrq=%d iLevel=%d uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, iIrq, iLevel, uTagSrc));
132 ich9pciSetIrqInternal(pDevIns, PDMINS_2_DATA(pDevIns, PDEVPCIROOT), PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC),
133 pPciDev->uDevFn, pPciDev, iIrq, iLevel, uTagSrc);
134}
135
136/**
137 * Worker for ich9pcibridgeSetIrq and pcibridgeSetIrq that walks up to the root
138 * bridges and permutates iIrq accordingly.
139 *
140 * See ich9pciBiosInitAllDevicesOnBus for corresponding configuration code.
141 */
142DECLHIDDEN(PPDMDEVINS) devpcibridgeCommonSetIrqRootWalk(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq,
143 PDEVPCIBUS *ppBus, uint8_t *puDevFnBridge, int *piIrqPinBridge)
144{
145 PDEVPCIBUSCC const pBridgeBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC); /* For keep using our own pcihlp. */
146 PPDMDEVINS const pBridgeDevIns = pDevIns; /* ditto */
147
148 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
149 PPDMDEVINS pDevInsBus;
150 PPDMPCIDEV pPciDevBus = pDevIns->apPciDevs[0];
151 uint8_t uDevFnBridge = pPciDevBus->uDevFn;
152 int iIrqPinBridge = ((pPciDev->uDevFn >> 3) + iIrq) & 3;
153 uint64_t bmSeen[256/64] = { 0, 0, 0, 0 };
154 AssertCompile(sizeof(pPciDevBus->Int.s.idxPdmBus) == 1);
155 ASMBitSet(bmSeen, pPciDevBus->Int.s.idxPdmBus);
156
157 /* Walk the chain until we reach the host bus. */
158 Assert(pBus->iBus != 0);
159 for (;;)
160 {
161 /* Get the parent. */
162 pDevInsBus = pBridgeBusCC->CTX_SUFF(pPciHlp)->pfnGetBusByNo(pBridgeDevIns, pPciDevBus->Int.s.idxPdmBus);
163 AssertLogRelReturn(pDevInsBus, NULL);
164
165 pBus = PDMINS_2_DATA(pDevInsBus, PDEVPCIBUS);
166 pPciDevBus = pDevInsBus->apPciDevs[0];
167 if (pBus->iBus == 0)
168 {
169 *ppBus = pBus;
170 *puDevFnBridge = uDevFnBridge;
171 *piIrqPinBridge = iIrqPinBridge;
172 return pDevInsBus;
173 }
174
175 uDevFnBridge = pPciDevBus->uDevFn;
176 iIrqPinBridge = ((uDevFnBridge >> 3) + iIrqPinBridge) & 3;
177
178 /* Make sure that we cannot end up in a loop here: */
179 AssertCompile(sizeof(pPciDevBus->Int.s.idxPdmBus) == 1);
180 AssertMsgReturn(ASMBitTestAndSet(bmSeen, pPciDevBus->Int.s.idxPdmBus),
181 ("idxPdmBus=%u\n", pPciDevBus->Int.s.idxPdmBus),
182 NULL);
183 }
184
185}
186
187static DECLCALLBACK(void) ich9pcibridgeSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
188{
189 /*
190 * The PCI-to-PCI bridge specification defines how the interrupt pins
191 * are routed from the secondary to the primary bus (see chapter 9).
192 * iIrq gives the interrupt pin the pci device asserted.
193 * We change iIrq here according to the spec and call the SetIrq function
194 * of our parent passing the device which asserted the interrupt instead of the device of the bridge.
195 *
196 * See ich9pciBiosInitAllDevicesOnBus for corresponding configuration code.
197 */
198 PDEVPCIBUS pBus;
199 uint8_t uDevFnBridge;
200 int iIrqPinBridge;
201 PPDMDEVINS pDevInsBus = devpcibridgeCommonSetIrqRootWalk(pDevIns, pPciDev, iIrq, &pBus, &uDevFnBridge, &iIrqPinBridge);
202 AssertReturnVoid(pDevInsBus);
203 AssertMsg(pBus->iBus == 0, ("This is not the host pci bus iBus=%d\n", pBus->iBus));
204 Assert(pDevInsBus->pReg == &g_DevicePciIch9); /* ASSUMPTION: Same style root bus. Need callback interface to mix types. */
205
206 /*
207 * For MSI/MSI-X enabled devices the iIrq doesn't denote the pin but rather a vector which is completely
208 * orthogonal to the pin based approach. The vector is not subject to the pin based routing with PCI bridges.
209 */
210 int iIrqPinVector = iIrqPinBridge;
211 if ( MsiIsEnabled(pPciDev)
212 || MsixIsEnabled(pPciDev))
213 iIrqPinVector = iIrq;
214 ich9pciSetIrqInternal(pDevInsBus, DEVPCIBUS_2_DEVPCIROOT(pBus), PDMINS_2_DATA_CC(pDevInsBus, PDEVPCIBUSCC),
215 uDevFnBridge, pPciDev, iIrqPinVector, iLevel, uTagSrc);
216}
217
218#ifdef IN_RING3
219
220/**
221 * @callback_method_impl{FNIOMIOPORTNEWOUT,
222 * Port I/O Handler for Fake PCI BIOS trigger OUT operations at 0410h.}
223 */
224static DECLCALLBACK(VBOXSTRICTRC)
225ich9pciR3IOPortMagicPCIWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
226{
227 Assert(offPort == 0); RT_NOREF2(pvUser, offPort);
228 LogFlowFunc(("offPort=%#x u32=%#x cb=%d\n", offPort, u32, cb));
229 if (cb == 4)
230 {
231 if (u32 == UINT32_C(19200509)) // Richard Adams
232 {
233 int rc = ich9pciFakePCIBIOS(pDevIns);
234 AssertRC(rc);
235 }
236 }
237
238 return VINF_SUCCESS;
239}
240
241
242/**
243 * @callback_method_impl{FNIOMIOPORTNEWIN,
244 * Port I/O Handler for Fake PCI BIOS trigger IN operations at 0410h.}
245 */
246static DECLCALLBACK(VBOXSTRICTRC)
247ich9pciR3IOPortMagicPCIRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
248{
249 Assert(offPort == 0); RT_NOREF5(pDevIns, pvUser, offPort, pu32, cb);
250 LogFunc(("offPort=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", offPort, cb));
251 return VERR_IOM_IOPORT_UNUSED;
252}
253
254#endif /* IN_RING3 */
255
256/**
257 * @callback_method_impl{FNIOMIOPORTNEWOUT,
258 * Port I/O Handler for PCI address OUT operations.}
259 *
260 * Emulates writes to Configuration Address Port at 0CF8h for Configuration
261 * Mechanism \#1.
262 */
263static DECLCALLBACK(VBOXSTRICTRC)
264ich9pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
265{
266 LogFlowFunc(("offPort=%#x u32=%#x cb=%d\n", offPort, u32, cb));
267 Assert(offPort == 0); RT_NOREF2(offPort, pvUser);
268 if (cb == 4)
269 {
270 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
271
272 /*
273 * bits [1:0] are hard-wired, read-only and must return zeroes
274 * when read.
275 */
276 u32 &= ~3;
277
278 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
279 pThis->uConfigReg = u32;
280 PCI_UNLOCK(pDevIns);
281 }
282
283 return VINF_SUCCESS;
284}
285
286
287/**
288 * @callback_method_impl{FNIOMIOPORTNEWIN,
289 * Port I/O Handler for PCI data IN operations.}
290 *
291 * Emulates reads from Configuration Address Port at 0CF8h for Configuration
292 * Mechanism \#1.
293 */
294static DECLCALLBACK(VBOXSTRICTRC)
295ich9pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
296{
297 Assert(offPort == 0); RT_NOREF2(offPort, pvUser);
298 if (cb == 4)
299 {
300 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
301
302 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_READ);
303 *pu32 = pThis->uConfigReg;
304 PCI_UNLOCK(pDevIns);
305
306 LogFlowFunc(("offPort=%#x cb=%d -> %#x\n", offPort, cb, *pu32));
307 return VINF_SUCCESS;
308 }
309
310 LogFunc(("offPort=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", offPort, cb));
311 return VERR_IOM_IOPORT_UNUSED;
312}
313
314
315/**
316 * Perform configuration space write.
317 */
318static VBOXSTRICTRC ich9pciConfigWrite(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PciAddress const *pPciAddr,
319 uint32_t u32Value, int cb, int rcReschedule)
320{
321 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
322
323 if (pPciAddr->iBus != 0) /* forward to subordinate bus */
324 {
325 if (pPciRoot->PciBus.cBridges)
326 {
327#ifdef IN_RING3 /** @todo do lookup in R0/RC too! r=klaus don't think that it can work, since the config space access callback only works in R3 */
328 PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(&pPciRoot->PciBus, pPciAddr->iBus);
329 if (pBridgeDevice)
330 {
331 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
332 rcStrict = pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), pPciAddr->iBus,
333 pPciAddr->iDeviceFunc, pPciAddr->iRegister, cb, u32Value);
334 }
335#else
336 rcStrict = rcReschedule;
337#endif
338 }
339 }
340 else /* forward to directly connected device */
341 {
342 R3PTRTYPE(PDMPCIDEV *) pPciDev = pPciRoot->PciBus.apDevices[pPciAddr->iDeviceFunc];
343 if (pPciDev)
344 {
345#ifdef IN_RING3
346 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
347 if (pPciDev->Int.s.pfnConfigWrite)
348 rcStrict = pPciDev->Int.s.pfnConfigWrite(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev,
349 pPciAddr->iRegister, cb, u32Value);
350 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
351 rcStrict = devpciR3CommonConfigWriteWorker(pDevIns, PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC),
352 pPciDev, pPciAddr->iRegister, cb, u32Value);
353 RT_NOREF(rcReschedule);
354#else
355 rcStrict = rcReschedule;
356 RT_NOREF(pDevIns, u32Value, cb);
357#endif
358 }
359 }
360
361 Log2Func(("%02x:%02x.%u reg %x(%u) %x %Rrc\n", pPciAddr->iBus, pPciAddr->iDeviceFunc >> 3, pPciAddr->iDeviceFunc & 0x7,
362 pPciAddr->iRegister, cb, u32Value, VBOXSTRICTRC_VAL(rcStrict)));
363 return rcStrict;
364}
365
366
367/**
368 * @callback_method_impl{FNIOMIOPORTNEWOUT,
369 * Port I/O Handler for PCI data OUT operations.}
370 *
371 * Emulates writes to Configuration Data Port at 0CFCh for Configuration
372 * Mechanism \#1.
373 */
374static DECLCALLBACK(VBOXSTRICTRC)
375ich9pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
376{
377 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
378 LogFlowFunc(("offPort=%u u32=%#x cb=%d (config=%#10x)\n", offPort, u32, cb, pThis->uConfigReg));
379 Assert(offPort < 4); NOREF(pvUser);
380
381 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
382 if (!(offPort % cb))
383 {
384 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
385
386 if (pThis->uConfigReg & (1 << 31))
387 {
388
389 /* Decode target device from Configuration Address Port */
390 PciAddress aPciAddr;
391 ich9pciStateToPciAddr(pThis, offPort, &aPciAddr);
392
393 /* Perform configuration space write */
394 rcStrict = ich9pciConfigWrite(pDevIns, pThis, &aPciAddr, u32, cb, VINF_IOM_R3_IOPORT_WRITE);
395 }
396
397 PCI_UNLOCK(pDevIns);
398 }
399 else
400 AssertMsgFailed(("Unaligned write to offPort=%u u32=%#x cb=%d\n", offPort, u32, cb));
401
402 return rcStrict;
403}
404
405
406/**
407 * Perform configuration space read.
408 */
409static VBOXSTRICTRC ich9pciConfigRead(PDEVPCIROOT pPciRoot, PciAddress* pPciAddr, int cb, uint32_t *pu32Value, int rcReschedule)
410{
411 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
412#ifdef IN_RING3
413 NOREF(rcReschedule);
414#else
415 NOREF(cb);
416#endif
417
418 if (pPciAddr->iBus != 0) /* forward to subordinate bus */
419 {
420 if (pPciRoot->PciBus.cBridges)
421 {
422#ifdef IN_RING3 /** @todo do lookup in R0/RC too! r=klaus don't think that it can work, since the config space access callback only works in R3 */
423 PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(&pPciRoot->PciBus, pPciAddr->iBus);
424 if (pBridgeDevice)
425 {
426 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
427 rcStrict = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), pPciAddr->iBus,
428 pPciAddr->iDeviceFunc, pPciAddr->iRegister, cb, pu32Value);
429 }
430 else
431 *pu32Value = UINT32_MAX;
432#else
433 rcStrict = rcReschedule;
434#endif
435 }
436 else
437 *pu32Value = 0xffffffff;
438 }
439 else /* forward to directly connected device */
440 {
441 R3PTRTYPE(PDMPCIDEV *) pPciDev = pPciRoot->PciBus.apDevices[pPciAddr->iDeviceFunc];
442 if (pPciDev)
443 {
444#ifdef IN_RING3
445 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
446 if (pPciDev->Int.s.pfnConfigRead)
447 rcStrict = pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev,
448 pPciAddr->iRegister, cb, pu32Value);
449 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
450 rcStrict = devpciR3CommonConfigReadWorker(pPciDev, pPciAddr->iRegister, cb, pu32Value);
451#else
452 rcStrict = rcReschedule;
453#endif
454 }
455 else
456 *pu32Value = UINT32_MAX;
457 }
458
459 Log3Func(("%02x:%02x.%d reg %x(%d) gave %x %Rrc\n", pPciAddr->iBus, pPciAddr->iDeviceFunc >> 3, pPciAddr->iDeviceFunc & 0x7,
460 pPciAddr->iRegister, cb, *pu32Value, VBOXSTRICTRC_VAL(rcStrict) ));
461 return rcStrict;
462}
463
464
465/**
466 * @callback_method_impl{FNIOMIOPORTNEWIN,
467 * Port I/O Handler for PCI data IN operations.}
468 *
469 * Emulates reads from Configuration Data Port at 0CFCh for Configuration
470 * Mechanism \#1.
471 */
472static DECLCALLBACK(VBOXSTRICTRC)
473ich9pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
474{
475 NOREF(pvUser);
476 Assert(offPort < 4);
477 if (!(offPort % cb))
478 {
479 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
480 *pu32 = 0xffffffff;
481
482 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_READ);
483
484 /* Configuration space mapping enabled? */
485 VBOXSTRICTRC rcStrict;
486 if (!(pThis->uConfigReg & (1 << 31)))
487 rcStrict = VINF_SUCCESS;
488 else
489 {
490 /* Decode target device and configuration space register */
491 PciAddress aPciAddr;
492 ich9pciStateToPciAddr(pThis, offPort, &aPciAddr);
493
494 /* Perform configuration space read */
495 rcStrict = ich9pciConfigRead(pThis, &aPciAddr, cb, pu32, VINF_IOM_R3_IOPORT_READ);
496 }
497
498 PCI_UNLOCK(pDevIns);
499
500 LogFlowFunc(("offPort=%u cb=%#x (config=%#10x) -> %#x (%Rrc)\n", offPort, cb, *pu32, pThis->uConfigReg, VBOXSTRICTRC_VAL(rcStrict)));
501 return rcStrict;
502 }
503 AssertMsgFailed(("Unaligned read from offPort=%u cb=%d\n", offPort, cb));
504 return VERR_IOM_IOPORT_UNUSED;
505}
506
507
508/* Compute mapping of PCI slot and IRQ number to APIC interrupt line */
509DECLINLINE(int) ich9pciSlot2ApicIrq(uint8_t uSlot, int irq_num)
510{
511 return (irq_num + uSlot) & 7;
512}
513
514#ifdef IN_RING3
515
516/* return the global irq number corresponding to a given device irq
517 pin. We could also use the bus number to have a more precise
518 mapping. This is the implementation note described in the PCI spec chapter 2.2.6 */
519DECLINLINE(int) ich9pciSlotGetPirq(uint8_t uBus, uint8_t uDevFn, uint8_t uIrqNum)
520{
521 NOREF(uBus);
522 int iSlotAddend = (uDevFn >> 3) - 1;
523 return (uIrqNum + iSlotAddend) & 3;
524}
525
526/* irqs corresponding to PCI irqs A-D, must match pci_irq_list in pcibios.inc */
527/** @todo r=klaus inconsistent! ich9 doesn't implement PIRQ yet, so both needs to be addressed and tested thoroughly. */
528static const uint8_t aPciIrqs[4] = { 11, 10, 9, 5 };
529
530#endif /* IN_RING3 */
531
532/* Add one more level up request on APIC input line */
533DECLINLINE(void) ich9pciApicLevelUp(PDEVPCIROOT pPciRoot, int irq_num)
534{
535 ASMAtomicIncU32(&pPciRoot->auPciApicIrqLevels[irq_num]);
536}
537
538/* Remove one level up request on APIC input line */
539DECLINLINE(void) ich9pciApicLevelDown(PDEVPCIROOT pPciRoot, int irq_num)
540{
541 ASMAtomicDecU32(&pPciRoot->auPciApicIrqLevels[irq_num]);
542}
543
544static void ich9pciApicSetIrq(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PDEVPCIBUSCC pBusCC,
545 uint8_t uDevFn, PDMPCIDEV *pPciDev, int irq_num1, int iLevel, uint32_t uTagSrc, int iForcedIrq)
546{
547 /* This is only allowed to be called with a pointer to the root bus. */
548 AssertMsg(pBus->iBus == 0, ("iBus=%u\n", pBus->iBus));
549 uint16_t const uBusDevFn = PCIBDF_MAKE(pBus->iBus, uDevFn);
550
551 if (iForcedIrq == -1)
552 {
553 int apic_irq, apic_level;
554 PDEVPCIROOT pPciRoot = DEVPCIBUS_2_DEVPCIROOT(pBus);
555 int irq_num = ich9pciSlot2ApicIrq(uDevFn >> 3, irq_num1);
556
557 if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_HIGH)
558 ich9pciApicLevelUp(pPciRoot, irq_num);
559 else if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_LOW)
560 ich9pciApicLevelDown(pPciRoot, irq_num);
561
562 apic_irq = irq_num + 0x10;
563 apic_level = pPciRoot->auPciApicIrqLevels[irq_num] != 0;
564 Log3Func(("%s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d uTagSrc=%#x\n",
565 R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, apic_irq, apic_level, irq_num, uTagSrc));
566 pBusCC->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pDevIns, uBusDevFn, apic_irq, apic_level, uTagSrc);
567
568 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
569 {
570 /*
571 * we raised it few lines above, as PDM_IRQ_LEVEL_FLIP_FLOP has
572 * PDM_IRQ_LEVEL_HIGH bit set
573 */
574 ich9pciApicLevelDown(pPciRoot, irq_num);
575 pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
576 apic_level = pPciRoot->auPciApicIrqLevels[irq_num] != 0;
577 Log3Func(("%s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d uTagSrc=%#x (flop)\n",
578 R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, apic_irq, apic_level, irq_num, uTagSrc));
579 pBusCC->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pDevIns, uBusDevFn, apic_irq, apic_level, uTagSrc);
580 }
581 } else {
582 Log3Func(("(forced) %s: irq_num1=%d level=%d acpi_irq=%d uTagSrc=%#x\n",
583 R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, iForcedIrq, uTagSrc));
584 pBusCC->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pDevIns, uBusDevFn, iForcedIrq, iLevel, uTagSrc);
585 }
586}
587
588static void ich9pciSetIrqInternal(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUSCC pBusCC,
589 uint8_t uDevFn, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
590{
591 /* If MSI or MSI-X is enabled, PCI INTx# signals are disabled regardless of the PCI command
592 * register interrupt bit state.
593 * PCI 3.0 (section 6.8) forbids MSI and MSI-X to be enabled at the same time and makes
594 * that undefined behavior. We check for MSI first, then MSI-X.
595 */
596 if (MsiIsEnabled(pPciDev))
597 {
598 Assert(!MsixIsEnabled(pPciDev)); /* Not allowed -- see note above. */
599 LogFlowFunc(("PCI Dev %p : MSI\n", pPciDev));
600 MsiNotify(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel, uTagSrc);
601 return;
602 }
603
604 if (MsixIsEnabled(pPciDev))
605 {
606 LogFlowFunc(("PCI Dev %p : MSI-X\n", pPciDev));
607 MsixNotify(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel, uTagSrc);
608 return;
609 }
610
611 PDEVPCIBUS pBus = &pPciRoot->PciBus;
612 /* safe, only needs to go to the config space array */
613 const bool fIsAcpiDevice = PDMPciDevGetDeviceId(pPciDev) == 0x7113;
614
615 LogFlowFunc(("PCI Dev %p : IRQ\n", pPciDev));
616 /* Check if the state changed. */
617 if (pPciDev->Int.s.uIrqPinState != iLevel)
618 {
619 pPciDev->Int.s.uIrqPinState = (iLevel & PDM_IRQ_LEVEL_HIGH);
620
621 /** @todo r=klaus: implement PIRQ handling (if APIC isn't active). Needed for legacy OSes which don't use the APIC stuff. */
622
623 /* Send interrupt to I/O APIC only now. */
624 if (fIsAcpiDevice)
625 /*
626 * ACPI needs special treatment since SCI is hardwired and
627 * should not be affected by PCI IRQ routing tables at the
628 * same time SCI IRQ is shared in PCI sense hence this
629 * kludge (i.e. we fetch the hardwired value from ACPIs
630 * PCI device configuration space).
631 */
632 /* safe, only needs to go to the config space array */
633 ich9pciApicSetIrq(pDevIns, pBus, pBusCC, uDevFn, pPciDev, -1, iLevel, uTagSrc, PDMPciDevGetInterruptLine(pPciDev));
634 else
635 ich9pciApicSetIrq(pDevIns, pBus, pBusCC, uDevFn, pPciDev, iIrq, iLevel, uTagSrc, -1);
636 }
637}
638
639
640/**
641 * @callback_method_impl{FNIOMMMIONEWWRITE,
642 * Emulates writes to configuration space.}
643 */
644static DECLCALLBACK(VBOXSTRICTRC) ich9pciMcfgMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
645{
646 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
647 Log2Func(("%RGp LB %d\n", off, cb));
648 NOREF(pvUser);
649
650 /* Decode target device and configuration space register */
651 PciAddress aDest;
652 ich9pciPhysToPciAddr(pPciRoot, off, &aDest);
653
654 /* Get the value. */
655 uint32_t u32;
656 switch (cb)
657 {
658 case 1:
659 u32 = *(uint8_t const *)pv;
660 break;
661 case 2:
662 u32 = *(uint16_t const *)pv;
663 break;
664 case 4:
665 u32 = *(uint32_t const *)pv;
666 break;
667 default:
668 ASSERT_GUEST_MSG_FAILED(("cb=%u off=%RGp\n", cb, off)); /** @todo how the heck should this work? Split it, right? */
669 u32 = 0;
670 break;
671 }
672
673 /* Perform configuration space write */
674 PCI_LOCK(pDevIns, VINF_IOM_R3_MMIO_WRITE);
675 VBOXSTRICTRC rcStrict = ich9pciConfigWrite(pDevIns, pPciRoot, &aDest, u32, cb, VINF_IOM_R3_MMIO_WRITE);
676 PCI_UNLOCK(pDevIns);
677
678 return rcStrict;
679}
680
681
682/**
683 * @callback_method_impl{FNIOMMMIONEWWRITE,
684 * Emulates reads from configuration space.}
685 */
686static DECLCALLBACK(VBOXSTRICTRC) ich9pciMcfgMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
687{
688 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
689 LogFlowFunc(("%RGp LB %u\n", off, cb));
690 NOREF(pvUser);
691
692 /* Decode target device and configuration space register */
693 PciAddress aDest;
694 ich9pciPhysToPciAddr(pPciRoot, off, &aDest);
695
696 /* Perform configuration space read */
697 uint32_t u32Value = 0;
698 PCI_LOCK(pDevIns, VINF_IOM_R3_MMIO_READ);
699 VBOXSTRICTRC rcStrict = ich9pciConfigRead(pPciRoot, &aDest, cb, &u32Value, VINF_IOM_R3_MMIO_READ);
700 PCI_UNLOCK(pDevIns);
701
702 if (RT_SUCCESS(rcStrict)) /** @todo this is wrong, though it probably works fine due to double buffering... */
703 {
704 switch (cb)
705 {
706 case 1:
707 *(uint8_t *)pv = (uint8_t)u32Value;
708 break;
709 case 2:
710 *(uint16_t *)pv = (uint16_t)u32Value;
711 break;
712 case 4:
713 *(uint32_t *)pv = u32Value;
714 break;
715 default:
716 ASSERT_GUEST_MSG_FAILED(("cb=%u off=%RGp\n", cb, off)); /** @todo how the heck should this work? Split it, right? */
717 break;
718 }
719 }
720
721 return VBOXSTRICTRC_TODO(rcStrict);
722}
723
724#ifdef IN_RING3
725
726DECLINLINE(PPDMPCIDEV) ich9pciFindBridge(PDEVPCIBUS pBus, uint8_t uBus)
727{
728 /* Search for a fitting bridge. */
729 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
730 {
731 /*
732 * Examine secondary and subordinate bus number.
733 * If the target bus is in the range we pass the request on to the bridge.
734 */
735 PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
736 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
737 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
738 /* safe, only needs to go to the config space array */
739 uint32_t uSecondary = PDMPciDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS);
740 /* safe, only needs to go to the config space array */
741 uint32_t uSubordinate = PDMPciDevGetByte(pBridge, VBOX_PCI_SUBORDINATE_BUS);
742 Log3Func(("bus %p, bridge %d: %d in %d..%d\n", pBus, iBridge, uBus, uSecondary, uSubordinate));
743 if (uBus >= uSecondary && uBus <= uSubordinate)
744 return pBridge;
745 }
746
747 /* Nothing found. */
748 return NULL;
749}
750
751uint32_t devpciR3GetCfg(PPDMPCIDEV pPciDev, int32_t iRegister, int cb)
752{
753 uint32_t u32Value = UINT32_MAX;
754 VBOXSTRICTRC rcStrict = VINF_PDM_PCI_DO_DEFAULT;
755 if (pPciDev->Int.s.pfnConfigRead)
756 rcStrict = pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, iRegister, cb, &u32Value);
757 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
758 rcStrict = devpciR3CommonConfigReadWorker(pPciDev, iRegister, cb, &u32Value);
759 AssertRCSuccess(VBOXSTRICTRC_VAL(rcStrict));
760 return u32Value;
761}
762
763DECLINLINE(uint32_t) devpciGetRegionReg(int iRegion)
764{
765 return iRegion == VBOX_PCI_ROM_SLOT
766 ? VBOX_PCI_ROM_ADDRESS : (VBOX_PCI_BASE_ADDRESS_0 + iRegion * 4);
767}
768
769/**
770 * Worker for devpciR3SetByte(), devpciR3SetWord() and devpciR3SetDWord(), also
771 * used during state restore.
772 */
773void devpciR3SetCfg(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int32_t iRegister, uint32_t u32Value, int cb)
774{
775 Assert(cb <= 4 && cb != 3);
776 VBOXSTRICTRC rcStrict = VINF_PDM_PCI_DO_DEFAULT;
777 if (pPciDev->Int.s.pfnConfigWrite)
778 rcStrict = pPciDev->Int.s.pfnConfigWrite(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, iRegister, cb, u32Value);
779 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
780 rcStrict = devpciR3CommonConfigWriteWorker(pDevIns, PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC),
781 pPciDev, iRegister, cb, u32Value);
782 AssertRCSuccess(VBOXSTRICTRC_VAL(rcStrict));
783}
784
785
786/* -=-=-=-=-=- PCI Bus Interface Methods (PDMPCIBUSREG) -=-=-=-=-=- */
787
788/**
789 * Search for a completely unused device entry (all 8 functions are unused).
790 *
791 * @returns VBox status code.
792 * @param pBus The bus to register with.
793 * @remarks Caller enters the PDM critical section.
794 */
795static uint8_t devpciR3CommonFindUnusedDeviceNo(PDEVPCIBUS pBus)
796{
797 for (uint8_t uPciDevNo = pBus->iDevSearch >> VBOX_PCI_DEVFN_DEV_SHIFT; uPciDevNo < VBOX_PCI_MAX_DEVICES; uPciDevNo++)
798 if ( !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 0)]
799 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 1)]
800 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 2)]
801 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 3)]
802 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 4)]
803 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 5)]
804 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 6)]
805 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 7)])
806 return uPciDevNo;
807 return UINT8_MAX;
808}
809
810
811
812/**
813 * Registers the device with the specified PCI bus.
814 *
815 * This is shared between the pci bus and pci bridge code.
816 *
817 * @returns VBox status code.
818 * @param pDevIns The PCI bus device instance.
819 * @param pBus The bus to register with.
820 * @param pPciDev The PCI device structure.
821 * @param fFlags Reserved for future use, PDMPCIDEVREG_F_MBZ.
822 * @param uPciDevNo PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, or a specific
823 * device number (0-31).
824 * @param uPciFunNo PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific
825 * function number (0-7).
826 * @param pszName Device name (static but not unique).
827 *
828 * @remarks Caller enters the PDM critical section.
829 */
830static int devpciR3CommonRegisterDeviceOnBus(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev, uint32_t fFlags,
831 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
832{
833 RT_NOREF(pDevIns);
834
835 /*
836 * Validate input.
837 */
838 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
839 AssertPtrReturn(pPciDev, VERR_INVALID_POINTER);
840 AssertReturn(!(fFlags & ~PDMPCIDEVREG_F_VALID_MASK), VERR_INVALID_FLAGS);
841 AssertReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES || uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER);
842 AssertReturn(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS || uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER);
843
844 /*
845 * Assign device & function numbers.
846 */
847
848 /* Work the optional assignment flag. */
849 if (fFlags & PDMPCIDEVREG_F_NOT_MANDATORY_NO)
850 {
851 AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES && uPciFunNo < VBOX_PCI_MAX_FUNCTIONS,
852 ("PDMPCIDEVREG_F_NOT_MANDATORY_NO not implemented for #Dev=%#x / #Fun=%#x\n", uPciDevNo, uPciFunNo),
853 VERR_NOT_IMPLEMENTED);
854 if (pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)])
855 {
856 uPciDevNo = PDMPCIDEVREG_DEV_NO_FIRST_UNUSED;
857 uPciFunNo = PDMPCIDEVREG_FUN_NO_FIRST_UNUSED;
858 }
859 }
860
861 if (uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED)
862 {
863 /* Just find the next unused device number and we're good. */
864 uPciDevNo = devpciR3CommonFindUnusedDeviceNo(pBus);
865 AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES, ("Couldn't find a free spot!\n"), VERR_PDM_TOO_PCI_MANY_DEVICES);
866 if (uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED)
867 uPciFunNo = 0;
868 }
869 else
870 {
871 /*
872 * Direct assignment of device number can be more complicated.
873 */
874 PPDMPCIDEV pClash;
875 if (uPciFunNo != PDMPCIDEVREG_FUN_NO_FIRST_UNUSED)
876 {
877 /* In the case of a specified function, we only relocate an existing
878 device if it belongs to a different device instance. Reasoning is
879 that the device should figure out it's own function assignments.
880 Note! We could make this more flexible by relocating functions assigned
881 via PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, but it can wait till it's needed. */
882 pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)];
883 if (!pClash)
884 { /* likely */ }
885 else if (pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3)
886 AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (same pDevIns)!\n",
887 uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName),
888 VERR_PDM_TOO_PCI_MANY_DEVICES);
889 else if (!pClash->Int.s.fReassignableDevNo)
890 AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (different pDevIns)!\n",
891 uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName),
892 VERR_PDM_TOO_PCI_MANY_DEVICES);
893 }
894 else
895 {
896 /* First unused function slot. Again, we only relocate the whole
897 thing if all the device instance differs, because we otherwise
898 reason that a device should manage its own functions correctly. */
899 unsigned cSameDevInses = 0;
900 for (uPciFunNo = 0, pClash = NULL; uPciFunNo < VBOX_PCI_MAX_FUNCTIONS; uPciFunNo++)
901 {
902 pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)];
903 if (!pClash)
904 break;
905 cSameDevInses += pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3;
906 }
907 if (!pClash)
908 Assert(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS);
909 else
910 AssertLogRelMsgReturn(cSameDevInses == 0,
911 ("PCI Configuration conflict at %u.* appending %s (%u of %u pDevIns matches)!\n",
912 uPciDevNo, pszName, cSameDevInses, VBOX_PCI_MAX_FUNCTIONS),
913 VERR_PDM_TOO_PCI_MANY_DEVICES);
914 }
915 if (pClash)
916 {
917 /*
918 * Try relocate the existing device.
919 */
920 /* Check that all functions can be moved. */
921 for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++)
922 {
923 PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)];
924 AssertLogRelMsgReturn(!pMovePciDev || pMovePciDev->Int.s.fReassignableDevNo,
925 ("PCI Configuration conflict at %u.%u: %s vs %s\n",
926 uPciDevNo, uMoveFun, pMovePciDev->pszNameR3, pszName),
927 VERR_PDM_TOO_PCI_MANY_DEVICES);
928 }
929
930 /* Find a free device number to move it to. */
931 uint8_t uMoveToDevNo = devpciR3CommonFindUnusedDeviceNo(pBus);
932 Assert(uMoveToDevNo != uPciFunNo);
933 AssertLogRelMsgReturn(uMoveToDevNo < VBOX_PCI_MAX_DEVICES,
934 ("No space to relocate device at %u so '%s' can be placed there instead!\n", uPciFunNo, pszName),
935 VERR_PDM_TOO_PCI_MANY_DEVICES);
936
937 /* Execute the move. */
938 for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++)
939 {
940 PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)];
941 if (pMovePciDev)
942 {
943 Log(("PCI: Relocating '%s' from %u.%u to %u.%u.\n", pMovePciDev->pszNameR3, uPciDevNo, uMoveFun, uMoveToDevNo, uMoveFun));
944 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)] = NULL;
945 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun)] = pMovePciDev;
946 pMovePciDev->uDevFn = VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun);
947 }
948 }
949 }
950 }
951
952 /*
953 * Now, initialize the rest of the PCI device structure.
954 */
955 Assert(!pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)]);
956 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)] = pPciDev;
957
958 pPciDev->uDevFn = VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo);
959 pPciDev->Int.s.pBusR3 = pBus;
960 Assert(pBus == PDMINS_2_DATA(pDevIns, PDEVPCIBUS));
961 pPciDev->Int.s.pfnConfigRead = NULL;
962 pPciDev->Int.s.pfnConfigWrite = NULL;
963 pPciDev->Int.s.hMmioMsix = NIL_IOMMMIOHANDLE;
964 if (pBus->fTypePiix3 && pPciDev->cbConfig > 256)
965 pPciDev->cbConfig = 256;
966
967 /* Remember and mark bridges. */
968 if (fFlags & PDMPCIDEVREG_F_PCI_BRIDGE)
969 {
970 AssertLogRelMsgReturn(pBus->cBridges < RT_ELEMENTS(pBus->apDevices),
971 ("Number of bridges exceeds the number of possible devices on the bus\n"),
972 VERR_INTERNAL_ERROR_3);
973 pBus->papBridgesR3[pBus->cBridges++] = pPciDev;
974 pciDevSetPci2PciBridge(pPciDev);
975 }
976
977 Log(("PCI: Registered device %d function %d (%#x) '%s'.\n",
978 uPciDevNo, uPciFunNo, UINT32_C(0x80000000) | (pPciDev->uDevFn << 8), pszName));
979
980 return VINF_SUCCESS;
981}
982
983
984/**
985 * @interface_method_impl{PDMPCIBUSREGR3,pfnRegisterR3}
986 */
987DECLCALLBACK(int) devpciR3CommonRegisterDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
988 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
989{
990 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
991 AssertCompileMemberOffset(DEVPCIROOT, PciBus, 0);
992 return devpciR3CommonRegisterDeviceOnBus(pDevIns, pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName);
993}
994
995
996/**
997 * @interface_method_impl{PDMPCIBUSREGR3,pfnRegisterR3}
998 */
999DECLCALLBACK(int) devpcibridgeR3CommonRegisterDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
1000 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
1001{
1002 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1003 return devpciR3CommonRegisterDeviceOnBus(pDevIns, pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName);
1004}
1005
1006
1007static DECLCALLBACK(int) ich9pciRegisterMsi(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg)
1008{
1009 //PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1010 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
1011
1012 int rc = MsiR3Init(pPciDev, pMsiReg);
1013 if (RT_SUCCESS(rc))
1014 rc = MsixR3Init(pBusCC->CTX_SUFF(pPciHlp), pPciDev, pMsiReg);
1015
1016 return rc;
1017}
1018
1019
1020/**
1021 * @interface_method_impl{PDMPCIBUSREGR3,pfnIORegionRegisterR3}
1022 */
1023DECLCALLBACK(int) devpciR3CommonIORegionRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
1024 RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, uint32_t fFlags,
1025 uint64_t hHandle, PFNPCIIOREGIONMAP pfnMapUnmap)
1026{
1027 LogFunc(("%s: region #%u size %RGp type %x fFlags=%#x hHandle=%#RX64\n",
1028 pPciDev->pszNameR3, iRegion, cbRegion, enmType, fFlags, hHandle));
1029 RT_NOREF(pDevIns);
1030
1031 /*
1032 * Validate.
1033 */
1034 AssertMsgReturn( enmType == (PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR32)
1035 || enmType == (PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_BAR32)
1036 || enmType == (PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64)
1037 || enmType == (PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_BAR64)
1038 || enmType == PCI_ADDRESS_SPACE_IO
1039 ,
1040 ("Invalid enmType=%#x? Or was this a bitmask after all...\n", enmType),
1041 VERR_INVALID_PARAMETER);
1042 AssertMsgReturn((unsigned)iRegion < VBOX_PCI_NUM_REGIONS,
1043 ("Invalid iRegion=%d VBOX_PCI_NUM_REGIONS=%d\n", iRegion, VBOX_PCI_NUM_REGIONS),
1044 VERR_INVALID_PARAMETER);
1045 int iLastSet = ASMBitLastSetU64(cbRegion);
1046 AssertMsgReturn( iLastSet != 0
1047 && RT_BIT_64(iLastSet - 1) == cbRegion,
1048 ("Invalid cbRegion=%RGp iLastSet=%#x (not a power of 2 or 0)\n", cbRegion, iLastSet),
1049 VERR_INVALID_PARAMETER);
1050 switch (fFlags & PDMPCIDEV_IORGN_F_HANDLE_MASK)
1051 {
1052 case PDMPCIDEV_IORGN_F_IOPORT_HANDLE:
1053 case PDMPCIDEV_IORGN_F_MMIO_HANDLE:
1054 case PDMPCIDEV_IORGN_F_MMIO2_HANDLE:
1055 AssertReturn(hHandle != UINT64_MAX, VERR_INVALID_HANDLE);
1056 break;
1057 default:
1058 AssertReturn(hHandle == UINT64_MAX, VERR_INVALID_HANDLE);
1059 }
1060
1061 /* Make sure that we haven't marked this region as continuation of 64-bit region. */
1062 AssertReturn(pPciDev->Int.s.aIORegions[iRegion].type != 0xff, VERR_NOT_AVAILABLE);
1063
1064 /*
1065 * Register the I/O region.
1066 */
1067 PPCIIOREGION pRegion = &pPciDev->Int.s.aIORegions[iRegion];
1068 pRegion->addr = INVALID_PCI_ADDRESS;
1069 pRegion->size = cbRegion;
1070 pRegion->fFlags = fFlags;
1071 pRegion->hHandle = hHandle;
1072 pRegion->type = enmType;
1073 pRegion->pfnMap = pfnMapUnmap;
1074
1075 if ((enmType & PCI_ADDRESS_SPACE_BAR64) != 0)
1076 {
1077 /* VBOX_PCI_BASE_ADDRESS_5 and VBOX_PCI_ROM_ADDRESS are excluded. */
1078 AssertMsgReturn(iRegion < VBOX_PCI_NUM_REGIONS - 2,
1079 ("Region %d cannot be 64-bit\n", iRegion),
1080 VERR_INVALID_PARAMETER);
1081 /* Mark next region as continuation of this one. */
1082 pPciDev->Int.s.aIORegions[iRegion + 1].type = 0xff;
1083 }
1084
1085 /* Set type in the PCI config space. */
1086 AssertCompile(PCI_ADDRESS_SPACE_MEM == 0);
1087 AssertCompile(PCI_ADDRESS_SPACE_IO == 1);
1088 AssertCompile(PCI_ADDRESS_SPACE_BAR64 == RT_BIT_32(2));
1089 AssertCompile(PCI_ADDRESS_SPACE_MEM_PREFETCH == RT_BIT_32(3));
1090 uint32_t u32Value = (uint32_t)enmType & (PCI_ADDRESS_SPACE_IO | PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_MEM_PREFETCH);
1091 /* safe, only needs to go to the config space array */
1092 PDMPciDevSetDWord(pPciDev, devpciGetRegionReg(iRegion), u32Value);
1093
1094 return VINF_SUCCESS;
1095}
1096
1097
1098/**
1099 * @interface_method_impl{PDMPCIBUSREGR3,pfnInterceptConfigAccesses}
1100 */
1101DECLCALLBACK(void) devpciR3CommonInterceptConfigAccesses(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
1102 PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite)
1103{
1104 NOREF(pDevIns);
1105
1106 pPciDev->Int.s.pfnConfigRead = pfnRead;
1107 pPciDev->Int.s.pfnConfigWrite = pfnWrite;
1108}
1109
1110
1111static int ich9pciR3CommonSaveExec(PDEVPCIBUS pBus, PSSMHANDLE pSSM)
1112{
1113 /*
1114 * Iterate thru all the devices.
1115 */
1116 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
1117 {
1118 PPDMPCIDEV pDev = pBus->apDevices[uDevFn];
1119 if (pDev)
1120 {
1121 /* Device position */
1122 SSMR3PutU32(pSSM, uDevFn);
1123
1124 /* PCI config registers */
1125 SSMR3PutU32(pSSM, sizeof(pDev->abConfig));
1126 SSMR3PutMem(pSSM, pDev->abConfig, sizeof(pDev->abConfig));
1127
1128 /* Device flags */
1129 SSMR3PutU32(pSSM, pDev->Int.s.fFlags);
1130
1131 /* IRQ pin state */
1132 SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
1133
1134 /* MSI info */
1135 SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapOffset);
1136 SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapSize);
1137
1138 /* MSI-X info */
1139 SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapOffset);
1140 SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapSize);
1141
1142 /* Save MSI-X page state */
1143 if (pDev->Int.s.u8MsixCapOffset != 0)
1144 {
1145 SSMR3PutU32(pSSM, pDev->Int.s.cbMsixRegion);
1146 SSMR3PutMem(pSSM, pDev->abMsixState, pDev->Int.s.cbMsixRegion);
1147 }
1148 else
1149 SSMR3PutU32(pSSM, 0);
1150
1151 /* Save the type an size of all the regions. */
1152 for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
1153 {
1154 SSMR3PutU8(pSSM, pDev->Int.s.aIORegions[iRegion].type);
1155 SSMR3PutU64(pSSM, pDev->Int.s.aIORegions[iRegion].size);
1156 }
1157 }
1158 }
1159 return SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
1160}
1161
1162static DECLCALLBACK(int) ich9pciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1163{
1164 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
1165
1166 /*
1167 * Bus state data.
1168 */
1169 SSMR3PutU32(pSSM, pThis->uConfigReg);
1170
1171 /*
1172 * Save IRQ states.
1173 */
1174 for (unsigned i = 0; i < RT_ELEMENTS(pThis->auPciApicIrqLevels); i++)
1175 SSMR3PutU32(pSSM, pThis->auPciApicIrqLevels[i]);
1176
1177 SSMR3PutU32(pSSM, UINT32_MAX); /* separator */
1178
1179 return ich9pciR3CommonSaveExec(&pThis->PciBus, pSSM);
1180}
1181
1182
1183static DECLCALLBACK(int) ich9pcibridgeR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1184{
1185 PDEVPCIBUS pThis = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1186 return ich9pciR3CommonSaveExec(pThis, pSSM);
1187}
1188
1189
1190/**
1191 * @callback_method_impl{FNPCIBRIDGECONFIGWRITE}
1192 */
1193static DECLCALLBACK(VBOXSTRICTRC) ich9pcibridgeConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice,
1194 uint32_t u32Address, unsigned cb, uint32_t u32Value)
1195{
1196 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1197 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1198 LogFlowFunc(("pDevIns=%p iBus=%d iDevice=%d u32Address=%#x cb=%d u32Value=%#x\n", pDevIns, iBus, iDevice, u32Address, cb, u32Value));
1199
1200 /* If the current bus is not the target bus search for the bus which contains the device. */
1201 /* safe, only needs to go to the config space array */
1202 if (iBus != PDMPciDevGetByte(pDevIns->apPciDevs[0], VBOX_PCI_SECONDARY_BUS))
1203 {
1204 PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1205 if (pBridgeDevice)
1206 {
1207 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
1208 pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus, iDevice,
1209 u32Address, cb, u32Value);
1210 }
1211 }
1212 else
1213 {
1214 /* This is the target bus, pass the write to the device. */
1215 PPDMPCIDEV pPciDev = pBus->apDevices[iDevice];
1216 if (pPciDev)
1217 {
1218 LogFunc(("%s: addr=%02x val=%08x len=%d\n", pPciDev->pszNameR3, u32Address, u32Value, cb));
1219 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
1220 if (pPciDev->Int.s.pfnConfigWrite)
1221 rcStrict = pPciDev->Int.s.pfnConfigWrite(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, u32Address, cb, u32Value);
1222 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
1223 rcStrict = devpciR3CommonConfigWriteWorker(pDevIns, PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC),
1224 pPciDev, u32Address, cb, u32Value);
1225 }
1226 }
1227 return rcStrict;
1228}
1229
1230/**
1231 * @callback_method_impl{FNPCIBRIDGECONFIGREAD}
1232 */
1233static DECLCALLBACK(VBOXSTRICTRC) ich9pcibridgeConfigRead(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice,
1234 uint32_t u32Address, unsigned cb, uint32_t *pu32Value)
1235{
1236 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1237 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1238 LogFlowFunc(("pDevIns=%p iBus=%d iDevice=%d u32Address=%#x cb=%d\n", pDevIns, iBus, iDevice, u32Address, cb));
1239
1240 /* If the current bus is not the target bus search for the bus which contains the device. */
1241 /* safe, only needs to go to the config space array */
1242 if (iBus != PDMPciDevGetByte(pDevIns->apPciDevs[0], VBOX_PCI_SECONDARY_BUS))
1243 {
1244 PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1245 if (pBridgeDevice)
1246 {
1247 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
1248 rcStrict = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus, iDevice,
1249 u32Address, cb, pu32Value);
1250 }
1251 else
1252 *pu32Value = UINT32_MAX;
1253 }
1254 else
1255 {
1256 /* This is the target bus, pass the read to the device. */
1257 PPDMPCIDEV pPciDev = pBus->apDevices[iDevice];
1258 if (pPciDev)
1259 {
1260 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
1261 if (pPciDev->Int.s.pfnConfigRead)
1262 rcStrict = pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, u32Address, cb, pu32Value);
1263 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
1264 rcStrict = devpciR3CommonConfigReadWorker(pPciDev, u32Address, cb, pu32Value);
1265 LogFunc(("%s: u32Address=%02x *pu32Value=%#010x cb=%d\n", pPciDev->pszNameR3, u32Address, *pu32Value, cb));
1266 }
1267 else
1268 *pu32Value = UINT32_MAX;
1269 }
1270
1271 return rcStrict;
1272}
1273
1274
1275
1276/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
1277
1278
1279/**
1280 * Common routine for restoring the config registers of a PCI device.
1281 *
1282 * @param pDevIns The device instance of the PC bus.
1283 * @param pDev The PCI device.
1284 * @param pbSrcConfig The configuration register values to be loaded.
1285 */
1286void devpciR3CommonRestoreConfig(PPDMDEVINS pDevIns, PPDMPCIDEV pDev, uint8_t const *pbSrcConfig)
1287{
1288 /*
1289 * This table defines the fields for normal devices and bridge devices, and
1290 * the order in which they need to be restored.
1291 */
1292 static const struct PciField
1293 {
1294 uint8_t off;
1295 uint8_t cb;
1296 uint8_t fWritable;
1297 uint8_t fBridge;
1298 const char *pszName;
1299 } s_aFields[] =
1300 {
1301 /* off,cb,fW,fB, pszName */
1302 { 0x00, 2, 0, 3, "VENDOR_ID" },
1303 { 0x02, 2, 0, 3, "DEVICE_ID" },
1304 { 0x06, 2, 1, 3, "STATUS" },
1305 { 0x08, 1, 0, 3, "REVISION_ID" },
1306 { 0x09, 1, 0, 3, "CLASS_PROG" },
1307 { 0x0a, 1, 0, 3, "CLASS_SUB" },
1308 { 0x0b, 1, 0, 3, "CLASS_BASE" },
1309 { 0x0c, 1, 1, 3, "CACHE_LINE_SIZE" },
1310 { 0x0d, 1, 1, 3, "LATENCY_TIMER" },
1311 { 0x0e, 1, 0, 3, "HEADER_TYPE" },
1312 { 0x0f, 1, 1, 3, "BIST" },
1313 { 0x10, 4, 1, 3, "BASE_ADDRESS_0" },
1314 { 0x14, 4, 1, 3, "BASE_ADDRESS_1" },
1315 { 0x18, 4, 1, 1, "BASE_ADDRESS_2" },
1316 { 0x18, 1, 1, 2, "PRIMARY_BUS" },
1317 { 0x19, 1, 1, 2, "SECONDARY_BUS" },
1318 { 0x1a, 1, 1, 2, "SUBORDINATE_BUS" },
1319 { 0x1b, 1, 1, 2, "SEC_LATENCY_TIMER" },
1320 { 0x1c, 4, 1, 1, "BASE_ADDRESS_3" },
1321 { 0x1c, 1, 1, 2, "IO_BASE" },
1322 { 0x1d, 1, 1, 2, "IO_LIMIT" },
1323 { 0x1e, 2, 1, 2, "SEC_STATUS" },
1324 { 0x20, 4, 1, 1, "BASE_ADDRESS_4" },
1325 { 0x20, 2, 1, 2, "MEMORY_BASE" },
1326 { 0x22, 2, 1, 2, "MEMORY_LIMIT" },
1327 { 0x24, 4, 1, 1, "BASE_ADDRESS_5" },
1328 { 0x24, 2, 1, 2, "PREF_MEMORY_BASE" },
1329 { 0x26, 2, 1, 2, "PREF_MEMORY_LIMIT" },
1330 { 0x28, 4, 0, 1, "CARDBUS_CIS" },
1331 { 0x28, 4, 1, 2, "PREF_BASE_UPPER32" },
1332 { 0x2c, 2, 0, 1, "SUBSYSTEM_VENDOR_ID" },
1333 { 0x2c, 4, 1, 2, "PREF_LIMIT_UPPER32" },
1334 { 0x2e, 2, 0, 1, "SUBSYSTEM_ID" },
1335 { 0x30, 4, 1, 1, "ROM_ADDRESS" },
1336 { 0x30, 2, 1, 2, "IO_BASE_UPPER16" },
1337 { 0x32, 2, 1, 2, "IO_LIMIT_UPPER16" },
1338 { 0x34, 4, 0, 3, "CAPABILITY_LIST" },
1339 { 0x38, 4, 1, 1, "RESERVED_38" },
1340 { 0x38, 4, 1, 2, "ROM_ADDRESS_BR" },
1341 { 0x3c, 1, 1, 3, "INTERRUPT_LINE" },
1342 { 0x3d, 1, 0, 3, "INTERRUPT_PIN" },
1343 { 0x3e, 1, 0, 1, "MIN_GNT" },
1344 { 0x3e, 2, 1, 2, "BRIDGE_CONTROL" },
1345 { 0x3f, 1, 0, 1, "MAX_LAT" },
1346 /* The COMMAND register must come last as it requires the *ADDRESS*
1347 registers to be restored before we pretent to change it from 0 to
1348 whatever value the guest assigned it. */
1349 { 0x04, 2, 1, 3, "COMMAND" },
1350 };
1351
1352#ifdef RT_STRICT
1353 /* Check that we've got full register coverage. */
1354 uint32_t bmDevice[0x40 / 32];
1355 uint32_t bmBridge[0x40 / 32];
1356 RT_ZERO(bmDevice);
1357 RT_ZERO(bmBridge);
1358 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1359 {
1360 uint8_t off = s_aFields[i].off;
1361 uint8_t cb = s_aFields[i].cb;
1362 uint8_t f = s_aFields[i].fBridge;
1363 while (cb-- > 0)
1364 {
1365 if (f & 1) AssertMsg(!ASMBitTest(bmDevice, off), ("%#x\n", off));
1366 if (f & 2) AssertMsg(!ASMBitTest(bmBridge, off), ("%#x\n", off));
1367 if (f & 1) ASMBitSet(bmDevice, off);
1368 if (f & 2) ASMBitSet(bmBridge, off);
1369 off++;
1370 }
1371 }
1372 for (uint32_t off = 0; off < 0x40; off++)
1373 {
1374 AssertMsg(ASMBitTest(bmDevice, off), ("%#x\n", off));
1375 AssertMsg(ASMBitTest(bmBridge, off), ("%#x\n", off));
1376 }
1377#endif
1378
1379 /*
1380 * Loop thru the fields covering the 64 bytes of standard registers.
1381 */
1382 uint8_t const fBridge = pciDevIsPci2PciBridge(pDev) ? 2 : 1;
1383 Assert(!pciDevIsPassthrough(pDev));
1384 uint8_t *pbDstConfig = &pDev->abConfig[0];
1385
1386 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1387 if (s_aFields[i].fBridge & fBridge)
1388 {
1389 uint8_t const off = s_aFields[i].off;
1390 uint8_t const cb = s_aFields[i].cb;
1391 uint32_t u32Src;
1392 uint32_t u32Dst;
1393 switch (cb)
1394 {
1395 case 1:
1396 u32Src = pbSrcConfig[off];
1397 u32Dst = pbDstConfig[off];
1398 break;
1399 case 2:
1400 u32Src = *(uint16_t const *)&pbSrcConfig[off];
1401 u32Dst = *(uint16_t const *)&pbDstConfig[off];
1402 break;
1403 case 4:
1404 u32Src = *(uint32_t const *)&pbSrcConfig[off];
1405 u32Dst = *(uint32_t const *)&pbDstConfig[off];
1406 break;
1407 default:
1408 AssertFailed();
1409 continue;
1410 }
1411
1412 if ( u32Src != u32Dst
1413 || off == VBOX_PCI_COMMAND)
1414 {
1415 if (u32Src != u32Dst)
1416 {
1417 if (!s_aFields[i].fWritable)
1418 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x - !READ ONLY!\n",
1419 pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1420 else
1421 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x\n",
1422 pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1423 }
1424 if (off == VBOX_PCI_COMMAND)
1425 /* safe, only needs to go to the config space array */
1426 PDMPciDevSetCommand(pDev, 0); /* For remapping, see pciR3CommonLoadExec/ich9pciR3CommonLoadExec. */
1427 devpciR3SetCfg(pDevIns, pDev, off, u32Src, cb);
1428 }
1429 }
1430
1431 /*
1432 * The device dependent registers.
1433 *
1434 * We will not use ConfigWrite here as we have no clue about the size
1435 * of the registers, so the device is responsible for correctly
1436 * restoring functionality governed by these registers.
1437 */
1438 for (uint32_t off = 0x40; off < sizeof(pDev->abConfig); off++)
1439 if (pbDstConfig[off] != pbSrcConfig[off])
1440 {
1441 LogRel(("PCI: %8s/%u: register %02x: %02x -> %02x\n",
1442 pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
1443 pbDstConfig[off] = pbSrcConfig[off];
1444 }
1445}
1446
1447
1448/**
1449 * @callback_method_impl{FNPCIIOREGIONOLDSETTER}
1450 */
1451static DECLCALLBACK(int) devpciR3CommonRestoreOldSetRegion(PPDMPCIDEV pPciDev, uint32_t iRegion,
1452 RTGCPHYS cbRegion, PCIADDRESSSPACE enmType)
1453{
1454 AssertLogRelReturn(iRegion < RT_ELEMENTS(pPciDev->Int.s.aIORegions), VERR_INVALID_PARAMETER);
1455 pPciDev->Int.s.aIORegions[iRegion].type = enmType;
1456 pPciDev->Int.s.aIORegions[iRegion].size = cbRegion;
1457 return VINF_SUCCESS;
1458}
1459
1460
1461/**
1462 * @callback_method_impl{FNPCIIOREGIONSWAP}
1463 */
1464static DECLCALLBACK(int) devpciR3CommonRestoreSwapRegions(PPDMPCIDEV pPciDev, uint32_t iRegion, uint32_t iOtherRegion)
1465{
1466 AssertReturn(iRegion < iOtherRegion, VERR_INVALID_PARAMETER);
1467 AssertLogRelReturn(iOtherRegion < RT_ELEMENTS(pPciDev->Int.s.aIORegions), VERR_INVALID_PARAMETER);
1468 AssertReturn(pPciDev->Int.s.bPadding0 == (0xe0 | (uint8_t)iRegion), VERR_INVALID_PARAMETER);
1469
1470 PCIIOREGION Tmp = pPciDev->Int.s.aIORegions[iRegion];
1471 pPciDev->Int.s.aIORegions[iRegion] = pPciDev->Int.s.aIORegions[iOtherRegion];
1472 pPciDev->Int.s.aIORegions[iOtherRegion] = Tmp;
1473
1474 return VINF_SUCCESS;
1475}
1476
1477
1478/**
1479 * Checks for and deals with changes in resource sizes and types.
1480 *
1481 * @returns VBox status code.
1482 * @param pSSM The Saved state handle.
1483 * @param pPciDev The PCI device in question.
1484 * @param paIoRegions I/O regions with the size and type fields from
1485 * the saved state.
1486 * @param fNewState Set if this is a new state with I/O region sizes
1487 * and types, clear if old one.
1488 */
1489int devpciR3CommonRestoreRegions(PSSMHANDLE pSSM, PPDMPCIDEV pPciDev, PPCIIOREGION paIoRegions, bool fNewState)
1490{
1491 int rc;
1492 if (fNewState)
1493 {
1494 for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
1495 {
1496 if ( pPciDev->Int.s.aIORegions[iRegion].type != paIoRegions[iRegion].type
1497 || pPciDev->Int.s.aIORegions[iRegion].size != paIoRegions[iRegion].size)
1498 {
1499 AssertLogRelMsgFailed(("PCI: %8s/%u: region #%u size/type load change: %#RGp/%#x -> %#RGp/%#x\n",
1500 pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, iRegion,
1501 pPciDev->Int.s.aIORegions[iRegion].size, pPciDev->Int.s.aIORegions[iRegion].type,
1502 paIoRegions[iRegion].size, paIoRegions[iRegion].type));
1503 if (pPciDev->pfnRegionLoadChangeHookR3)
1504 {
1505 pPciDev->Int.s.bPadding0 = 0xe0 | (uint8_t)iRegion;
1506 rc = pPciDev->pfnRegionLoadChangeHookR3(pPciDev->Int.s.pDevInsR3, pPciDev, iRegion, paIoRegions[iRegion].size,
1507 (PCIADDRESSSPACE)paIoRegions[iRegion].type, NULL /*pfnOldSetter*/,
1508 devpciR3CommonRestoreSwapRegions);
1509 pPciDev->Int.s.bPadding0 = 0;
1510 if (RT_FAILURE(rc))
1511 return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,
1512 N_("Device %s/%u failed to respond to region #%u size/type changing from %#RGp/%#x to %#RGp/%#x: %Rrc"),
1513 pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, iRegion,
1514 pPciDev->Int.s.aIORegions[iRegion].size, pPciDev->Int.s.aIORegions[iRegion].type,
1515 paIoRegions[iRegion].size, paIoRegions[iRegion].type, rc);
1516 }
1517 pPciDev->Int.s.aIORegions[iRegion].type = paIoRegions[iRegion].type;
1518 pPciDev->Int.s.aIORegions[iRegion].size = paIoRegions[iRegion].size;
1519 }
1520 }
1521 }
1522 /* Old saved state without sizes and types. Do a special hook call to give
1523 devices with changes a chance to adjust resources back to old values. */
1524 else if (pPciDev->pfnRegionLoadChangeHookR3)
1525 {
1526 rc = pPciDev->pfnRegionLoadChangeHookR3(pPciDev->Int.s.pDevInsR3, pPciDev, UINT32_MAX, RTGCPHYS_MAX, (PCIADDRESSSPACE)-1,
1527 devpciR3CommonRestoreOldSetRegion, NULL);
1528 if (RT_FAILURE(rc))
1529 return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS, N_("Device %s/%u failed to resize its resources: %Rrc"),
1530 pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, rc);
1531 }
1532 return VINF_SUCCESS;
1533}
1534
1535
1536/**
1537 * Common worker for ich9pciR3LoadExec and ich9pcibridgeR3LoadExec.
1538 *
1539 * @returns VBox status code.
1540 * @param pDevIns The device instance of the bus.
1541 * @param pBus The bus which data is being loaded.
1542 * @param pSSM The saved state handle.
1543 * @param uVersion The data version.
1544 * @param uPass The pass.
1545 */
1546static int ich9pciR3CommonLoadExec(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1547{
1548 uint32_t u32;
1549 int rc;
1550
1551 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1552 if ( uVersion < VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI
1553 || uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION)
1554 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1555
1556 /*
1557 * Iterate thru all the devices and write 0 to the COMMAND register so
1558 * that all the memory is unmapped before we start restoring the saved
1559 * mapping locations.
1560 *
1561 * The register value is restored afterwards so we can do proper
1562 * LogRels in devpciR3CommonRestoreConfig.
1563 */
1564 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
1565 {
1566 PPDMPCIDEV pDev = pBus->apDevices[uDevFn];
1567 if (pDev)
1568 {
1569 /* safe, only needs to go to the config space array */
1570 uint16_t u16 = PDMPciDevGetCommand(pDev);
1571 devpciR3SetCfg(pDevIns, pDev, VBOX_PCI_COMMAND, 0 /*u32Value*/, 2 /*cb*/);
1572 /* safe, only needs to go to the config space array */
1573 PDMPciDevSetCommand(pDev, u16);
1574 /* safe, only needs to go to the config space array */
1575 Assert(PDMPciDevGetCommand(pDev) == u16);
1576 }
1577 }
1578
1579 /*
1580 * Iterate all the devices.
1581 */
1582 for (uint32_t uDevFn = 0;; uDevFn++)
1583 {
1584 /* index / terminator */
1585 rc = SSMR3GetU32(pSSM, &u32);
1586 if (RT_FAILURE(rc))
1587 break;
1588 if (u32 == (uint32_t)~0)
1589 break;
1590 AssertLogRelMsgBreak(u32 < RT_ELEMENTS(pBus->apDevices) && u32 >= uDevFn, ("u32=%#x uDevFn=%#x\n", u32, uDevFn));
1591
1592 /* skip forward to the device checking that no new devices are present. */
1593 PPDMPCIDEV pDev;
1594 for (; uDevFn < u32; uDevFn++)
1595 {
1596 pDev = pBus->apDevices[uDevFn];
1597 if (pDev)
1598 {
1599 /* safe, only needs to go to the config space array */
1600 LogRel(("PCI: New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", uDevFn, pDev->pszNameR3,
1601 PDMPciDevGetVendorId(pDev), PDMPciDevGetDeviceId(pDev)));
1602 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1603 {
1604 /* safe, only needs to go to the config space array */
1605 rc = SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("New device in slot %#x, %s (vendor=%#06x device=%#06x)"),
1606 uDevFn, pDev->pszNameR3, PDMPciDevGetVendorId(pDev), PDMPciDevGetDeviceId(pDev));
1607 break;
1608 }
1609 }
1610 }
1611 if (RT_FAILURE(rc))
1612 break;
1613 pDev = pBus->apDevices[uDevFn];
1614
1615 /* get the data */
1616 union
1617 {
1618 PDMPCIDEV DevTmp;
1619 uint8_t abPadding[RT_UOFFSETOF(PDMPCIDEV, abMsixState) + _32K + _16K]; /* the MSI-X state shouldn't be much more than 32KB. */
1620 } u;
1621 RT_ZERO(u);
1622 u.DevTmp.Int.s.fFlags = 0;
1623 u.DevTmp.Int.s.u8MsiCapOffset = 0;
1624 u.DevTmp.Int.s.u8MsiCapSize = 0;
1625 u.DevTmp.Int.s.u8MsixCapOffset = 0;
1626 u.DevTmp.Int.s.u8MsixCapSize = 0;
1627 u.DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
1628 uint32_t cbConfig = 256;
1629 if (uVersion >= VBOX_ICH9PCI_SAVED_STATE_VERSION_4KB_CFG_SPACE)
1630 {
1631 rc = SSMR3GetU32(pSSM, &cbConfig);
1632 AssertRCReturn(rc, rc);
1633 if (cbConfig != 256 && cbConfig != _4K)
1634 return SSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
1635 "cbConfig=%#RX32, expected 0x100 or 0x1000", cbConfig);
1636 }
1637 SSMR3GetMem(pSSM, u.DevTmp.abConfig, cbConfig);
1638
1639 SSMR3GetU32(pSSM, &u.DevTmp.Int.s.fFlags);
1640 SSMR3GetS32(pSSM, &u.DevTmp.Int.s.uIrqPinState);
1641 SSMR3GetU8(pSSM, &u.DevTmp.Int.s.u8MsiCapOffset);
1642 SSMR3GetU8(pSSM, &u.DevTmp.Int.s.u8MsiCapSize);
1643 SSMR3GetU8(pSSM, &u.DevTmp.Int.s.u8MsixCapOffset);
1644 rc = SSMR3GetU8(pSSM, &u.DevTmp.Int.s.u8MsixCapSize);
1645 AssertRCReturn(rc, rc);
1646
1647 /* Load MSI-X page state */
1648 uint32_t cbMsixState = u.DevTmp.Int.s.u8MsixCapOffset != 0 ? _4K : 0;
1649 if (uVersion >= VBOX_ICH9PCI_SAVED_STATE_VERSION_4KB_CFG_SPACE)
1650 {
1651 rc = SSMR3GetU32(pSSM, &cbMsixState);
1652 AssertRCReturn(rc, rc);
1653 }
1654 if (cbMsixState)
1655 {
1656 if ( cbMsixState > (uint32_t)(pDev ? pDev->cbMsixState : _32K + _16K)
1657 || cbMsixState > sizeof(u) - RT_UOFFSETOF(PDMPCIDEV, abMsixState))
1658 return SSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
1659 "cbMsixState=%#RX32, expected at most RT_MIN(%#x, %#zx)",
1660 cbMsixState, (pDev ? pDev->cbMsixState : _32K + _16K),
1661 sizeof(u) - RT_UOFFSETOF(PDMPCIDEV, abMsixState));
1662 rc = SSMR3GetMem(pSSM, u.DevTmp.abMsixState, cbMsixState);
1663 AssertRCReturn(rc, rc);
1664 }
1665
1666 /* Load the region types and sizes. */
1667 if (uVersion >= VBOX_ICH9PCI_SAVED_STATE_VERSION_REGION_SIZES)
1668 {
1669 for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
1670 {
1671 SSMR3GetU8(pSSM, &u.DevTmp.Int.s.aIORegions[iRegion].type);
1672 rc = SSMR3GetU64(pSSM, &u.DevTmp.Int.s.aIORegions[iRegion].size);
1673 AssertLogRelRCReturn(rc, rc);
1674 }
1675 }
1676
1677 /*
1678 * Check that it's still around.
1679 */
1680 pDev = pBus->apDevices[uDevFn];
1681 if (!pDev)
1682 {
1683 /* safe, only needs to go to the config space array */
1684 LogRel(("PCI: Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", uDevFn,
1685 PDMPciDevGetVendorId(&u.DevTmp), PDMPciDevGetDeviceId(&u.DevTmp)));
1686 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1687 {
1688 /* safe, only needs to go to the config space array */
1689 rc = SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x has been removed! vendor=%#06x device=%#06x"),
1690 uDevFn, PDMPciDevGetVendorId(&u.DevTmp), PDMPciDevGetDeviceId(&u.DevTmp));
1691 break;
1692 }
1693 continue;
1694 }
1695
1696 /* match the vendor id assuming that this will never be changed. */
1697 /* safe, only needs to go to the config space array */
1698 if (PDMPciDevGetVendorId(&u.DevTmp) != PDMPciDevGetVendorId(pDev))
1699 {
1700 /* safe, only needs to go to the config space array */
1701 rc = SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
1702 uDevFn, pDev->pszNameR3, PDMPciDevGetVendorId(&u.DevTmp), PDMPciDevGetVendorId(pDev));
1703 break;
1704 }
1705
1706 /* commit the loaded device config. */
1707 rc = devpciR3CommonRestoreRegions(pSSM, pDev, u.DevTmp.Int.s.aIORegions,
1708 uVersion >= VBOX_ICH9PCI_SAVED_STATE_VERSION_REGION_SIZES);
1709 if (RT_FAILURE(rc))
1710 break;
1711 Assert(!pciDevIsPassthrough(pDev));
1712 devpciR3CommonRestoreConfig(pDevIns, pDev, &u.DevTmp.abConfig[0]);
1713
1714 pDev->Int.s.uIrqPinState = u.DevTmp.Int.s.uIrqPinState;
1715 pDev->Int.s.u8MsiCapOffset = u.DevTmp.Int.s.u8MsiCapOffset;
1716 pDev->Int.s.u8MsiCapSize = u.DevTmp.Int.s.u8MsiCapSize;
1717 pDev->Int.s.u8MsixCapOffset = u.DevTmp.Int.s.u8MsixCapOffset;
1718 pDev->Int.s.u8MsixCapSize = u.DevTmp.Int.s.u8MsixCapSize;
1719 if (u.DevTmp.Int.s.u8MsixCapSize != 0) /** @todo r=bird: Why isn't this checkin u8MsixCapOffset??? */
1720 {
1721 Assert(pDev->Int.s.cbMsixRegion != 0);
1722 Assert(pDev->cbMsixState != 0);
1723 memcpy(pDev->abMsixState, u.DevTmp.abMsixState, RT_MIN(pDev->Int.s.cbMsixRegion, _32K + _16K));
1724 }
1725 }
1726
1727 return rc;
1728}
1729
1730static DECLCALLBACK(int) ich9pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1731{
1732 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
1733 PDEVPCIBUS pBus = &pThis->PciBus;
1734 uint32_t u32;
1735 int rc;
1736
1737 /* We ignore this version as there's no saved state with it anyway */
1738 if (uVersion <= VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI)
1739 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1740 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION)
1741 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1742
1743 /*
1744 * Bus state data.
1745 */
1746 SSMR3GetU32(pSSM, &pThis->uConfigReg);
1747
1748 /*
1749 * Load IRQ states.
1750 */
1751 for (unsigned i = 0; i < RT_ELEMENTS(pThis->auPciApicIrqLevels); i++)
1752 SSMR3GetU32V(pSSM, &pThis->auPciApicIrqLevels[i]);
1753
1754 /* separator */
1755 rc = SSMR3GetU32(pSSM, &u32);
1756 if (RT_FAILURE(rc))
1757 return rc;
1758 if (u32 != (uint32_t)~0)
1759 AssertMsgFailedReturn(("u32=%#x\n", u32), rc);
1760
1761 return ich9pciR3CommonLoadExec(pDevIns, pBus, pSSM, uVersion, uPass);
1762}
1763
1764static DECLCALLBACK(int) ich9pcibridgeR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1765{
1766 PDEVPCIBUS pThis = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1767 return ich9pciR3CommonLoadExec(pDevIns, pThis, pSSM, uVersion, uPass);
1768}
1769
1770
1771
1772/* -=-=-=-=-=- Fake PCI BIOS Init -=-=-=-=-=- */
1773
1774
1775void devpciR3BiosInitSetRegionAddress(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev, int iRegion, uint64_t addr)
1776{
1777 NOREF(pBus);
1778 uint32_t uReg = devpciGetRegionReg(iRegion);
1779
1780 /* Read memory type first. */
1781 uint8_t uResourceType = devpciR3GetByte(pPciDev, uReg);
1782 bool f64Bit = (uResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
1783 == PCI_ADDRESS_SPACE_BAR64;
1784
1785 Log(("Set region address: %02x:%02x.%d region %d address=%RX64%s\n",
1786 pBus->iBus, pPciDev->uDevFn >> 3, pPciDev->uDevFn & 7, iRegion, addr, f64Bit ? " (64-bit)" : ""));
1787
1788 /* Write address of the device. */
1789 devpciR3SetDWord(pDevIns, pPciDev, uReg, (uint32_t)addr);
1790 if (f64Bit)
1791 devpciR3SetDWord(pDevIns, pPciDev, uReg + 4, (uint32_t)(addr >> 32));
1792}
1793
1794
1795static void ich9pciBiosInitBridge(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus)
1796{
1797 PPDMPCIDEV pBridge = pDevIns->apPciDevs[0];
1798 Log(("BIOS init bridge: %02x:%02x.%d\n", pBus->iBus, pBridge->uDevFn >> 3, pBridge->uDevFn & 7));
1799
1800 /*
1801 * The I/O range for the bridge must be aligned to a 4KB boundary.
1802 * This does not change anything really as the access to the device is not going
1803 * through the bridge but we want to be compliant to the spec.
1804 */
1805 if ((pPciRoot->uPciBiosIo % _4K) != 0)
1806 {
1807 pPciRoot->uPciBiosIo = RT_ALIGN_32(pPciRoot->uPciBiosIo, _4K);
1808 LogFunc(("Aligned I/O start address. New address %#x\n", pPciRoot->uPciBiosIo));
1809 }
1810 devpciR3SetByte(pDevIns, pBridge, VBOX_PCI_IO_BASE, (pPciRoot->uPciBiosIo >> 8) & 0xf0);
1811
1812 /* The MMIO range for the bridge must be aligned to a 1MB boundary. */
1813 if ((pPciRoot->uPciBiosMmio % _1M) != 0)
1814 {
1815 pPciRoot->uPciBiosMmio = RT_ALIGN_32(pPciRoot->uPciBiosMmio, _1M);
1816 LogFunc(("Aligned MMIO start address. New address %#x\n", pPciRoot->uPciBiosMmio));
1817 }
1818 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_MEMORY_BASE, (pPciRoot->uPciBiosMmio >> 16) & UINT32_C(0xffff0));
1819
1820 /* Save values to compare later to. */
1821 uint32_t u32IoAddressBase = pPciRoot->uPciBiosIo;
1822 uint32_t u32MMIOAddressBase = pPciRoot->uPciBiosMmio;
1823
1824 /* Init all devices behind the bridge (recursing to further buses). */
1825 ich9pciBiosInitAllDevicesOnBus(pDevIns, pPciRoot, pBus);
1826
1827 /*
1828 * Set I/O limit register. If there is no device with I/O space behind the
1829 * bridge we set a lower value than in the base register.
1830 */
1831 if (u32IoAddressBase != pPciRoot->uPciBiosIo)
1832 {
1833 /* Need again alignment to a 4KB boundary. */
1834 pPciRoot->uPciBiosIo = RT_ALIGN_32(pPciRoot->uPciBiosIo, _4K);
1835 devpciR3SetByte(pDevIns, pBridge, VBOX_PCI_IO_LIMIT, ((pPciRoot->uPciBiosIo - 1) >> 8) & 0xf0);
1836 }
1837 else
1838 {
1839 devpciR3SetByte(pDevIns, pBridge, VBOX_PCI_IO_BASE, 0xf0);
1840 devpciR3SetByte(pDevIns, pBridge, VBOX_PCI_IO_LIMIT, 0x00);
1841 }
1842
1843 /* Same with the MMIO limit register but with 1MB boundary here. */
1844 if (u32MMIOAddressBase != pPciRoot->uPciBiosMmio)
1845 {
1846 pPciRoot->uPciBiosMmio = RT_ALIGN_32(pPciRoot->uPciBiosMmio, _1M);
1847 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_MEMORY_LIMIT, ((pPciRoot->uPciBiosMmio - 1) >> 16) & UINT32_C(0xfff0));
1848 }
1849 else
1850 {
1851 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_MEMORY_BASE, 0xfff0);
1852 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_MEMORY_LIMIT, 0x0000);
1853 }
1854
1855 /*
1856 * Set the prefetch base and limit registers. We currently have no device with a prefetchable region
1857 * which may be behind a bridge. That's why it is unconditionally disabled here atm by writing a higher value into
1858 * the base register than in the limit register.
1859 */
1860 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_PREF_MEMORY_BASE, 0xfff0);
1861 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_PREF_MEMORY_LIMIT, 0x0000);
1862 devpciR3SetDWord(pDevIns, pBridge, VBOX_PCI_PREF_BASE_UPPER32, 0x00000000);
1863 devpciR3SetDWord(pDevIns, pBridge, VBOX_PCI_PREF_LIMIT_UPPER32, 0x00000000);
1864}
1865
1866static int ich9pciBiosInitDeviceGetRegions(PPDMPCIDEV pPciDev)
1867{
1868 uint8_t uHeaderType = devpciR3GetByte(pPciDev, VBOX_PCI_HEADER_TYPE) & 0x7f;
1869 if (uHeaderType == 0x00)
1870 /* Ignore ROM region here, which is included in VBOX_PCI_NUM_REGIONS. */
1871 return VBOX_PCI_NUM_REGIONS - 1;
1872 else if (uHeaderType == 0x01)
1873 /* PCI bridges have 2 BARs. */
1874 return 2;
1875 else
1876 {
1877 AssertMsgFailed(("invalid header type %#x\n", uHeaderType));
1878 return 0;
1879 }
1880}
1881
1882static void ich9pciBiosInitDeviceBARs(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev)
1883{
1884 int cRegions = ich9pciBiosInitDeviceGetRegions(pPciDev);
1885 bool fSuppressMem = false;
1886 bool fActiveMemRegion = false;
1887 bool fActiveIORegion = false;
1888 for (int iRegion = 0; iRegion < cRegions; iRegion++)
1889 {
1890 uint32_t u32Address = devpciGetRegionReg(iRegion);
1891
1892 /* Calculate size - we write all 1s into the BAR, and then evaluate which bits
1893 are cleared. */
1894 uint8_t u8ResourceType = devpciR3GetByte(pPciDev, u32Address);
1895
1896 bool fPrefetch = (u8ResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_IO)))
1897 == PCI_ADDRESS_SPACE_MEM_PREFETCH;
1898 bool f64Bit = (u8ResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
1899 == PCI_ADDRESS_SPACE_BAR64;
1900 bool fIsPio = ((u8ResourceType & PCI_ADDRESS_SPACE_IO) == PCI_ADDRESS_SPACE_IO);
1901 uint64_t cbRegSize64 = 0;
1902
1903 /* Hack: initialize prefetchable BARs for devices on the root bus
1904 * early, but for all other prefetchable BARs do it after the
1905 * non-prefetchable BARs are initialized on all buses. */
1906 if (fPrefetch && pBus->iBus != 0)
1907 {
1908 fSuppressMem = true;
1909 if (f64Bit)
1910 iRegion++; /* skip next region */
1911 continue;
1912 }
1913
1914 if (f64Bit)
1915 {
1916 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0xffffffff));
1917 devpciR3SetDWord(pDevIns, pPciDev, u32Address+4, UINT32_C(0xffffffff));
1918 cbRegSize64 = RT_MAKE_U64(devpciR3GetDWord(pPciDev, u32Address),
1919 devpciR3GetDWord(pPciDev, u32Address+4));
1920 cbRegSize64 &= ~UINT64_C(0x0f);
1921 cbRegSize64 = (~cbRegSize64) + 1;
1922
1923 /* No 64-bit PIO regions possible. */
1924#ifndef DEBUG_bird /* EFI triggers this for DevAHCI. */
1925 AssertMsg((u8ResourceType & PCI_ADDRESS_SPACE_IO) == 0, ("type=%#x rgn=%d\n", u8ResourceType, iRegion));
1926#endif
1927 }
1928 else
1929 {
1930 uint32_t cbRegSize32;
1931 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0xffffffff));
1932 cbRegSize32 = devpciR3GetDWord(pPciDev, u32Address);
1933
1934 /* Clear resource information depending on resource type. */
1935 if (fIsPio) /* PIO */
1936 cbRegSize32 &= ~UINT32_C(0x01);
1937 else /* MMIO */
1938 cbRegSize32 &= ~UINT32_C(0x0f);
1939
1940 /*
1941 * Invert all bits and add 1 to get size of the region.
1942 * (From PCI implementation note)
1943 */
1944 if (fIsPio && (cbRegSize32 & UINT32_C(0xffff0000)) == 0)
1945 cbRegSize32 = (~(cbRegSize32 | UINT32_C(0xffff0000))) + 1;
1946 else
1947 cbRegSize32 = (~cbRegSize32) + 1;
1948
1949 cbRegSize64 = cbRegSize32;
1950 }
1951 Log2Func(("Size of region %u for device %d on bus %d is %lld\n", iRegion, pPciDev->uDevFn, pBus->iBus, cbRegSize64));
1952
1953 if (cbRegSize64)
1954 {
1955 /* Try 32-bit base first. */
1956 uint32_t* paddr = fIsPio ? &pPciRoot->uPciBiosIo : &pPciRoot->uPciBiosMmio;
1957 uint64_t uNew = *paddr;
1958 /* Align starting address to region size. */
1959 uNew = (uNew + cbRegSize64 - 1) & ~(cbRegSize64 - 1);
1960 if (fIsPio)
1961 uNew &= UINT32_C(0xffff);
1962 /* Unconditionally exclude I/O-APIC/HPET/ROM. Pessimistic, but better than causing a mess. */
1963 if ( !uNew
1964 || (uNew <= UINT32_C(0xffffffff) && uNew + cbRegSize64 - 1 >= UINT32_C(0xfec00000))
1965 || uNew >= _4G)
1966 {
1967 /* Only prefetchable regions can be placed above 4GB, as the
1968 * address decoder for non-prefetchable addresses in bridges
1969 * is limited to 32 bits. */
1970 if (f64Bit && fPrefetch)
1971 {
1972 /* Map a 64-bit region above 4GB. */
1973 Assert(!fIsPio);
1974 uNew = pPciRoot->uPciBiosMmio64;
1975 /* Align starting address to region size. */
1976 uNew = (uNew + cbRegSize64 - 1) & ~(cbRegSize64 - 1);
1977 LogFunc(("Start address of 64-bit MMIO region %u/%u is %#llx\n", iRegion, iRegion + 1, uNew));
1978 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, iRegion, uNew);
1979 fActiveMemRegion = true;
1980 pPciRoot->uPciBiosMmio64 = uNew + cbRegSize64;
1981 Log2Func(("New 64-bit address is %#llx\n", pPciRoot->uPciBiosMmio64));
1982 }
1983 else
1984 {
1985 uint16_t uVendor = devpciR3GetWord(pPciDev, VBOX_PCI_VENDOR_ID);
1986 uint16_t uDevice = devpciR3GetWord(pPciDev, VBOX_PCI_DEVICE_ID);
1987 LogRel(("PCI: no space left for BAR%u of device %u/%u/%u (vendor=%#06x device=%#06x)\n",
1988 iRegion, pBus->iBus, pPciDev->uDevFn >> 3, pPciDev->uDevFn & 7, uVendor, uDevice)); /** @todo make this a VM start failure later. */
1989 /* Undo the mapping mess caused by the size probing. */
1990 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0));
1991 }
1992 }
1993 else
1994 {
1995 LogFunc(("Start address of %s region %u is %#x\n", (fIsPio ? "I/O" : "MMIO"), iRegion, uNew));
1996 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, iRegion, uNew);
1997 if (fIsPio)
1998 fActiveIORegion = true;
1999 else
2000 fActiveMemRegion = true;
2001 *paddr = uNew + cbRegSize64;
2002 Log2Func(("New 32-bit address is %#x\n", *paddr));
2003 }
2004
2005 if (f64Bit)
2006 iRegion++; /* skip next region */
2007 }
2008 }
2009
2010 /* Update the command word appropriately. */
2011 uint16_t uCmd = devpciR3GetWord(pPciDev, VBOX_PCI_COMMAND);
2012 if (fActiveMemRegion && !fSuppressMem)
2013 uCmd |= VBOX_PCI_COMMAND_MEMORY; /* Enable MMIO access. */
2014 if (fActiveIORegion)
2015 uCmd |= VBOX_PCI_COMMAND_IO; /* Enable I/O space access. */
2016 devpciR3SetWord(pDevIns, pPciDev, VBOX_PCI_COMMAND, uCmd);
2017}
2018
2019static bool ich9pciBiosInitDevicePrefetchableBARs(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev, bool fUse64Bit, bool fDryrun)
2020{
2021 int cRegions = ich9pciBiosInitDeviceGetRegions(pPciDev);
2022 bool fActiveMemRegion = false;
2023 for (int iRegion = 0; iRegion < cRegions; iRegion++)
2024 {
2025 uint32_t u32Address = devpciGetRegionReg(iRegion);
2026 uint8_t u8ResourceType = devpciR3GetByte(pPciDev, u32Address);
2027 bool fPrefetch = (u8ResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_IO)))
2028 == PCI_ADDRESS_SPACE_MEM_PREFETCH;
2029 bool f64Bit = (u8ResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
2030 == PCI_ADDRESS_SPACE_BAR64;
2031 uint64_t cbRegSize64 = 0;
2032
2033 /* Everything besides prefetchable regions has been set up already. */
2034 if (!fPrefetch)
2035 continue;
2036
2037 if (f64Bit)
2038 {
2039 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0xffffffff));
2040 devpciR3SetDWord(pDevIns, pPciDev, u32Address+4, UINT32_C(0xffffffff));
2041 cbRegSize64 = RT_MAKE_U64(devpciR3GetDWord(pPciDev, u32Address),
2042 devpciR3GetDWord(pPciDev, u32Address+4));
2043 cbRegSize64 &= ~UINT64_C(0x0f);
2044 cbRegSize64 = (~cbRegSize64) + 1;
2045 }
2046 else
2047 {
2048 uint32_t cbRegSize32;
2049 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0xffffffff));
2050 cbRegSize32 = devpciR3GetDWord(pPciDev, u32Address);
2051 cbRegSize32 &= ~UINT32_C(0x0f);
2052 cbRegSize32 = (~cbRegSize32) + 1;
2053
2054 cbRegSize64 = cbRegSize32;
2055 }
2056 Log2Func(("Size of region %u for device %d on bus %d is %lld\n", iRegion, pPciDev->uDevFn, pBus->iBus, cbRegSize64));
2057
2058 if (cbRegSize64)
2059 {
2060 uint64_t uNew;
2061 if (!fUse64Bit)
2062 {
2063 uNew = pPciRoot->uPciBiosMmio;
2064 /* Align starting address to region size. */
2065 uNew = (uNew + cbRegSize64 - 1) & ~(cbRegSize64 - 1);
2066 /* Unconditionally exclude I/O-APIC/HPET/ROM. Pessimistic, but better than causing a mess. Okay for BIOS. */
2067 if ( !uNew
2068 || (uNew <= UINT32_C(0xffffffff) && uNew + cbRegSize64 - 1 >= UINT32_C(0xfec00000))
2069 || uNew >= _4G)
2070 {
2071 Log2Func(("region #%u: Rejecting address range: %#x LB %#RX64\n", iRegion, uNew, cbRegSize64));
2072 Assert(fDryrun);
2073 return true;
2074 }
2075 if (!fDryrun)
2076 {
2077 LogFunc(("Start address of MMIO region %u is %#x\n", iRegion, uNew));
2078 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, iRegion, uNew);
2079 fActiveMemRegion = true;
2080 }
2081 pPciRoot->uPciBiosMmio = uNew + cbRegSize64;
2082 }
2083 else
2084 {
2085 /* Can't handle 32-bit BARs when forcing 64-bit allocs. */
2086 if (!f64Bit)
2087 {
2088 Assert(fDryrun);
2089 return true;
2090 }
2091 uNew = pPciRoot->uPciBiosMmio64;
2092 /* Align starting address to region size. */
2093 uNew = (uNew + cbRegSize64 - 1) & ~(cbRegSize64 - 1);
2094 pPciRoot->uPciBiosMmio64 = uNew + cbRegSize64;
2095 if (!fDryrun)
2096 {
2097 LogFunc(("Start address of 64-bit MMIO region %u/%u is %#llx\n", iRegion, iRegion + 1, uNew));
2098 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, iRegion, uNew);
2099 fActiveMemRegion = true;
2100 }
2101 }
2102
2103 if (f64Bit)
2104 iRegion++; /* skip next region */
2105 }
2106 }
2107
2108 if (!fDryrun)
2109 {
2110 /* Update the command word appropriately. */
2111 uint16_t uCmd = devpciR3GetWord(pPciDev, VBOX_PCI_COMMAND);
2112 if (fActiveMemRegion)
2113 uCmd |= VBOX_PCI_COMMAND_MEMORY; /* Enable MMIO access. */
2114 devpciR3SetWord(pDevIns, pPciDev, VBOX_PCI_COMMAND, uCmd);
2115 }
2116 else
2117 Assert(!fActiveMemRegion);
2118
2119 return false;
2120}
2121
2122static bool ich9pciBiosInitBridgePrefetchable(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus, bool fUse64Bit, bool fDryrun)
2123{
2124 PPDMPCIDEV pBridge = pDevIns->apPciDevs[0];
2125 Log(("BIOS init bridge (prefetch): %02x:%02x.%d use64bit=%d dryrun=%d\n", pBus->iBus, pBridge->uDevFn >> 3, pBridge->uDevFn & 7, fUse64Bit, fDryrun));
2126
2127 pPciRoot->uPciBiosMmio = RT_ALIGN_32(pPciRoot->uPciBiosMmio, _1M);
2128 pPciRoot->uPciBiosMmio64 = RT_ALIGN_64(pPciRoot->uPciBiosMmio64, _1M);
2129
2130 /* Save values to compare later to. */
2131 uint32_t u32MMIOAddressBase = pPciRoot->uPciBiosMmio;
2132 uint64_t u64MMIOAddressBase = pPciRoot->uPciBiosMmio64;
2133
2134 /* Init all devices behind the bridge (recursing to further buses). */
2135 bool fRes = ich9pciBiosInitAllDevicesPrefetchableOnBus(pDevIns, pPciRoot, pBus, fUse64Bit, fDryrun);
2136 if (fDryrun)
2137 return fRes;
2138 Assert(!fRes);
2139
2140 /* Set prefetchable MMIO limit register with 1MB boundary. */
2141 uint64_t uBase, uLimit;
2142 if (fUse64Bit)
2143 {
2144 if (u64MMIOAddressBase == pPciRoot->uPciBiosMmio64)
2145 return false;
2146 uBase = u64MMIOAddressBase;
2147 uLimit = RT_ALIGN_64(pPciRoot->uPciBiosMmio64, _1M) - 1;
2148 }
2149 else
2150 {
2151 if (u32MMIOAddressBase == pPciRoot->uPciBiosMmio)
2152 return false;
2153 uBase = u32MMIOAddressBase;
2154 uLimit = RT_ALIGN_32(pPciRoot->uPciBiosMmio, _1M) - 1;
2155 }
2156 devpciR3SetDWord(pDevIns, pBridge, VBOX_PCI_PREF_BASE_UPPER32, uBase >> 32);
2157 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_PREF_MEMORY_BASE, (uint32_t)(uBase >> 16) & UINT32_C(0xfff0));
2158 devpciR3SetDWord(pDevIns, pBridge, VBOX_PCI_PREF_LIMIT_UPPER32, uLimit >> 32);
2159 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_PREF_MEMORY_LIMIT, (uint32_t)(uLimit >> 16) & UINT32_C(0xfff0));
2160
2161 return false;
2162}
2163
2164static bool ich9pciBiosInitAllDevicesPrefetchableOnBus(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus,
2165 bool fUse64Bit, bool fDryrun)
2166{
2167 /* First pass: assign resources to all devices. */
2168 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
2169 {
2170 PPDMPCIDEV pPciDev = pBus->apDevices[uDevFn];
2171
2172 /* check if device is present */
2173 if (!pPciDev)
2174 continue;
2175
2176 Log(("BIOS init device (prefetch): %02x:%02x.%d\n", pBus->iBus, uDevFn >> 3, uDevFn & 7));
2177
2178 /* prefetchable memory mappings */
2179 bool fRes = ich9pciBiosInitDevicePrefetchableBARs(pDevIns, pPciRoot, pBus, pPciDev, fUse64Bit, fDryrun);
2180 if (fRes)
2181 {
2182 Assert(fDryrun);
2183 return fRes;
2184 }
2185 }
2186
2187 /* Second pass: handle bridges recursively. */
2188 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2189 {
2190 PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
2191 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
2192 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
2193 PDEVPCIBUS pChildBus = PDMINS_2_DATA(pBridge->Int.s.CTX_SUFF(pDevIns), PDEVPCIBUS);
2194
2195 bool fRes = ich9pciBiosInitBridgePrefetchable(pDevIns, pPciRoot, pChildBus, fUse64Bit, fDryrun);
2196 if (fRes)
2197 {
2198 Assert(fDryrun);
2199 return fRes;
2200 }
2201 }
2202 return false;
2203}
2204
2205static void ich9pciBiosInitAllDevicesOnBus(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus)
2206{
2207 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
2208
2209 /* First pass: assign resources to all devices and map the interrupt. */
2210 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
2211 {
2212 PPDMPCIDEV pPciDev = pBus->apDevices[uDevFn];
2213
2214 /* check if device is present */
2215 if (!pPciDev)
2216 continue;
2217
2218 Log(("BIOS init device: %02x:%02x.%d\n", pBus->iBus, uDevFn >> 3, uDevFn & 7));
2219
2220 /* default memory mappings */
2221 ich9pciBiosInitDeviceBARs(pDevIns, pPciRoot, pBus, pPciDev);
2222 uint16_t uDevClass = devpciR3GetWord(pPciDev, VBOX_PCI_CLASS_DEVICE);
2223 switch (uDevClass)
2224 {
2225 case 0x0101:
2226 /* IDE controller */
2227 devpciR3SetWord(pDevIns, pPciDev, 0x40, 0x8000); /* enable IDE0 */
2228 devpciR3SetWord(pDevIns, pPciDev, 0x42, 0x8000); /* enable IDE1 */
2229 break;
2230 case 0x0300:
2231 {
2232 /* VGA controller */
2233
2234 /* NB: Default Bochs VGA LFB address is 0xE0000000. Old guest
2235 * software may break if the framebuffer isn't mapped there.
2236 */
2237
2238 /*
2239 * Legacy VGA I/O ports are implicitly decoded by a VGA class device. But
2240 * only the framebuffer (i.e., a memory region) is explicitly registered via
2241 * ich9pciSetRegionAddress, so don't forget to enable I/O decoding.
2242 */
2243 uint16_t uCmd = devpciR3GetWord(pPciDev, VBOX_PCI_COMMAND);
2244 devpciR3SetWord(pDevIns, pPciDev, VBOX_PCI_COMMAND, uCmd | VBOX_PCI_COMMAND_IO);
2245 break;
2246 }
2247 default:
2248 break;
2249 }
2250
2251 /* map the interrupt */
2252 uint8_t iPin = devpciR3GetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN);
2253 if (iPin != 0)
2254 {
2255 iPin--;
2256
2257 /* We need to go up to the host bus to see which irq pin this
2258 device will use there. See logic in ich9pcibridgeSetIrq(). */
2259 uint32_t idxPdmParentBus;
2260 PPDMDEVINS pDevInsParent = pDevIns;
2261 while ((idxPdmParentBus = pDevInsParent->apPciDevs[0]->Int.s.idxPdmBus) != 0)
2262 {
2263 /* Get the pin the device would assert on the bridge. */
2264 iPin = ((pDevInsParent->apPciDevs[0]->uDevFn >> 3) + iPin) & 3;
2265
2266 pDevInsParent = pBusCC->pPciHlpR3->pfnGetBusByNo(pDevIns, idxPdmParentBus);
2267 AssertLogRelBreak(pDevInsParent);
2268 }
2269
2270 int iIrq = aPciIrqs[ich9pciSlotGetPirq(pBus->iBus, uDevFn, iPin)];
2271 Log(("Using pin %d and IRQ %d for device %02x:%02x.%d\n",
2272 iPin, iIrq, pBus->iBus, uDevFn>>3, uDevFn&7));
2273 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_INTERRUPT_LINE, iIrq);
2274 }
2275 }
2276
2277 /* Second pass: handle bridges recursively. */
2278 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2279 {
2280 PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
2281 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
2282 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
2283 PDEVPCIBUS pChildBus = PDMINS_2_DATA(pBridge->Int.s.CTX_SUFF(pDevIns), PDEVPCIBUS);
2284
2285 ich9pciBiosInitBridge(pDevIns, pPciRoot, pChildBus);
2286 }
2287
2288 /* Third pass (only for bus 0): set up prefetchable BARs recursively. */
2289 if (pBus->iBus == 0)
2290 {
2291 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2292 {
2293 PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
2294 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
2295 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
2296 PDEVPCIBUS pChildBus = PDMINS_2_DATA(pBridge->Int.s.CTX_SUFF(pDevIns), PDEVPCIBUS);
2297
2298 Log(("BIOS init prefetchable memory behind bridge: %02x:%02x.%d\n", pChildBus->iBus, pBridge->uDevFn >> 3, pBridge->uDevFn & 7));
2299 /* Save values for the prefetchable dryruns. */
2300 uint32_t u32MMIOAddressBase = pPciRoot->uPciBiosMmio;
2301 uint64_t u64MMIOAddressBase = pPciRoot->uPciBiosMmio64;
2302
2303 bool fProbe = ich9pciBiosInitBridgePrefetchable(pDevIns, pPciRoot, pChildBus, false /* fUse64Bit */, true /* fDryrun */);
2304 pPciRoot->uPciBiosMmio = u32MMIOAddressBase;
2305 pPciRoot->uPciBiosMmio64 = u64MMIOAddressBase;
2306 if (fProbe)
2307 {
2308 fProbe = ich9pciBiosInitBridgePrefetchable(pDevIns, pPciRoot, pChildBus, true /* fUse64Bit */, true /* fDryrun */);
2309 pPciRoot->uPciBiosMmio = u32MMIOAddressBase;
2310 pPciRoot->uPciBiosMmio64 = u64MMIOAddressBase;
2311 if (fProbe)
2312 LogRel(("PCI: unresolvable prefetchable memory behind bridge %02x:%02x.%d\n", pChildBus->iBus, pBridge->uDevFn >> 3, pBridge->uDevFn & 7));
2313 else
2314 ich9pciBiosInitBridgePrefetchable(pDevIns, pPciRoot, pChildBus, true /* fUse64Bit */, false /* fDryrun */);
2315 }
2316 else
2317 ich9pciBiosInitBridgePrefetchable(pDevIns, pPciRoot, pChildBus, false /* fUse64Bit */, false /* fDryrun */);
2318 }
2319 }
2320}
2321
2322/**
2323 * Initializes bridges registers used for routing.
2324 *
2325 * We ASSUME PDM bus assignments are the same as the PCI bus assignments and
2326 * will complain if we find any conflicts. This because it is just soo much
2327 * simpler to have the two numbers match one another by default.
2328 *
2329 * @returns Max subordinate bus number.
2330 * @param pDevIns The device instance of the bus.
2331 * @param pPciRoot Global device instance data used to generate unique bus numbers.
2332 * @param pBus The PCI bus to initialize.
2333 * @param pbmUsed Pointer to a 32-bit bitmap tracking which device
2334 * (ranges) has been used.
2335 * @param uBusPrimary The primary bus number the bus is connected to.
2336 */
2337static uint8_t ich9pciBiosInitBridgeTopology(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus,
2338 uint32_t *pbmUsed, uint8_t uBusPrimary)
2339{
2340 PPDMPCIDEV pBridgeDev = pDevIns->apPciDevs[0];
2341
2342 /* Check if the PDM bus assignment makes sense. */
2343 AssertLogRelMsg(!(*pbmUsed & RT_BIT_32(pBus->iBus)),
2344 ("PCIBIOS: Bad PCI bridge config! Conflict for bus %#x. Make sure to instantiate bridges for a sub-trees in sequence!\n",
2345 pBus->iBus));
2346 *pbmUsed |= RT_BIT_32(pBus->iBus);
2347
2348 /* Set only if we are not on the root bus, it has no primary bus attached. */
2349 if (pBus->iBus != 0)
2350 {
2351 devpciR3SetByte(pDevIns, pBridgeDev, VBOX_PCI_PRIMARY_BUS, uBusPrimary);
2352 devpciR3SetByte(pDevIns, pBridgeDev, VBOX_PCI_SECONDARY_BUS, pBus->iBus);
2353 /* Since the subordinate bus value can only be finalized once we
2354 * finished recursing through everything behind the bridge, the only
2355 * solution is temporarily configuring the subordinate to the maximum
2356 * possible value. This makes sure that the config space accesses work
2357 * (for our own sloppy emulation it apparently doesn't matter, but
2358 * this is vital for real PCI bridges/devices in passthrough mode). */
2359 devpciR3SetByte(pDevIns, pBridgeDev, VBOX_PCI_SUBORDINATE_BUS, 0xff);
2360 }
2361
2362 uint8_t uMaxSubNum = pBus->iBus;
2363 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2364 {
2365 PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
2366 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
2367 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
2368 PDEVPCIBUS pChildBus = PDMINS_2_DATA(pBridge->Int.s.CTX_SUFF(pDevIns), PDEVPCIBUS);
2369 uint8_t uMaxChildSubBus = ich9pciBiosInitBridgeTopology(pDevIns, pPciRoot, pChildBus, pbmUsed, pBus->iBus);
2370 uMaxSubNum = RT_MAX(uMaxSubNum, uMaxChildSubBus);
2371 }
2372
2373 if (pBus->iBus != 0)
2374 devpciR3SetByte(pDevIns, pBridgeDev, VBOX_PCI_SUBORDINATE_BUS, uMaxSubNum);
2375 for (uint32_t i = pBus->iBus; i <= uMaxSubNum; i++)
2376 *pbmUsed |= RT_BIT_32(i);
2377
2378 /* Make sure that transactions are able to get through the bridge. Not
2379 * strictly speaking necessary this early (before any device is set up),
2380 * but on the other hand it can't hurt either. */
2381 if (pBus->iBus != 0)
2382 devpciR3SetWord(pDevIns, pBridgeDev, VBOX_PCI_COMMAND,
2383 VBOX_PCI_COMMAND_IO
2384 | VBOX_PCI_COMMAND_MEMORY
2385 | VBOX_PCI_COMMAND_MASTER);
2386
2387 /* safe, only needs to go to the config space array */
2388 Log2Func(("for bus %p: primary=%d secondary=%d subordinate=%d\n", pBus,
2389 PDMPciDevGetByte(pBridgeDev, VBOX_PCI_PRIMARY_BUS),
2390 PDMPciDevGetByte(pBridgeDev, VBOX_PCI_SECONDARY_BUS),
2391 PDMPciDevGetByte(pBridgeDev, VBOX_PCI_SUBORDINATE_BUS) ));
2392
2393 return uMaxSubNum;
2394}
2395
2396
2397/**
2398 * Worker for Fake PCI BIOS config
2399 *
2400 * @returns VBox status code.
2401 *
2402 * @param pDevIns ICH9 device instance.
2403 */
2404static int ich9pciFakePCIBIOS(PPDMDEVINS pDevIns)
2405{
2406 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
2407 PVM pVM = PDMDevHlpGetVM(pDevIns);
2408 uint32_t const cbBelow4GB = MMR3PhysGetRamSizeBelow4GB(pVM);
2409 uint64_t const cbAbove4GB = MMR3PhysGetRamSizeAbove4GB(pVM);
2410
2411 LogRel(("PCI: setting up topology, resources and interrupts\n"));
2412
2413 /** @todo r=klaus this needs to do the same elcr magic as DevPCI.cpp, as the BIOS can't be trusted to do the right thing. Of course it's more difficult than with the old code, as there are bridges to be handled. The interrupt routing needs to be taken into account. Also I highly suspect that the chipset has 8 interrupt lines which we might be able to use for handling things on the root bus better (by treating them as devices on the mainboard). */
2414
2415 /*
2416 * Set the start addresses.
2417 */
2418 pPciRoot->uPciBiosBus = 0;
2419 pPciRoot->uPciBiosIo = 0xd000;
2420 pPciRoot->uPciBiosMmio = cbBelow4GB;
2421 pPciRoot->uPciBiosMmio64 = cbAbove4GB + _4G;
2422
2423 /* NB: Assume that if PCI controller MMIO range is enabled, it is below the beginning of the memory hole. */
2424 if (pPciRoot->u64PciConfigMMioAddress)
2425 {
2426 AssertRelease(pPciRoot->u64PciConfigMMioAddress >= cbBelow4GB);
2427 pPciRoot->uPciBiosMmio = pPciRoot->u64PciConfigMMioAddress + pPciRoot->u64PciConfigMMioLength;
2428 }
2429 Log(("cbBelow4GB: %#RX32, uPciBiosMmio: %#RX64, cbAbove4GB: %#RX64, uPciBiosMmio64=%#RX64\n",
2430 cbBelow4GB, pPciRoot->uPciBiosMmio, cbAbove4GB, pPciRoot->uPciBiosMmio64));
2431
2432 /*
2433 * Assign bridge topology, for further routing to work.
2434 */
2435 PDEVPCIBUS pBus = &pPciRoot->PciBus;
2436 AssertLogRel(pBus->iBus == 0);
2437 uint32_t bmUsed = 0;
2438 ich9pciBiosInitBridgeTopology(pDevIns, pPciRoot, pBus, &bmUsed, 0);
2439
2440 /*
2441 * Init all devices on bus 0 (recursing to further buses).
2442 */
2443 ich9pciBiosInitAllDevicesOnBus(pDevIns, pPciRoot, pBus);
2444
2445 return VINF_SUCCESS;
2446}
2447
2448
2449/* -=-=-=-=-=- PCI Config Space -=-=-=-=-=- */
2450
2451
2452/**
2453 * Reads config space for a device, ignoring interceptors.
2454 */
2455DECLHIDDEN(VBOXSTRICTRC) devpciR3CommonConfigReadWorker(PPDMPCIDEV pPciDev, uint32_t uAddress, unsigned cb, uint32_t *pu32Value)
2456{
2457 uint32_t uValue;
2458 if (uAddress + cb <= RT_MIN(pPciDev->cbConfig, sizeof(pPciDev->abConfig)))
2459 {
2460 switch (cb)
2461 {
2462 case 1:
2463 /* safe, only needs to go to the config space array */
2464 uValue = PDMPciDevGetByte(pPciDev, uAddress);
2465 break;
2466 case 2:
2467 /* safe, only needs to go to the config space array */
2468 uValue = PDMPciDevGetWord(pPciDev, uAddress);
2469 break;
2470 case 4:
2471 /* safe, only needs to go to the config space array */
2472 uValue = PDMPciDevGetDWord(pPciDev, uAddress);
2473 break;
2474 default:
2475 AssertFailed();
2476 uValue = 0;
2477 break;
2478 }
2479
2480#ifdef LOG_ENABLED
2481 if ( pciDevIsMsiCapable(pPciDev)
2482 && uAddress - (uint32_t)pPciDev->Int.s.u8MsiCapOffset < (uint32_t)pPciDev->Int.s.u8MsiCapSize )
2483 Log2Func(("MSI CAP: %#x LB %u -> %#x\n", uAddress - (uint32_t)pPciDev->Int.s.u8MsiCapOffset, cb, uValue));
2484 else if ( pciDevIsMsixCapable(pPciDev)
2485 && uAddress - (uint32_t)pPciDev->Int.s.u8MsixCapOffset < (uint32_t)pPciDev->Int.s.u8MsixCapSize)
2486 Log2Func(("MSI-X CAP: %#x LB %u -> %#x\n", uAddress - (uint32_t)pPciDev->Int.s.u8MsiCapOffset, cb, uValue));
2487#endif
2488 }
2489 else
2490 {
2491 AssertMsgFailed(("Read after end of PCI config space: %#x LB %u\n", uAddress, cb));
2492 uValue = 0;
2493 }
2494
2495 *pu32Value = uValue;
2496 return VINF_SUCCESS;
2497}
2498
2499
2500/**
2501 * @interface_method_impl{PDMPCIBUSREGR3,pfnConfigRead}
2502 */
2503DECLCALLBACK(VBOXSTRICTRC) devpciR3CommonConfigRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
2504 uint32_t uAddress, unsigned cb, uint32_t *pu32Value)
2505{
2506 RT_NOREF(pDevIns);
2507 return devpciR3CommonConfigReadWorker(pPciDev, uAddress, cb, pu32Value);
2508}
2509
2510
2511/**
2512 * Worker for devpciR3ResetDevice and devpciR3UpdateMappings that unmaps a region.
2513 *
2514 * @returns VBox status code.
2515 * @param pDev The PCI device.
2516 * @param iRegion The region to unmap.
2517 */
2518static int devpciR3UnmapRegion(PPDMPCIDEV pDev, int iRegion)
2519{
2520 PPCIIOREGION pRegion = &pDev->Int.s.aIORegions[iRegion];
2521 AssertReturn(pRegion->size != 0, VINF_SUCCESS);
2522
2523 int rc = VINF_SUCCESS;
2524 if (pRegion->addr != INVALID_PCI_ADDRESS)
2525 {
2526 /*
2527 * Do callout first (optional), then do the unmapping via handle if we've been handed one.
2528 */
2529 if (pRegion->pfnMap)
2530 {
2531 rc = pRegion->pfnMap(pDev->Int.s.pDevInsR3, pDev, iRegion,
2532 NIL_RTGCPHYS, pRegion->size, (PCIADDRESSSPACE)(pRegion->type));
2533 AssertRC(rc);
2534 }
2535
2536 switch (pRegion->fFlags & PDMPCIDEV_IORGN_F_HANDLE_MASK)
2537 {
2538 case PDMPCIDEV_IORGN_F_IOPORT_HANDLE:
2539 rc = PDMDevHlpIoPortUnmap(pDev->Int.s.pDevInsR3, (IOMIOPORTHANDLE)pRegion->hHandle);
2540 AssertRC(rc);
2541 break;
2542
2543 case PDMPCIDEV_IORGN_F_MMIO_HANDLE:
2544 rc = PDMDevHlpMmioUnmap(pDev->Int.s.pDevInsR3, (IOMMMIOHANDLE)pRegion->hHandle);
2545 AssertRC(rc);
2546 break;
2547
2548 case PDMPCIDEV_IORGN_F_MMIO2_HANDLE:
2549 rc = PDMDevHlpMmio2Unmap(pDev->Int.s.pDevInsR3, (PGMMMIO2HANDLE)pRegion->hHandle);
2550 AssertRC(rc);
2551 break;
2552
2553 case PDMPCIDEV_IORGN_F_NO_HANDLE:
2554 Assert(pRegion->fFlags & PDMPCIDEV_IORGN_F_NEW_STYLE);
2555 Assert(pRegion->hHandle == UINT64_MAX);
2556 break;
2557
2558 default:
2559 AssertLogRelFailed();
2560 }
2561 pRegion->addr = INVALID_PCI_ADDRESS;
2562 }
2563 return rc;
2564}
2565
2566
2567/**
2568 * Worker for devpciR3CommonDefaultConfigWrite that updates BAR and ROM mappings.
2569 *
2570 * @returns VINF_SUCCESS of DBGFSTOP result.
2571 * @param pPciDev The PCI device to update the mappings for.
2572 * @param fP2PBridge Whether this is a PCI to PCI bridge or not.
2573 */
2574static VBOXSTRICTRC devpciR3UpdateMappings(PPDMPCIDEV pPciDev, bool fP2PBridge)
2575{
2576 /* safe, only needs to go to the config space array */
2577 uint16_t const u16Cmd = PDMPciDevGetWord(pPciDev, VBOX_PCI_COMMAND);
2578 Log4(("devpciR3UpdateMappings: dev %u/%u (%s): u16Cmd=%#x\n",
2579 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK, pPciDev->pszNameR3, u16Cmd));
2580 for (unsigned iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
2581 {
2582 /* Skip over BAR2..BAR5 for bridges, as they have a different meaning there. */
2583 if (fP2PBridge && iRegion >= 2 && iRegion <= 5)
2584 continue;
2585 PCIIOREGION *pRegion = &pPciDev->Int.s.aIORegions[iRegion];
2586 uint64_t const cbRegion = pRegion->size;
2587 if (cbRegion != 0)
2588 {
2589 uint32_t const offCfgReg = devpciGetRegionReg(iRegion);
2590 bool const f64Bit = (pRegion->type & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
2591 == PCI_ADDRESS_SPACE_BAR64;
2592 uint64_t uNew = INVALID_PCI_ADDRESS;
2593
2594 /*
2595 * Port I/O region. Check if mapped and within 1..65535 range.
2596 */
2597 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
2598 {
2599 if (u16Cmd & VBOX_PCI_COMMAND_IO)
2600 {
2601 /* safe, only needs to go to the config space array */
2602 uint32_t uIoBase = PDMPciDevGetDWord(pPciDev, offCfgReg);
2603 uIoBase &= ~(uint32_t)(cbRegion - 1);
2604
2605 uint64_t uLast = cbRegion - 1 + uIoBase;
2606 if ( uLast < _64K
2607 && uIoBase < uLast
2608 && uIoBase > 0)
2609 uNew = uIoBase;
2610 else
2611 Log4(("devpciR3UpdateMappings: dev %u/%u (%s): region #%u: Disregarding invalid I/O port range: %#RX32..%#RX64\n",
2612 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2613 pPciDev->pszNameR3, iRegion, uIoBase, uLast));
2614 }
2615 }
2616 /*
2617 * MMIO or ROM. Check ROM enable bit and range.
2618 *
2619 * Note! We exclude the I/O-APIC/HPET/ROM area at the end of the first 4GB to
2620 * prevent the (fake) PCI BIOS and others from making a mess. Pure paranoia.
2621 * Additionally addresses with the top 32 bits all set are excluded, to
2622 * catch silly OSes which probe 64-bit BARs without disabling the
2623 * corresponding transactions.
2624 *
2625 * Update: The pure paranoia above broke NT 3.51, so it was changed to only
2626 * exclude the 64KB BIOS mapping at the top. NT 3.51 excludes the
2627 * top 256KB, btw.
2628 */
2629 /** @todo Query upper boundrary from CPUM and PGMPhysRom instead of making
2630 * incorrect assumptions. */
2631 else if (u16Cmd & VBOX_PCI_COMMAND_MEMORY)
2632 {
2633 /* safe, only needs to go to the config space array */
2634 uint64_t uMemBase = PDMPciDevGetDWord(pPciDev, offCfgReg);
2635 if (f64Bit)
2636 {
2637 Assert(iRegion < VBOX_PCI_ROM_SLOT);
2638 /* safe, only needs to go to the config space array */
2639 uMemBase |= (uint64_t)PDMPciDevGetDWord(pPciDev, offCfgReg + 4) << 32;
2640 }
2641 if ( iRegion != PCI_ROM_SLOT
2642 || (uMemBase & RT_BIT_32(0))) /* ROM enable bit. */
2643 {
2644 uMemBase &= ~(cbRegion - 1);
2645
2646 uint64_t uLast = uMemBase + cbRegion - 1;
2647 if ( uMemBase < uLast
2648 && uMemBase > 0)
2649 {
2650 if ( ( uMemBase > UINT32_C(0xffffffff)
2651 || uLast < UINT32_C(0xffff0000) ) /* UINT32_C(0xfec00000) - breaks NT3.51! */
2652 && uMemBase < UINT64_C(0xffffffff00000000) )
2653 uNew = uMemBase;
2654 else
2655 Log(("devpciR3UpdateMappings: dev %u/%u (%s): region #%u: Rejecting address range: %#RX64..%#RX64!\n",
2656 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2657 pPciDev->pszNameR3, iRegion, uMemBase, uLast));
2658 }
2659 else
2660 Log2(("devpciR3UpdateMappings: dev %u/%u (%s): region #%u: Disregarding invalid address range: %#RX64..%#RX64\n",
2661 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2662 pPciDev->pszNameR3, iRegion, uMemBase, uLast));
2663 }
2664 }
2665
2666 /*
2667 * Do real unmapping and/or mapping if the address change.
2668 */
2669 Log4(("devpciR3UpdateMappings: dev %u/%u (%s): iRegion=%u addr=%#RX64 uNew=%#RX64\n",
2670 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK, pPciDev->pszNameR3,
2671 iRegion, pRegion->addr, uNew));
2672 if (uNew != pRegion->addr)
2673 {
2674 LogRel2(("PCI: config dev %u/%u (%s) BAR%i: %#RX64 -> %#RX64 (LB %RX64 (%RU64))\n",
2675 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2676 pPciDev->pszNameR3, iRegion, pRegion->addr, uNew, cbRegion, cbRegion));
2677
2678 int rc = devpciR3UnmapRegion(pPciDev, iRegion);
2679 AssertLogRelRC(rc);
2680 pRegion->addr = uNew;
2681 if (uNew != INVALID_PCI_ADDRESS)
2682 {
2683 /* The callout is optional (typically not used): */
2684 if (!pRegion->pfnMap)
2685 rc = VINF_SUCCESS;
2686 else
2687 {
2688 rc = pRegion->pfnMap(pPciDev->Int.s.pDevInsR3, pPciDev, iRegion,
2689 uNew, cbRegion, (PCIADDRESSSPACE)(pRegion->type));
2690 AssertLogRelRC(rc);
2691 }
2692
2693 /* We do the mapping for most devices: */
2694 if (pRegion->hHandle != UINT64_MAX && rc != VINF_PCI_MAPPING_DONE)
2695 {
2696 switch (pRegion->fFlags & PDMPCIDEV_IORGN_F_HANDLE_MASK)
2697 {
2698 case PDMPCIDEV_IORGN_F_IOPORT_HANDLE:
2699 rc = PDMDevHlpIoPortMap(pPciDev->Int.s.pDevInsR3, (IOMIOPORTHANDLE)pRegion->hHandle, (RTIOPORT)uNew);
2700 AssertLogRelRC(rc);
2701 break;
2702
2703 case PDMPCIDEV_IORGN_F_MMIO_HANDLE:
2704 rc = PDMDevHlpMmioMap(pPciDev->Int.s.pDevInsR3, (IOMMMIOHANDLE)pRegion->hHandle, uNew);
2705 AssertLogRelRC(rc);
2706 break;
2707
2708 case PDMPCIDEV_IORGN_F_MMIO2_HANDLE:
2709 rc = PDMDevHlpMmio2Map(pPciDev->Int.s.pDevInsR3, (PGMMMIO2HANDLE)pRegion->hHandle, uNew);
2710 AssertRC(rc);
2711 break;
2712
2713 default:
2714 AssertLogRelFailed();
2715 }
2716 }
2717 }
2718 }
2719
2720 if (f64Bit)
2721 iRegion++;
2722 }
2723 /* else: size == 0: unused region */
2724 }
2725
2726 return VINF_SUCCESS;
2727}
2728
2729
2730/**
2731 * Worker for devpciR3CommonDefaultConfigWrite that write a byte to a BAR.
2732 *
2733 * @param pPciDev The PCI device.
2734 * @param iRegion The region.
2735 * @param off The BAR offset.
2736 * @param bVal The byte to write.
2737 */
2738DECLINLINE(void) devpciR3WriteBarByte(PPDMPCIDEV pPciDev, uint32_t iRegion, uint32_t off, uint8_t bVal)
2739{
2740 PCIIOREGION *pRegion = &pPciDev->Int.s.aIORegions[iRegion];
2741 Log3Func(("region=%d off=%d val=%#x size=%#llx\n", iRegion, off, bVal, pRegion->size));
2742 Assert(off <= 3);
2743
2744 /* Check if we're writing to upper part of 64-bit BAR. */
2745 if (pRegion->type == 0xff)
2746 {
2747 AssertLogRelReturnVoid(iRegion > 0 && iRegion < VBOX_PCI_ROM_SLOT);
2748 pRegion--;
2749 iRegion--;
2750 off += 4;
2751 Assert(pRegion->type & PCI_ADDRESS_SPACE_BAR64);
2752 }
2753
2754 /* Ignore zero sized regions (they don't exist). */
2755 if (pRegion->size != 0)
2756 {
2757 uint32_t uAddr = devpciGetRegionReg(iRegion) + off;
2758 Assert((pRegion->size & (pRegion->size - 1)) == 0); /* Region size must be power of two. */
2759 uint8_t bMask = ( (pRegion->size - 1) >> (off * 8) ) & 0xff;
2760 if (off == 0)
2761 bMask |= (pRegion->type & PCI_ADDRESS_SPACE_IO)
2762 ? (1 << 2) - 1 /* 2 lowest bits for IO region */ :
2763 (1 << 4) - 1 /* 4 lowest bits for memory region, also ROM enable bit for ROM region */;
2764
2765 /* safe, only needs to go to the config space array */
2766 uint8_t bOld = PDMPciDevGetByte(pPciDev, uAddr) & bMask;
2767 bVal = (bOld & bMask) | (bVal & ~bMask);
2768
2769 Log3Func(("%x changed to %x\n", bOld, bVal));
2770
2771 /* safe, only needs to go to the config space array */
2772 PDMPciDevSetByte(pPciDev, uAddr, bVal);
2773 }
2774}
2775
2776
2777/**
2778 * Checks if the given configuration byte is writable.
2779 *
2780 * @returns true if writable, false if not
2781 * @param uAddress The config space byte byte.
2782 * @param bHeaderType The device header byte.
2783 */
2784DECLINLINE(bool) devpciR3IsConfigByteWritable(uint32_t uAddress, uint8_t bHeaderType)
2785{
2786 switch (bHeaderType)
2787 {
2788 case 0x00: /* normal device */
2789 case 0x80: /* multi-function device */
2790 switch (uAddress)
2791 {
2792 /* Read-only registers. */
2793 case VBOX_PCI_VENDOR_ID:
2794 case VBOX_PCI_VENDOR_ID+1:
2795 case VBOX_PCI_DEVICE_ID:
2796 case VBOX_PCI_DEVICE_ID+1:
2797 case VBOX_PCI_REVISION_ID:
2798 case VBOX_PCI_CLASS_PROG:
2799 case VBOX_PCI_CLASS_SUB:
2800 case VBOX_PCI_CLASS_BASE:
2801 case VBOX_PCI_HEADER_TYPE:
2802 case VBOX_PCI_SUBSYSTEM_VENDOR_ID:
2803 case VBOX_PCI_SUBSYSTEM_VENDOR_ID+1:
2804 case VBOX_PCI_SUBSYSTEM_ID:
2805 case VBOX_PCI_SUBSYSTEM_ID+1:
2806 case VBOX_PCI_ROM_ADDRESS:
2807 case VBOX_PCI_ROM_ADDRESS+1:
2808 case VBOX_PCI_ROM_ADDRESS+2:
2809 case VBOX_PCI_ROM_ADDRESS+3:
2810 case VBOX_PCI_CAPABILITY_LIST:
2811 case VBOX_PCI_INTERRUPT_PIN:
2812 return false;
2813 /* Other registers can be written. */
2814 default:
2815 return true;
2816 }
2817 break;
2818 case 0x01: /* PCI-PCI bridge */
2819 switch (uAddress)
2820 {
2821 /* Read-only registers. */
2822 case VBOX_PCI_VENDOR_ID:
2823 case VBOX_PCI_VENDOR_ID+1:
2824 case VBOX_PCI_DEVICE_ID:
2825 case VBOX_PCI_DEVICE_ID+1:
2826 case VBOX_PCI_REVISION_ID:
2827 case VBOX_PCI_CLASS_PROG:
2828 case VBOX_PCI_CLASS_SUB:
2829 case VBOX_PCI_CLASS_BASE:
2830 case VBOX_PCI_HEADER_TYPE:
2831 case VBOX_PCI_ROM_ADDRESS_BR:
2832 case VBOX_PCI_ROM_ADDRESS_BR+1:
2833 case VBOX_PCI_ROM_ADDRESS_BR+2:
2834 case VBOX_PCI_ROM_ADDRESS_BR+3:
2835 case VBOX_PCI_INTERRUPT_PIN:
2836 return false;
2837 /* Other registers can be written. */
2838 default:
2839 return true;
2840 }
2841 break;
2842 default:
2843 AssertMsgFailed(("Unknown header type %#x\n", bHeaderType));
2844 return false;
2845 }
2846}
2847
2848
2849/**
2850 * Writes config space for a device, ignoring interceptors.
2851 *
2852 * See paragraph 7.5 of PCI Express specification (p. 349) for
2853 * definition of registers and their writability policy.
2854 */
2855DECLHIDDEN(VBOXSTRICTRC) devpciR3CommonConfigWriteWorker(PPDMDEVINS pDevIns, PDEVPCIBUSCC pBusCC,
2856 PPDMPCIDEV pPciDev, uint32_t uAddress, unsigned cb, uint32_t u32Value)
2857{
2858 Assert(cb <= 4 && cb != 3);
2859 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2860
2861 if (uAddress + cb <= RT_MIN(pPciDev->cbConfig, sizeof(pPciDev->abConfig)))
2862 {
2863 /*
2864 * MSI and MSI-X capabilites needs to be handled separately.
2865 */
2866 if ( pciDevIsMsiCapable(pPciDev)
2867 && uAddress - (uint32_t)pPciDev->Int.s.u8MsiCapOffset < (uint32_t)pPciDev->Int.s.u8MsiCapSize)
2868 MsiR3PciConfigWrite(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, uAddress, u32Value, cb);
2869 else if ( pciDevIsMsixCapable(pPciDev)
2870 && uAddress - (uint32_t)pPciDev->Int.s.u8MsixCapOffset < (uint32_t)pPciDev->Int.s.u8MsixCapSize)
2871 MsixR3PciConfigWrite(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, uAddress, u32Value, cb);
2872 else
2873 {
2874 /*
2875 * Handle the writes byte-by-byte to catch all possible cases.
2876 *
2877 * Note! Real hardware may not necessarily handle non-dword writes like
2878 * we do here and even produce erratic behavior. We don't (yet)
2879 * try emulate that.
2880 */
2881 uint8_t const bHeaderType = devpciR3GetByte(pPciDev, VBOX_PCI_HEADER_TYPE);
2882 bool const fP2PBridge = bHeaderType == 0x01; /* PCI-PCI bridge */
2883 bool fUpdateMappings = false;
2884 while (cb-- > 0)
2885 {
2886 bool fWritable = devpciR3IsConfigByteWritable(uAddress, bHeaderType);
2887 uint8_t bVal = (uint8_t)u32Value;
2888 bool fRom = false;
2889 switch (uAddress)
2890 {
2891 case VBOX_PCI_COMMAND: /* Command register, bits 0-7. */
2892 if (fWritable)
2893 {
2894 /* safe, only needs to go to the config space array */
2895 PDMPciDevSetByte(pPciDev, uAddress, bVal);
2896 fUpdateMappings = true;
2897 }
2898 break;
2899
2900 case VBOX_PCI_COMMAND+1: /* Command register, bits 8-15. */
2901 if (fWritable)
2902 {
2903 /* don't change reserved bits (11-15) */
2904 bVal &= ~UINT8_C(0xf8);
2905 /* safe, only needs to go to the config space array */
2906 PDMPciDevSetByte(pPciDev, uAddress, bVal);
2907 fUpdateMappings = true;
2908 }
2909 break;
2910
2911 case VBOX_PCI_STATUS: /* Status register, bits 0-7. */
2912 /* don't change read-only bits => actually all lower bits are read-only */
2913 bVal &= ~UINT8_C(0xff);
2914 /* status register, low part: clear bits by writing a '1' to the corresponding bit */
2915 pPciDev->abConfig[uAddress] &= ~bVal;
2916 break;
2917
2918 case VBOX_PCI_STATUS+1: /* Status register, bits 8-15. */
2919 /* don't change read-only bits */
2920 bVal &= ~UINT8_C(0x06);
2921 /* status register, high part: clear bits by writing a '1' to the corresponding bit */
2922 pPciDev->abConfig[uAddress] &= ~bVal;
2923 break;
2924
2925 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS +1: case VBOX_PCI_ROM_ADDRESS +2: case VBOX_PCI_ROM_ADDRESS +3:
2926 fRom = true;
2927 RT_FALL_THRU();
2928 case VBOX_PCI_BASE_ADDRESS_0: case VBOX_PCI_BASE_ADDRESS_0+1: case VBOX_PCI_BASE_ADDRESS_0+2: case VBOX_PCI_BASE_ADDRESS_0+3:
2929 case VBOX_PCI_BASE_ADDRESS_1: case VBOX_PCI_BASE_ADDRESS_1+1: case VBOX_PCI_BASE_ADDRESS_1+2: case VBOX_PCI_BASE_ADDRESS_1+3:
2930 case VBOX_PCI_BASE_ADDRESS_2: case VBOX_PCI_BASE_ADDRESS_2+1: case VBOX_PCI_BASE_ADDRESS_2+2: case VBOX_PCI_BASE_ADDRESS_2+3:
2931 case VBOX_PCI_BASE_ADDRESS_3: case VBOX_PCI_BASE_ADDRESS_3+1: case VBOX_PCI_BASE_ADDRESS_3+2: case VBOX_PCI_BASE_ADDRESS_3+3:
2932 case VBOX_PCI_BASE_ADDRESS_4: case VBOX_PCI_BASE_ADDRESS_4+1: case VBOX_PCI_BASE_ADDRESS_4+2: case VBOX_PCI_BASE_ADDRESS_4+3:
2933 case VBOX_PCI_BASE_ADDRESS_5: case VBOX_PCI_BASE_ADDRESS_5+1: case VBOX_PCI_BASE_ADDRESS_5+2: case VBOX_PCI_BASE_ADDRESS_5+3:
2934 /* We check that, as same PCI register numbers as BARs may mean different registers for bridges */
2935 if (!fP2PBridge)
2936 {
2937 uint32_t iRegion = fRom ? VBOX_PCI_ROM_SLOT : (uAddress - VBOX_PCI_BASE_ADDRESS_0) >> 2;
2938 devpciR3WriteBarByte(pPciDev, iRegion, uAddress & 0x3, bVal);
2939 fUpdateMappings = true;
2940 break;
2941 }
2942 if (uAddress < VBOX_PCI_BASE_ADDRESS_2 || uAddress > VBOX_PCI_BASE_ADDRESS_5+3)
2943 {
2944 /* PCI bridges have only BAR0, BAR1 and ROM */
2945 uint32_t iRegion = fRom ? VBOX_PCI_ROM_SLOT : (uAddress - VBOX_PCI_BASE_ADDRESS_0) >> 2;
2946 devpciR3WriteBarByte(pPciDev, iRegion, uAddress & 0x3, bVal);
2947 fUpdateMappings = true;
2948 break;
2949 }
2950 if ( uAddress == VBOX_PCI_IO_BASE
2951 || uAddress == VBOX_PCI_IO_LIMIT
2952 || uAddress == VBOX_PCI_MEMORY_BASE
2953 || uAddress == VBOX_PCI_MEMORY_LIMIT
2954 || uAddress == VBOX_PCI_PREF_MEMORY_BASE
2955 || uAddress == VBOX_PCI_PREF_MEMORY_LIMIT)
2956 {
2957 /* All bridge address decoders have the low 4 bits
2958 * as readonly, and all but the prefetchable ones
2959 * have the low 4 bits as 0 (the prefetchable have
2960 * it as 1 to show the 64-bit decoder support. */
2961 bVal &= 0xf0;
2962 if ( uAddress == VBOX_PCI_PREF_MEMORY_BASE
2963 || uAddress == VBOX_PCI_PREF_MEMORY_LIMIT)
2964 bVal |= 0x01;
2965 }
2966 /* (bridge config space which isn't a BAR) */
2967 RT_FALL_THRU();
2968 default:
2969 if (fWritable)
2970 /* safe, only needs to go to the config space array */
2971 PDMPciDevSetByte(pPciDev, uAddress, bVal);
2972 break;
2973 }
2974 uAddress++;
2975 u32Value >>= 8;
2976 }
2977
2978 /*
2979 * Update the region mappings if anything changed related to them (command, BARs, ROM).
2980 */
2981 if (fUpdateMappings)
2982 rcStrict = devpciR3UpdateMappings(pPciDev, fP2PBridge);
2983 }
2984 }
2985 else
2986 AssertMsgFailed(("Write after end of PCI config space: %#x LB %u\n", uAddress, cb));
2987
2988 return rcStrict;
2989}
2990
2991
2992/**
2993 * @interface_method_impl{PDMPCIBUSREGR3,pfnConfigWrite}
2994 */
2995DECLCALLBACK(VBOXSTRICTRC) devpciR3CommonConfigWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
2996 uint32_t uAddress, unsigned cb, uint32_t u32Value)
2997{
2998 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
2999 return devpciR3CommonConfigWriteWorker(pDevIns, pBusCC, pPciDev, uAddress, cb, u32Value);
3000}
3001
3002
3003/* -=-=-=-=-=- Debug Info Handlers -=-=-=-=-=- */
3004
3005/**
3006 * Indents an info line.
3007 * @param pHlp The info helper.
3008 * @param iIndentLvl The desired indentation level.
3009 */
3010static void devpciR3InfoIndent(PCDBGFINFOHLP pHlp, unsigned iIndentLvl)
3011{
3012 for (unsigned i = 0; i < iIndentLvl; i++)
3013 pHlp->pfnPrintf(pHlp, " ");
3014}
3015
3016static const char *devpciR3InInfoPciBusClassName(uint8_t iBaseClass)
3017{
3018 static const char *s_szBaseClass[] =
3019 {
3020 /* 00h */ "unknown",
3021 /* 01h */ "mass storage controller",
3022 /* 02h */ "network controller",
3023 /* 03h */ "display controller",
3024 /* 04h */ "multimedia controller",
3025 /* 05h */ "memory controller",
3026 /* 06h */ "bridge device",
3027 /* 07h */ "simple communication controllers",
3028 /* 08h */ "base system peripherals",
3029 /* 09h */ "input devices",
3030 /* 0Ah */ "docking stations",
3031 /* 0Bh */ "processors",
3032 /* 0Ch */ "serial bus controllers",
3033 /* 0Dh */ "wireless controller",
3034 /* 0Eh */ "intelligent I/O controllers",
3035 /* 0Fh */ "satellite communication controllers",
3036 /* 10h */ "encryption/decryption controllers",
3037 /* 11h */ "data acquisition and signal processing controllers"
3038 };
3039 if (iBaseClass < RT_ELEMENTS(s_szBaseClass))
3040 return s_szBaseClass[iBaseClass];
3041 if (iBaseClass < 0xFF)
3042 return "reserved";
3043 return "device does not fit in any defined classes";
3044}
3045
3046
3047/**
3048 * Recursive worker for devpciR3InfoPci.
3049 *
3050 * @param pBus The bus to show info for.
3051 * @param pHlp The info helpers.
3052 * @param iIndentLvl The indentation level.
3053 * @param fRegisters Whether to show device registers or not.
3054 */
3055static void devpciR3InfoPciBus(PDEVPCIBUS pBus, PCDBGFINFOHLP pHlp, unsigned iIndentLvl, bool fRegisters)
3056{
3057 /* This has to use the callbacks for accuracy reasons. Otherwise it can get
3058 * confusing in the passthrough case or when the callbacks for some device
3059 * are doing something non-trivial (like implementing an indirect
3060 * passthrough approach), because then the abConfig array is an imprecise
3061 * cache needed for efficiency (so that certain reads can be done from
3062 * R0/RC), but far from authoritative or what the guest would see. */
3063
3064 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
3065 {
3066 PPDMPCIDEV pPciDev = pBus->apDevices[uDevFn];
3067 if (pPciDev != NULL)
3068 {
3069 devpciR3InfoIndent(pHlp, iIndentLvl);
3070
3071 /*
3072 * For passthrough devices MSI/MSI-X mostly reflects the way interrupts delivered to the guest,
3073 * as host driver handles real devices interrupts.
3074 */
3075 pHlp->pfnPrintf(pHlp, "%02x:%02x.%d %s%s: %04x-%04x %s%s%s",
3076 pBus->iBus, (uDevFn >> 3) & 0xff, uDevFn & 0x7,
3077 pPciDev->pszNameR3,
3078 pciDevIsPassthrough(pPciDev) ? " (PASSTHROUGH)" : "",
3079 devpciR3GetWord(pPciDev, VBOX_PCI_VENDOR_ID), devpciR3GetWord(pPciDev, VBOX_PCI_DEVICE_ID),
3080 pBus->fTypeIch9 ? "ICH9" : pBus->fTypePiix3 ? "PIIX3" : "?type?",
3081 pciDevIsMsiCapable(pPciDev) ? " MSI" : "",
3082 pciDevIsMsixCapable(pPciDev) ? " MSI-X" : ""
3083 );
3084 if (devpciR3GetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN) != 0)
3085 {
3086 pHlp->pfnPrintf(pHlp, " IRQ%d", devpciR3GetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE));
3087 pHlp->pfnPrintf(pHlp, " (INTA#->IRQ%d)", 0x10 + ich9pciSlot2ApicIrq(uDevFn >> 3, 0));
3088 }
3089 pHlp->pfnPrintf(pHlp, "\n");
3090 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3091 uint8_t uClassBase = devpciR3GetByte(pPciDev, VBOX_PCI_CLASS_BASE);
3092 uint8_t uClassSub = devpciR3GetByte(pPciDev, VBOX_PCI_CLASS_SUB);
3093 pHlp->pfnPrintf(pHlp, "Class base/sub: %02x%02x (%s)\n",
3094 uClassBase, uClassSub, devpciR3InInfoPciBusClassName(uClassBase));
3095
3096 if (pciDevIsMsiCapable(pPciDev) || pciDevIsMsixCapable(pPciDev))
3097 {
3098 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3099
3100 if (pciDevIsMsiCapable(pPciDev))
3101 pHlp->pfnPrintf(pHlp, "MSI: %s ", MsiIsEnabled(pPciDev) ? "on" : "off");
3102
3103 if (pciDevIsMsixCapable(pPciDev))
3104 pHlp->pfnPrintf(pHlp, "MSI-X: %s ", MsixIsEnabled(pPciDev) ? "on" : "off");
3105
3106 pHlp->pfnPrintf(pHlp, "\n");
3107 }
3108
3109 for (unsigned iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
3110 {
3111 PCIIOREGION const *pRegion = &pPciDev->Int.s.aIORegions[iRegion];
3112 uint64_t const cbRegion = pRegion->size;
3113
3114 if (cbRegion == 0)
3115 continue;
3116
3117 uint32_t uAddr = devpciR3GetDWord(pPciDev, devpciGetRegionReg(iRegion));
3118 const char * pszDesc;
3119 char szDescBuf[128];
3120
3121 bool f64Bit = (pRegion->type & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
3122 == PCI_ADDRESS_SPACE_BAR64;
3123 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
3124 {
3125 pszDesc = "IO";
3126 uAddr &= ~0x3;
3127 }
3128 else
3129 {
3130 RTStrPrintf(szDescBuf, sizeof(szDescBuf), "MMIO%s%s",
3131 f64Bit ? "64" : "32",
3132 pRegion->type & PCI_ADDRESS_SPACE_MEM_PREFETCH ? " PREFETCH" : "");
3133 pszDesc = szDescBuf;
3134 uAddr &= ~0xf;
3135 }
3136
3137 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3138 pHlp->pfnPrintf(pHlp, "%s region #%u: ", pszDesc, iRegion);
3139 if (f64Bit)
3140 {
3141 uint32_t u32High = devpciR3GetDWord(pPciDev, devpciGetRegionReg(iRegion+1));
3142 uint64_t u64Addr = RT_MAKE_U64(uAddr, u32High);
3143 pHlp->pfnPrintf(pHlp, "%RX64..%RX64\n", u64Addr, u64Addr + cbRegion - 1);
3144 iRegion++;
3145 }
3146 else
3147 pHlp->pfnPrintf(pHlp, "%x..%x\n", uAddr, uAddr + (uint32_t)cbRegion - 1);
3148 }
3149
3150 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3151 uint16_t iCmd = devpciR3GetWord(pPciDev, VBOX_PCI_COMMAND);
3152 uint16_t iStatus = devpciR3GetWord(pPciDev, VBOX_PCI_STATUS);
3153 pHlp->pfnPrintf(pHlp, "Command: %04x, Status: %04x\n", iCmd, iStatus);
3154 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3155 pHlp->pfnPrintf(pHlp, "Bus master: %s\n", iCmd & VBOX_PCI_COMMAND_MASTER ? "Yes" : "No");
3156 if (iCmd != PDMPciDevGetCommand(pPciDev))
3157 {
3158 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3159 pHlp->pfnPrintf(pHlp, "CACHE INCONSISTENCY: Command: %04x\n", PDMPciDevGetCommand(pPciDev));
3160 }
3161
3162 if (fRegisters)
3163 {
3164 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3165 pHlp->pfnPrintf(pHlp, "PCI registers:\n");
3166 for (unsigned iReg = 0; iReg < 0x100; )
3167 {
3168 unsigned iPerLine = 0x10;
3169 Assert(0x100 % iPerLine == 0);
3170 devpciR3InfoIndent(pHlp, iIndentLvl + 3);
3171
3172 while (iPerLine-- > 0)
3173 pHlp->pfnPrintf(pHlp, "%02x ", devpciR3GetByte(pPciDev, iReg++));
3174 pHlp->pfnPrintf(pHlp, "\n");
3175 }
3176 }
3177 }
3178 }
3179
3180 if (pBus->cBridges > 0)
3181 {
3182 devpciR3InfoIndent(pHlp, iIndentLvl);
3183 pHlp->pfnPrintf(pHlp, "Registered %d bridges, subordinate buses info follows\n", pBus->cBridges);
3184 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
3185 {
3186 PPDMDEVINS pDevInsSub = pBus->papBridgesR3[iBridge]->Int.s.CTX_SUFF(pDevIns);
3187 PPDMPCIDEV pPciDevSub = pDevInsSub->apPciDevs[0];
3188 PDEVPCIBUS pBusSub = PDMINS_2_DATA(pDevInsSub, PDEVPCIBUS);
3189 uint8_t uPrimary = devpciR3GetByte(pPciDevSub, VBOX_PCI_PRIMARY_BUS);
3190 uint8_t uSecondary = devpciR3GetByte(pPciDevSub, VBOX_PCI_SECONDARY_BUS);
3191 uint8_t uSubordinate = devpciR3GetByte(pPciDevSub, VBOX_PCI_SUBORDINATE_BUS);
3192 devpciR3InfoIndent(pHlp, iIndentLvl);
3193 pHlp->pfnPrintf(pHlp, "%02x:%02x.%d: bridge topology: primary=%d secondary=%d subordinate=%d\n",
3194 uPrimary, pPciDevSub->uDevFn >> 3, pPciDevSub->uDevFn & 7,
3195 uPrimary, uSecondary, uSubordinate);
3196 if ( uPrimary != PDMPciDevGetByte(pPciDevSub, VBOX_PCI_PRIMARY_BUS)
3197 || uSecondary != PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SECONDARY_BUS)
3198 || uSubordinate != PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SUBORDINATE_BUS))
3199 {
3200 devpciR3InfoIndent(pHlp, iIndentLvl);
3201 pHlp->pfnPrintf(pHlp, "CACHE INCONSISTENCY: primary=%d secondary=%d subordinate=%d\n",
3202 PDMPciDevGetByte(pPciDevSub, VBOX_PCI_PRIMARY_BUS),
3203 PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SECONDARY_BUS),
3204 PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SUBORDINATE_BUS));
3205 }
3206 devpciR3InfoIndent(pHlp, iIndentLvl);
3207 pHlp->pfnPrintf(pHlp, "behind bridge: ");
3208 uint8_t uIoBase = devpciR3GetByte(pPciDevSub, VBOX_PCI_IO_BASE);
3209 uint8_t uIoLimit = devpciR3GetByte(pPciDevSub, VBOX_PCI_IO_LIMIT);
3210 pHlp->pfnPrintf(pHlp, "I/O %#06x..%#06x",
3211 (uIoBase & 0xf0) << 8,
3212 (uIoLimit & 0xf0) << 8 | 0xfff);
3213 if (uIoBase > uIoLimit)
3214 pHlp->pfnPrintf(pHlp, " (IGNORED)");
3215 pHlp->pfnPrintf(pHlp, "\n");
3216 devpciR3InfoIndent(pHlp, iIndentLvl);
3217 pHlp->pfnPrintf(pHlp, "behind bridge: ");
3218 uint32_t uMemoryBase = devpciR3GetWord(pPciDevSub, VBOX_PCI_MEMORY_BASE);
3219 uint32_t uMemoryLimit = devpciR3GetWord(pPciDevSub, VBOX_PCI_MEMORY_LIMIT);
3220 pHlp->pfnPrintf(pHlp, "memory %#010x..%#010x",
3221 (uMemoryBase & 0xfff0) << 16,
3222 (uMemoryLimit & 0xfff0) << 16 | 0xfffff);
3223 if (uMemoryBase > uMemoryLimit)
3224 pHlp->pfnPrintf(pHlp, " (IGNORED)");
3225 pHlp->pfnPrintf(pHlp, "\n");
3226 devpciR3InfoIndent(pHlp, iIndentLvl);
3227 pHlp->pfnPrintf(pHlp, "behind bridge: ");
3228 uint32_t uPrefMemoryRegBase = devpciR3GetWord(pPciDevSub, VBOX_PCI_PREF_MEMORY_BASE);
3229 uint32_t uPrefMemoryRegLimit = devpciR3GetWord(pPciDevSub, VBOX_PCI_PREF_MEMORY_LIMIT);
3230 uint64_t uPrefMemoryBase = (uPrefMemoryRegBase & 0xfff0) << 16;
3231 uint64_t uPrefMemoryLimit = (uPrefMemoryRegLimit & 0xfff0) << 16 | 0xfffff;
3232 if ( (uPrefMemoryRegBase & 0xf) == 1
3233 && (uPrefMemoryRegLimit & 0xf) == 1)
3234 {
3235 uPrefMemoryBase |= (uint64_t)devpciR3GetDWord(pPciDevSub, VBOX_PCI_PREF_BASE_UPPER32) << 32;
3236 uPrefMemoryLimit |= (uint64_t)devpciR3GetDWord(pPciDevSub, VBOX_PCI_PREF_LIMIT_UPPER32) << 32;
3237 pHlp->pfnPrintf(pHlp, "64-bit ");
3238 }
3239 else
3240 pHlp->pfnPrintf(pHlp, "32-bit ");
3241 pHlp->pfnPrintf(pHlp, "prefetch memory %#018llx..%#018llx", uPrefMemoryBase, uPrefMemoryLimit);
3242 if (uPrefMemoryBase > uPrefMemoryLimit)
3243 pHlp->pfnPrintf(pHlp, " (IGNORED)");
3244 pHlp->pfnPrintf(pHlp, "\n");
3245 devpciR3InfoPciBus(pBusSub, pHlp, iIndentLvl + 1, fRegisters);
3246 }
3247 }
3248}
3249
3250
3251/**
3252 * @callback_method_impl{FNDBGFHANDLERDEV, 'pci'}
3253 */
3254DECLCALLBACK(void) devpciR3InfoPci(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3255{
3256 PDEVPCIBUS pBus = DEVINS_2_DEVPCIBUS(pDevIns);
3257
3258 if (pszArgs == NULL || !*pszArgs || !strcmp(pszArgs, "basic"))
3259 devpciR3InfoPciBus(pBus, pHlp, 0 /*iIndentLvl*/, false /*fRegisters*/);
3260 else if (!strcmp(pszArgs, "verbose"))
3261 devpciR3InfoPciBus(pBus, pHlp, 0 /*iIndentLvl*/, true /*fRegisters*/);
3262 else
3263 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'verbose'.\n");
3264}
3265
3266
3267/**
3268 * @callback_method_impl{FNDBGFHANDLERDEV, 'pciirq'}
3269 */
3270DECLCALLBACK(void) devpciR3InfoPciIrq(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3271{
3272 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3273 NOREF(pszArgs);
3274
3275 pHlp->pfnPrintf(pHlp, "PCI I/O APIC IRQ levels:\n");
3276 for (int i = 0; i < DEVPCI_APIC_IRQ_PINS; ++i)
3277 pHlp->pfnPrintf(pHlp, " IRQ%02d: %u\n", 0x10 + i, pPciRoot->auPciApicIrqLevels[i]);
3278}
3279
3280
3281/**
3282 * @interface_method_impl{PDMDEVREG,pfnConstruct}
3283 */
3284static DECLCALLBACK(int) ich9pciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
3285{
3286 RT_NOREF1(iInstance);
3287 Assert(iInstance == 0);
3288 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3289
3290 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3291 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3292 PDEVPCIBUS pBus = &pPciRoot->PciBus;
3293 Assert(ASMMemIsZero(pPciRoot, sizeof(*pPciRoot))); /* code used to memset it for some funny reason. just temp insurance. */
3294
3295 /*
3296 * Validate and read configuration.
3297 */
3298 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IOAPIC|McfgBase|McfgLength", "");
3299
3300 /* query whether we got an IOAPIC */
3301 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &pPciRoot->fUseIoApic, false /** @todo default to true? */);
3302 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to query boolean value \"IOAPIC\"")));
3303
3304 if (!pPciRoot->fUseIoApic)
3305 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Must use IO-APIC with ICH9 chipset"));
3306
3307 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pPciRoot->u64PciConfigMMioAddress, 0);
3308 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"McfgBase\"")));
3309
3310 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pPciRoot->u64PciConfigMMioLength, 0);
3311 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"McfgLength\"")));
3312
3313 Log(("PCI: fUseIoApic=%RTbool McfgBase=%#RX64 McfgLength=%#RX64 fR0Enabled=%RTbool fRCEnabled=%RTbool\n", pPciRoot->fUseIoApic,
3314 pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength, pDevIns->fR0Enabled, pDevIns->fRCEnabled));
3315
3316 /*
3317 * Init data.
3318 */
3319 /* And fill values */
3320 pBusCC->pDevInsR3 = pDevIns;
3321 pPciRoot->hIoPortAddress = NIL_IOMIOPORTHANDLE;
3322 pPciRoot->hIoPortData = NIL_IOMIOPORTHANDLE;
3323 pPciRoot->hIoPortMagic = NIL_IOMIOPORTHANDLE;
3324 pPciRoot->hMmioMcfg = NIL_IOMMMIOHANDLE;
3325 pPciRoot->PciBus.fTypePiix3 = false;
3326 pPciRoot->PciBus.fTypeIch9 = true;
3327 pPciRoot->PciBus.fPureBridge = false;
3328 pPciRoot->PciBus.papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pPciRoot->PciBus.apDevices));
3329 AssertLogRelReturn(pPciRoot->PciBus.papBridgesR3, VERR_NO_MEMORY);
3330
3331 /*
3332 * Disable default device locking.
3333 */
3334 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3335 AssertRCReturn(rc, rc);
3336
3337 /*
3338 * Register bus
3339 */
3340 PDMPCIBUSREGCC PciBusReg;
3341 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3342 PciBusReg.pfnRegisterR3 = devpciR3CommonRegisterDevice;
3343 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
3344 PciBusReg.pfnIORegionRegisterR3 = devpciR3CommonIORegionRegister;
3345 PciBusReg.pfnInterceptConfigAccesses = devpciR3CommonInterceptConfigAccesses;
3346 PciBusReg.pfnConfigRead = devpciR3CommonConfigRead;
3347 PciBusReg.pfnConfigWrite = devpciR3CommonConfigWrite;
3348 PciBusReg.pfnSetIrqR3 = ich9pciSetIrq;
3349 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3350 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBusCC->pPciHlpR3, &pBus->iBus);
3351 if (RT_FAILURE(rc))
3352 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as a PCI Bus"));
3353 Assert(pBus->iBus == 0);
3354 if (pBusCC->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
3355 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
3356 N_("PCI helper version mismatch; got %#x expected %#x"),
3357 pBusCC->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
3358
3359 /*
3360 * Fill in PCI configs and add them to the bus.
3361 */
3362 /** @todo Disabled for now because this causes error messages with Linux guests.
3363 * The guest loads the x38_edac device which tries to map a memory region
3364 * using an address given at place 0x48 - 0x4f in the PCI config space.
3365 * This fails. because we don't register such a region.
3366 */
3367#if 0
3368 /* Host bridge device */
3369 PDMPciDevSetVendorId( &pBus->PciDev, 0x8086); /* Intel */
3370 PDMPciDevSetDeviceId( &pBus->PciDev, 0x29e0); /* Desktop */
3371 PDMPciDevSetRevisionId(&pBus->PciDev, 0x01); /* rev. 01 */
3372 PDMPciDevSetClassBase( &pBus->PciDev, 0x06); /* bridge */
3373 PDMPciDevSetClassSub( &pBus->PciDev, 0x00); /* Host/PCI bridge */
3374 PDMPciDevSetClassProg( &pBus->PciDev, 0x00); /* Host/PCI bridge */
3375 PDMPciDevSetHeaderType(&pBus->PciDev, 0x00); /* bridge */
3376 PDMPciDevSetWord(&pBus->PciDev, VBOX_PCI_SEC_STATUS, 0x0280); /* secondary status */
3377
3378 pBus->PciDev.pDevIns = pDevIns;
3379 /* We register Host<->PCI controller on the bus */
3380 ich9pciRegisterInternal(pBus, 0, &pBus->PciDev, "dram");
3381#endif
3382
3383 /*
3384 * Register I/O ports.
3385 */
3386 static const IOMIOPORTDESC s_aAddrDesc[] = { { "PCI address", "PCI address", NULL, NULL }, { NULL, NULL, NULL, NULL } };
3387 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x0cf8, 1, ich9pciIOPortAddressWrite, ich9pciIOPortAddressRead,
3388 "ICH9 (PCI)", s_aAddrDesc, &pPciRoot->hIoPortAddress);
3389 AssertLogRelRCReturn(rc, rc);
3390
3391 static const IOMIOPORTDESC s_aDataDesc[] = { { "PCI data", "PCI data", NULL, NULL }, { NULL, NULL, NULL, NULL } };
3392 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x0cfc, 4, ich9pciIOPortDataWrite, ich9pciIOPortDataRead,
3393 "ICH9 (PCI)", s_aDataDesc, &pPciRoot->hIoPortData);
3394 AssertLogRelRCReturn(rc, rc);
3395
3396 static const IOMIOPORTDESC s_aMagicDesc[] = { { "PCI magic", NULL, NULL, NULL }, { NULL, NULL, NULL, NULL } };
3397 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x0410, 1, ich9pciR3IOPortMagicPCIWrite, ich9pciR3IOPortMagicPCIRead,
3398 "ICH9 (Fake PCI BIOS trigger)", s_aMagicDesc, &pPciRoot->hIoPortMagic);
3399 AssertLogRelRCReturn(rc, rc);
3400
3401 /*
3402 * MMIO handlers.
3403 */
3404 if (pPciRoot->u64PciConfigMMioAddress != 0)
3405 {
3406 rc = PDMDevHlpMmioCreateAndMap(pDevIns, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength,
3407 ich9pciMcfgMMIOWrite, ich9pciMcfgMMIORead,
3408 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
3409 "MCFG ranges", &pPciRoot->hMmioMcfg);
3410 AssertMsgRCReturn(rc, ("rc=%Rrc %#RX64/%#RX64\n", rc, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength), rc);
3411 }
3412
3413 /*
3414 * Saved state and info handlers.
3415 */
3416 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION,
3417 sizeof(*pBus) + 16*128, "pgm",
3418 NULL, NULL, NULL,
3419 NULL, ich9pciR3SaveExec, NULL,
3420 NULL, ich9pciR3LoadExec, NULL);
3421 AssertRCReturn(rc, rc);
3422
3423 /** @todo other chipset devices shall be registered too */
3424
3425 PDMDevHlpDBGFInfoRegister(pDevIns, "pci",
3426 "Display PCI bus status. Recognizes 'basic' or 'verbose' as arguments, defaults to 'basic'.",
3427 devpciR3InfoPci);
3428 PDMDevHlpDBGFInfoRegister(pDevIns, "pciirq", "Display PCI IRQ state. (no arguments)", devpciR3InfoPciIrq);
3429
3430 return VINF_SUCCESS;
3431}
3432
3433
3434/**
3435 * @interface_method_impl{PDMDEVREG,pfnDestruct}
3436 */
3437static DECLCALLBACK(int) ich9pciR3Destruct(PPDMDEVINS pDevIns)
3438{
3439 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3440 if (pPciRoot->PciBus.papBridgesR3)
3441 {
3442 PDMDevHlpMMHeapFree(pDevIns, pPciRoot->PciBus.papBridgesR3);
3443 pPciRoot->PciBus.papBridgesR3 = NULL;
3444 }
3445 return VINF_SUCCESS;
3446}
3447
3448
3449/**
3450 * @param pDevIns The PCI bus device instance.
3451 * @param pDev The PCI device to reset.
3452 */
3453void devpciR3ResetDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pDev)
3454{
3455 /* Clear regions */
3456 for (int iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
3457 {
3458 PCIIOREGION *pRegion = &pDev->Int.s.aIORegions[iRegion];
3459 if (pRegion->size == 0)
3460 continue;
3461 bool const f64Bit = (pRegion->type & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
3462 == PCI_ADDRESS_SPACE_BAR64;
3463
3464 devpciR3UnmapRegion(pDev, iRegion);
3465
3466 if (f64Bit)
3467 iRegion++;
3468 }
3469
3470 if (pciDevIsPassthrough(pDev))
3471 {
3472 // no reset handler - we can do what we need in PDM reset handler
3473 /// @todo is it correct?
3474 }
3475 else
3476 {
3477 devpciR3SetWord(pDevIns, pDev, VBOX_PCI_COMMAND,
3478 devpciR3GetWord(pDev, VBOX_PCI_COMMAND)
3479 & ~(VBOX_PCI_COMMAND_IO | VBOX_PCI_COMMAND_MEMORY |
3480 VBOX_PCI_COMMAND_MASTER | VBOX_PCI_COMMAND_SPECIAL |
3481 VBOX_PCI_COMMAND_PARITY | VBOX_PCI_COMMAND_SERR |
3482 VBOX_PCI_COMMAND_FAST_BACK | VBOX_PCI_COMMAND_INTX_DISABLE));
3483
3484 /* Bridge device reset handlers processed later */
3485 if (!pciDevIsPci2PciBridge(pDev))
3486 {
3487 devpciR3SetByte(pDevIns, pDev, VBOX_PCI_CACHE_LINE_SIZE, 0x0);
3488 devpciR3SetByte(pDevIns, pDev, VBOX_PCI_INTERRUPT_LINE, 0x0);
3489 }
3490
3491 /* Reset MSI message control. */
3492 if (pciDevIsMsiCapable(pDev))
3493 devpciR3SetWord(pDevIns, pDev, pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL,
3494 devpciR3GetWord(pDev, pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL) & 0xff8e);
3495
3496 /* Reset MSI-X message control. */
3497 if (pciDevIsMsixCapable(pDev))
3498 devpciR3SetWord(pDevIns, pDev, pDev->Int.s.u8MsixCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL,
3499 devpciR3GetWord(pDev, pDev->Int.s.u8MsixCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL) & 0x3fff);
3500 }
3501}
3502
3503/**
3504 * Returns the PCI express encoding for the given PCI Express Device/Port type string.
3505 *
3506 * @returns PCI express encoding.
3507 * @param pszExpressPortType The string identifier for the port/device type.
3508 */
3509static uint8_t ich9pcibridgeR3GetExpressPortTypeFromString(const char *pszExpressPortType)
3510{
3511 if (!RTStrCmp(pszExpressPortType, "EndPtDev"))
3512 return VBOX_PCI_EXP_TYPE_ENDPOINT;
3513 if (!RTStrCmp(pszExpressPortType, "LegEndPtDev"))
3514 return VBOX_PCI_EXP_TYPE_LEG_END;
3515 if (!RTStrCmp(pszExpressPortType, "RootCmplxRootPort"))
3516 return VBOX_PCI_EXP_TYPE_ROOT_PORT;
3517 if (!RTStrCmp(pszExpressPortType, "ExpressSwUpstream"))
3518 return VBOX_PCI_EXP_TYPE_UPSTREAM;
3519 if (!RTStrCmp(pszExpressPortType, "ExpressSwDownstream"))
3520 return VBOX_PCI_EXP_TYPE_DOWNSTREAM;
3521 if (!RTStrCmp(pszExpressPortType, "Express2PciBridge"))
3522 return VBOX_PCI_EXP_TYPE_PCI_BRIDGE;
3523 if (!RTStrCmp(pszExpressPortType, "Pci2ExpressBridge"))
3524 return VBOX_PCI_EXP_TYPE_PCIE_BRIDGE;
3525 if (!RTStrCmp(pszExpressPortType, "RootCmplxIntEp"))
3526 return VBOX_PCI_EXP_TYPE_ROOT_INT_EP;
3527 if (!RTStrCmp(pszExpressPortType, "RootCmplxEc"))
3528 return VBOX_PCI_EXP_TYPE_ROOT_EC;
3529
3530 AssertLogRelMsgFailedReturn(("Unknown express port type specified"), VBOX_PCI_EXP_TYPE_ROOT_INT_EP);
3531}
3532
3533/**
3534 * Recursive worker for ich9pciReset.
3535 *
3536 * @param pDevIns ICH9 bridge (root or PCI-to-PCI) instance.
3537 */
3538static void ich9pciResetBridge(PPDMDEVINS pDevIns)
3539{
3540 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3541
3542 /* PCI-specific reset for each device. */
3543 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
3544 {
3545 if (pBus->apDevices[uDevFn])
3546 devpciR3ResetDevice(pDevIns, pBus->apDevices[uDevFn]);
3547 }
3548
3549 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
3550 {
3551 if (pBus->papBridgesR3[iBridge])
3552 ich9pciResetBridge(pBus->papBridgesR3[iBridge]->Int.s.CTX_SUFF(pDevIns));
3553 }
3554
3555 /* Reset topology config for non-root bridge. Last thing to do, otherwise
3556 * the secondary and subordinate are instantly unreachable. */
3557 if (pBus->iBus != 0)
3558 {
3559 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
3560
3561 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_PRIMARY_BUS, 0);
3562 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_SECONDARY_BUS, 0);
3563 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_SUBORDINATE_BUS, 0);
3564 /* Not resetting the address decoders of the bridge to 0, since the
3565 * PCI-to-PCI Bridge spec says that there is no default value. */
3566 }
3567}
3568
3569
3570/**
3571 * @interface_method_impl{PDMDEVREG,pfnReset}
3572 */
3573static DECLCALLBACK(void) ich9pciReset(PPDMDEVINS pDevIns)
3574{
3575 /* Reset everything under the root bridge. */
3576 ich9pciResetBridge(pDevIns);
3577}
3578
3579
3580/**
3581 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
3582 */
3583static DECLCALLBACK(void *) ich9pcibridgeQueryInterface(PPDMIBASE pInterface, const char *pszIID)
3584{
3585 PPDMDEVINS pDevIns = RT_FROM_MEMBER(pInterface, PDMDEVINS, IBase);
3586 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevIns->IBase);
3587
3588 /* HACK ALERT! Special access to the PDMPCIDEV structure of an ich9pcibridge
3589 instance (see PDMIICH9BRIDGEPDMPCIDEV_IID for details). */
3590 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIICH9BRIDGEPDMPCIDEV, pDevIns->apPciDevs[0]);
3591 return NULL;
3592}
3593
3594
3595/**
3596 * @interface_method_impl{PDMDEVREG,pfnDestruct}
3597 */
3598static DECLCALLBACK(int) ich9pcibridgeR3Destruct(PPDMDEVINS pDevIns)
3599{
3600 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3601 if (pBus->papBridgesR3)
3602 {
3603 PDMDevHlpMMHeapFree(pDevIns, pBus->papBridgesR3);
3604 pBus->papBridgesR3 = NULL;
3605 }
3606 return VINF_SUCCESS;
3607}
3608
3609
3610/**
3611 * @interface_method_impl{PDMDEVREG,pfnConstruct}
3612 */
3613static DECLCALLBACK(int) ich9pcibridgeR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
3614{
3615 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3616
3617 /*
3618 * Validate and read configuration.
3619 */
3620 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "ExpressEnabled|ExpressPortType", "");
3621
3622 /* check if we're supposed to implement a PCIe bridge. */
3623 bool fExpress;
3624 int rc = CFGMR3QueryBoolDef(pCfg, "ExpressEnabled", &fExpress, false);
3625 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to query boolean value \"ExpressEnabled\"")));
3626
3627 char szExpressPortType[80];
3628 rc = CFGMR3QueryStringDef(pCfg, "ExpressPortType", szExpressPortType, sizeof(szExpressPortType), "RootCmplxIntEp");
3629 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: failed to read \"ExpressPortType\" as string")));
3630
3631 uint8_t const uExpressPortType = ich9pcibridgeR3GetExpressPortTypeFromString(szExpressPortType);
3632 Log(("PCI/bridge#%u: fR0Enabled=%RTbool fRCEnabled=%RTbool fExpress=%RTbool uExpressPortType=%u (%s)\n",
3633 iInstance, pDevIns->fR0Enabled, pDevIns->fRCEnabled, fExpress, uExpressPortType, szExpressPortType));
3634
3635 /*
3636 * Init data and register the PCI bus.
3637 */
3638 pDevIns->IBase.pfnQueryInterface = ich9pcibridgeQueryInterface;
3639
3640 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3641 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3642
3643 pBus->fTypePiix3 = false;
3644 pBus->fTypeIch9 = true;
3645 pBus->fPureBridge = true;
3646 pBusCC->pDevInsR3 = pDevIns;
3647 pBus->papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pBus->apDevices));
3648 AssertLogRelReturn(pBus->papBridgesR3, VERR_NO_MEMORY);
3649
3650 PDMPCIBUSREGCC PciBusReg;
3651 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3652 PciBusReg.pfnRegisterR3 = devpcibridgeR3CommonRegisterDevice;
3653 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
3654 PciBusReg.pfnIORegionRegisterR3 = devpciR3CommonIORegionRegister;
3655 PciBusReg.pfnInterceptConfigAccesses = devpciR3CommonInterceptConfigAccesses;
3656 PciBusReg.pfnConfigWrite = devpciR3CommonConfigWrite;
3657 PciBusReg.pfnConfigRead = devpciR3CommonConfigRead;
3658 PciBusReg.pfnSetIrqR3 = ich9pcibridgeSetIrq;
3659 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3660 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBusCC->pPciHlpR3, &pBus->iBus);
3661 if (RT_FAILURE(rc))
3662 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as a PCI Bus"));
3663 Assert(pBus->iBus == (uint32_t)iInstance + 1); /* Can be removed when adding support for multiple bridge implementations. */
3664 if (pBusCC->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
3665 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
3666 N_("PCI helper version mismatch; got %#x expected %#x"),
3667 pBusCC->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
3668
3669 LogRel(("PCI: Registered bridge instance #%u as PDM bus no %u.\n", iInstance, pBus->iBus));
3670
3671
3672 /* Disable default device locking. */
3673 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3674 AssertRCReturn(rc, rc);
3675
3676 /*
3677 * Fill in PCI configs and add them to the bus.
3678 */
3679 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
3680 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
3681
3682 PDMPciDevSetVendorId( pPciDev, 0x8086); /* Intel */
3683 if (fExpress)
3684 {
3685 PDMPciDevSetDeviceId(pPciDev, 0x29e1); /* 82X38/X48 Express Host-Primary PCI Express Bridge. */
3686 PDMPciDevSetRevisionId(pPciDev, 0x01);
3687 }
3688 else
3689 {
3690 PDMPciDevSetDeviceId(pPciDev, 0x2448); /* 82801 Mobile PCI bridge. */
3691 PDMPciDevSetRevisionId(pPciDev, 0xf2);
3692 }
3693 PDMPciDevSetClassSub( pPciDev, 0x04); /* pci2pci */
3694 PDMPciDevSetClassBase( pPciDev, 0x06); /* PCI_bridge */
3695 if (fExpress)
3696 PDMPciDevSetClassProg(pPciDev, 0x00); /* Normal decoding. */
3697 else
3698 PDMPciDevSetClassProg(pPciDev, 0x01); /* Supports subtractive decoding. */
3699 PDMPciDevSetHeaderType(pPciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
3700 if (fExpress)
3701 {
3702 PDMPciDevSetCommand(pPciDev, VBOX_PCI_COMMAND_SERR);
3703 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST); /* Has capabilities. */
3704 PDMPciDevSetByte(pPciDev, VBOX_PCI_CACHE_LINE_SIZE, 8); /* 32 bytes */
3705 /* PCI Express */
3706 PDMPciDevSetByte(pPciDev, 0xa0 + 0, VBOX_PCI_CAP_ID_EXP); /* PCI_Express */
3707 PDMPciDevSetByte(pPciDev, 0xa0 + 1, 0); /* next */
3708 PDMPciDevSetWord(pPciDev, 0xa0 + 2,
3709 /* version */ 0x2
3710 | (uExpressPortType << 4));
3711 PDMPciDevSetDWord(pPciDev, 0xa0 + 4, VBOX_PCI_EXP_DEVCAP_RBE); /* Device capabilities. */
3712 PDMPciDevSetWord(pPciDev, 0xa0 + 8, 0x0000); /* Device control. */
3713 PDMPciDevSetWord(pPciDev, 0xa0 + 10, 0x0000); /* Device status. */
3714 PDMPciDevSetDWord(pPciDev, 0xa0 + 12,
3715 /* Max Link Speed */ 2
3716 | /* Maximum Link Width */ (16 << 4)
3717 | /* Active State Power Management (ASPM) Sopport */ (0 << 10)
3718 | VBOX_PCI_EXP_LNKCAP_LBNC
3719 | /* Port Number */ ((2 + iInstance) << 24)); /* Link capabilities. */
3720 PDMPciDevSetWord(pPciDev, 0xa0 + 16, VBOX_PCI_EXP_LNKCTL_CLOCK); /* Link control. */
3721 PDMPciDevSetWord(pPciDev, 0xa0 + 18,
3722 /* Current Link Speed */ 2
3723 | /* Negotiated Link Width */ (16 << 4)
3724 | VBOX_PCI_EXP_LNKSTA_SL_CLK); /* Link status. */
3725 PDMPciDevSetDWord(pPciDev, 0xa0 + 20,
3726 /* Slot Power Limit Value */ (75 << 7)
3727 | /* Physical Slot Number */ (0 << 19)); /* Slot capabilities. */
3728 PDMPciDevSetWord(pPciDev, 0xa0 + 24, 0x0000); /* Slot control. */
3729 PDMPciDevSetWord(pPciDev, 0xa0 + 26, 0x0000); /* Slot status. */
3730 PDMPciDevSetWord(pPciDev, 0xa0 + 28, 0x0000); /* Root control. */
3731 PDMPciDevSetWord(pPciDev, 0xa0 + 30, 0x0000); /* Root capabilities. */
3732 PDMPciDevSetDWord(pPciDev, 0xa0 + 32, 0x00000000); /* Root status. */
3733 PDMPciDevSetDWord(pPciDev, 0xa0 + 36, 0x00000000); /* Device capabilities 2. */
3734 PDMPciDevSetWord(pPciDev, 0xa0 + 40, 0x0000); /* Device control 2. */
3735 PDMPciDevSetWord(pPciDev, 0xa0 + 42, 0x0000); /* Device status 2. */
3736 PDMPciDevSetDWord(pPciDev, 0xa0 + 44,
3737 /* Supported Link Speeds Vector */ (2 << 1)); /* Link capabilities 2. */
3738 PDMPciDevSetWord(pPciDev, 0xa0 + 48,
3739 /* Target Link Speed */ 2); /* Link control 2. */
3740 PDMPciDevSetWord(pPciDev, 0xa0 + 50, 0x0000); /* Link status 2. */
3741 PDMPciDevSetDWord(pPciDev, 0xa0 + 52, 0x00000000); /* Slot capabilities 2. */
3742 PDMPciDevSetWord(pPciDev, 0xa0 + 56, 0x0000); /* Slot control 2. */
3743 PDMPciDevSetWord(pPciDev, 0xa0 + 58, 0x0000); /* Slot status 2. */
3744 PDMPciDevSetCapabilityList(pPciDev, 0xa0);
3745 }
3746 else
3747 {
3748 PDMPciDevSetCommand(pPciDev, 0x00);
3749 PDMPciDevSetStatus(pPciDev, 0x20); /* 66MHz Capable. */
3750 }
3751 PDMPciDevSetInterruptLine(pPciDev, 0x00); /* This device does not assert interrupts. */
3752
3753 /*
3754 * This device does not generate interrupts. Interrupt delivery from
3755 * devices attached to the bus is unaffected.
3756 */
3757 PDMPciDevSetInterruptPin (pPciDev, 0x00);
3758
3759 if (fExpress)
3760 {
3761 /** @todo r=klaus set up the PCIe config space beyond the old 256 byte
3762 * limit, containing additional capability descriptors. */
3763 }
3764
3765 /*
3766 * Register this PCI bridge. The called function will take care on which bus we will get registered.
3767 */
3768 rc = PDMDevHlpPCIRegisterEx(pDevIns, pPciDev, PDMPCIDEVREG_F_PCI_BRIDGE, PDMPCIDEVREG_DEV_NO_FIRST_UNUSED,
3769 PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, "ich9pcibridge");
3770 AssertLogRelRCReturn(rc, rc);
3771
3772 pPciDev->Int.s.pfnBridgeConfigRead = ich9pcibridgeConfigRead;
3773 pPciDev->Int.s.pfnBridgeConfigWrite = ich9pcibridgeConfigWrite;
3774
3775 /*
3776 * Register SSM handlers. We use the same saved state version as for the host bridge
3777 * to make changes easier.
3778 */
3779 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION,
3780 sizeof(*pBus) + 16*128,
3781 "pgm" /* before */,
3782 NULL, NULL, NULL,
3783 NULL, ich9pcibridgeR3SaveExec, NULL,
3784 NULL, ich9pcibridgeR3LoadExec, NULL);
3785 AssertLogRelRCReturn(rc, rc);
3786
3787 return VINF_SUCCESS;
3788}
3789
3790#else /* !IN_RING3 */
3791
3792/**
3793 * @interface_method_impl{PDMDEVREGR0,pfnConstruct}
3794 */
3795DECLCALLBACK(int) ich9pciRZConstruct(PPDMDEVINS pDevIns)
3796{
3797 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3798 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3799 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3800
3801 /* Mirror the ring-3 device lock disabling: */
3802 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3803 AssertRCReturn(rc, rc);
3804
3805 /* Set up the RZ PCI bus callbacks: */
3806 PDMPCIBUSREGCC PciBusReg;
3807 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3808 PciBusReg.iBus = pPciRoot->PciBus.iBus;
3809 PciBusReg.pfnSetIrq = ich9pciSetIrq;
3810 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3811 rc = PDMDevHlpPCIBusSetUpContext(pDevIns, &PciBusReg, &pBusCC->CTX_SUFF(pPciHlp));
3812 AssertRCReturn(rc, rc);
3813
3814 /* Set up I/O port callbacks, except for the magic port: */
3815 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pPciRoot->hIoPortAddress, ich9pciIOPortAddressWrite, ich9pciIOPortAddressRead, NULL);
3816 AssertLogRelRCReturn(rc, rc);
3817
3818 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pPciRoot->hIoPortData, ich9pciIOPortDataWrite, ich9pciIOPortDataRead, NULL);
3819 AssertLogRelRCReturn(rc, rc);
3820
3821 /* Set up MMIO callbacks: */
3822 if (pPciRoot->hMmioMcfg != NIL_IOMMMIOHANDLE)
3823 {
3824 rc = PDMDevHlpMmioSetUpContext(pDevIns, pPciRoot->hMmioMcfg, ich9pciMcfgMMIOWrite, ich9pciMcfgMMIORead, NULL /*pvUser*/);
3825 AssertLogRelRCReturn(rc, rc);
3826 }
3827
3828 return rc;
3829}
3830
3831
3832/**
3833 * @interface_method_impl{PDMDEVREGR0,pfnConstruct}
3834 */
3835DECLCALLBACK(int) ich9pcibridgeRZConstruct(PPDMDEVINS pDevIns)
3836{
3837 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3838 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3839 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3840
3841 /* Mirror the ring-3 device lock disabling: */
3842 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3843 AssertRCReturn(rc, rc);
3844
3845 /* Set up the RZ PCI bus callbacks: */
3846 PDMPCIBUSREGCC PciBusReg;
3847 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3848 PciBusReg.iBus = pBus->iBus;
3849 PciBusReg.pfnSetIrq = ich9pcibridgeSetIrq;
3850 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3851 rc = PDMDevHlpPCIBusSetUpContext(pDevIns, &PciBusReg, &pBusCC->CTX_SUFF(pPciHlp));
3852 AssertRCReturn(rc, rc);
3853
3854 return rc;
3855}
3856
3857#endif /* !IN_RING3 */
3858
3859/**
3860 * The PCI bus device registration structure.
3861 */
3862const PDMDEVREG g_DevicePciIch9 =
3863{
3864 /* .u32Version = */ PDM_DEVREG_VERSION,
3865 /* .uReserved0 = */ 0,
3866 /* .szName = */ "ich9pci",
3867 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
3868 /* .fClass = */ PDM_DEVREG_CLASS_BUS_PCI,
3869 /* .cMaxInstances = */ 1,
3870 /* .uSharedVersion = */ 42,
3871 /* .cbInstanceShared = */ sizeof(DEVPCIROOT),
3872 /* .cbInstanceCC = */ sizeof(CTX_SUFF(DEVPCIBUS)),
3873 /* .cbInstanceRC = */ sizeof(DEVPCIBUSRC),
3874 /* .cMaxPciDevices = */ 1,
3875 /* .cMaxMsixVectors = */ 0,
3876 /* .pszDescription = */ "ICH9 PCI bridge",
3877#if defined(IN_RING3)
3878 /* .pszRCMod = */ "VBoxDDRC.rc",
3879 /* .pszR0Mod = */ "VBoxDDR0.r0",
3880 /* .pfnConstruct = */ ich9pciR3Construct,
3881 /* .pfnDestruct = */ ich9pciR3Destruct,
3882 /* .pfnRelocate = */ NULL,
3883 /* .pfnMemSetup = */ NULL,
3884 /* .pfnPowerOn = */ NULL,
3885 /* .pfnReset = */ ich9pciReset,
3886 /* .pfnSuspend = */ NULL,
3887 /* .pfnResume = */ NULL,
3888 /* .pfnAttach = */ NULL,
3889 /* .pfnDetach = */ NULL,
3890 /* .pfnQueryInterface = */ NULL,
3891 /* .pfnInitComplete = */ NULL,
3892 /* .pfnPowerOff = */ NULL,
3893 /* .pfnSoftReset = */ NULL,
3894 /* .pfnReserved0 = */ NULL,
3895 /* .pfnReserved1 = */ NULL,
3896 /* .pfnReserved2 = */ NULL,
3897 /* .pfnReserved3 = */ NULL,
3898 /* .pfnReserved4 = */ NULL,
3899 /* .pfnReserved5 = */ NULL,
3900 /* .pfnReserved6 = */ NULL,
3901 /* .pfnReserved7 = */ NULL,
3902#elif defined(IN_RING0)
3903 /* .pfnEarlyConstruct = */ NULL,
3904 /* .pfnConstruct = */ ich9pciRZConstruct,
3905 /* .pfnDestruct = */ NULL,
3906 /* .pfnFinalDestruct = */ NULL,
3907 /* .pfnRequest = */ NULL,
3908 /* .pfnReserved0 = */ NULL,
3909 /* .pfnReserved1 = */ NULL,
3910 /* .pfnReserved2 = */ NULL,
3911 /* .pfnReserved3 = */ NULL,
3912 /* .pfnReserved4 = */ NULL,
3913 /* .pfnReserved5 = */ NULL,
3914 /* .pfnReserved6 = */ NULL,
3915 /* .pfnReserved7 = */ NULL,
3916#elif defined(IN_RC)
3917 /* .pfnConstruct = */ ich9pciRZConstruct,
3918 /* .pfnReserved0 = */ NULL,
3919 /* .pfnReserved1 = */ NULL,
3920 /* .pfnReserved2 = */ NULL,
3921 /* .pfnReserved3 = */ NULL,
3922 /* .pfnReserved4 = */ NULL,
3923 /* .pfnReserved5 = */ NULL,
3924 /* .pfnReserved6 = */ NULL,
3925 /* .pfnReserved7 = */ NULL,
3926#else
3927# error "Not in IN_RING3, IN_RING0 or IN_RC!"
3928#endif
3929 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
3930};
3931
3932/**
3933 * The device registration structure
3934 * for the PCI-to-PCI bridge.
3935 */
3936const PDMDEVREG g_DevicePciIch9Bridge =
3937{
3938 /* .u32Version = */ PDM_DEVREG_VERSION,
3939 /* .uReserved0 = */ 0,
3940 /* .szName = */ "ich9pcibridge",
3941 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
3942 /* .fClass = */ PDM_DEVREG_CLASS_BUS_PCI,
3943 /* .cMaxInstances = */ ~0U,
3944 /* .uSharedVersion = */ 42,
3945 /* .cbInstanceShared = */ sizeof(DEVPCIBUS),
3946 /* .cbInstanceCC = */ sizeof(CTX_SUFF(DEVPCIBUS)),
3947 /* .cbInstanceRC = */ 0,
3948 /* .cMaxPciDevices = */ 1,
3949 /* .cMaxMsixVectors = */ 0,
3950 /* .pszDescription = */ "ICH9 PCI to PCI bridge",
3951#if defined(IN_RING3)
3952 /* .pszRCMod = */ "VBoxDDRC.rc",
3953 /* .pszR0Mod = */ "VBoxDDR0.r0",
3954 /* .pfnConstruct = */ ich9pcibridgeR3Construct,
3955 /* .pfnDestruct = */ ich9pcibridgeR3Destruct,
3956 /* .pfnRelocate = */ NULL,
3957 /* .pfnMemSetup = */ NULL,
3958 /* .pfnPowerOn = */ NULL,
3959 /* .pfnReset = */ NULL, /* Must be NULL, to make sure only bus driver handles reset */
3960 /* .pfnSuspend = */ NULL,
3961 /* .pfnResume = */ NULL,
3962 /* .pfnAttach = */ NULL,
3963 /* .pfnDetach = */ NULL,
3964 /* .pfnQueryInterface = */ NULL,
3965 /* .pfnInitComplete = */ NULL,
3966 /* .pfnPowerOff = */ NULL,
3967 /* .pfnSoftReset = */ NULL,
3968 /* .pfnReserved0 = */ NULL,
3969 /* .pfnReserved1 = */ NULL,
3970 /* .pfnReserved2 = */ NULL,
3971 /* .pfnReserved3 = */ NULL,
3972 /* .pfnReserved4 = */ NULL,
3973 /* .pfnReserved5 = */ NULL,
3974 /* .pfnReserved6 = */ NULL,
3975 /* .pfnReserved7 = */ NULL,
3976#elif defined(IN_RING0)
3977 /* .pfnEarlyConstruct = */ NULL,
3978 /* .pfnConstruct = */ ich9pcibridgeRZConstruct,
3979 /* .pfnDestruct = */ NULL,
3980 /* .pfnFinalDestruct = */ NULL,
3981 /* .pfnRequest = */ NULL,
3982 /* .pfnReserved0 = */ NULL,
3983 /* .pfnReserved1 = */ NULL,
3984 /* .pfnReserved2 = */ NULL,
3985 /* .pfnReserved3 = */ NULL,
3986 /* .pfnReserved4 = */ NULL,
3987 /* .pfnReserved5 = */ NULL,
3988 /* .pfnReserved6 = */ NULL,
3989 /* .pfnReserved7 = */ NULL,
3990#elif defined(IN_RC)
3991 /* .pfnConstruct = */ ich9pcibridgeRZConstruct,
3992 /* .pfnReserved0 = */ NULL,
3993 /* .pfnReserved1 = */ NULL,
3994 /* .pfnReserved2 = */ NULL,
3995 /* .pfnReserved3 = */ NULL,
3996 /* .pfnReserved4 = */ NULL,
3997 /* .pfnReserved5 = */ NULL,
3998 /* .pfnReserved6 = */ NULL,
3999 /* .pfnReserved7 = */ NULL,
4000#else
4001# error "Not in IN_RING3, IN_RING0 or IN_RC!"
4002#endif
4003 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
4004};
4005
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