VirtualBox

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

Last change on this file since 82891 was 82313, checked in by vboxsync, 5 years ago

IOM,PDMDevHlp: Kicked out the old MMIO code. bugref:9218

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