VirtualBox

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

Last change on this file since 82254 was 82221, checked in by vboxsync, 5 years ago

DevPciIch9: Converted the MCFG MMIO registration. bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 170.3 KB
Line 
1/* $Id: DevPciIch9.cpp 82221 2019-11-26 13:30:10Z vboxsync $ */
2/** @file
3 * DevPCI - ICH9 southbridge PCI bus emulation device.
4 *
5 * @remarks We'll be slowly promoting the code in this file to common PCI bus
6 * code. Function without 'static' and using 'devpci' as prefix is
7 * also used by DevPCI.cpp and have a prototype in DevPciInternal.h.
8 *
9 * For the time being the DevPciMerge1.cpp.h file will remain separate,
10 * due to 5.1. We can merge it into this one later in the dev cycle.
11 *
12 * DO NOT use the PDMPciDev* or PCIDev* family of functions in this
13 * file except in the two callbacks for config space access (and the
14 * functions which are used exclusively by that code) and the two
15 * device constructors when setting up the config space for the
16 * bridges. Everything else need extremely careful review. Using
17 * them elsewhere (especially in the init code) causes weird failures
18 * with PCI passthrough, as it would only update the array of
19 * (emulated) config space, but not talk to the actual device (needs
20 * invoking the respective callback).
21 */
22
23/*
24 * Copyright (C) 2010-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 pDevIns The PCI bus device instance.
2515 * @param pDev The PCI device.
2516 * @param iRegion The region to unmap.
2517 */
2518static int devpciR3UnmapRegion(PPDMDEVINS pDevIns, PPDMPCIDEV pDev, int iRegion)
2519{
2520 PPCIIOREGION pRegion = &pDev->Int.s.aIORegions[iRegion];
2521 AssertReturn(pRegion->size != 0, VINF_SUCCESS);
2522
2523 int rc = VINF_SUCCESS;
2524 if (pRegion->addr != INVALID_PCI_ADDRESS)
2525 {
2526 if ( (pRegion->hHandle != UINT64_MAX)
2527 || (pRegion->fFlags & PDMPCIDEV_IORGN_F_NEW_STYLE))
2528 {
2529 /*
2530 * New style device with a IOM handle. Do callout first (optional),
2531 * then do the unmapping via handle.
2532 */
2533 if (pRegion->pfnMap)
2534 {
2535 rc = pRegion->pfnMap(pDev->Int.s.pDevInsR3, pDev, iRegion,
2536 NIL_RTGCPHYS, pRegion->size, (PCIADDRESSSPACE)(pRegion->type));
2537 AssertRC(rc);
2538 }
2539
2540 switch (pRegion->fFlags & PDMPCIDEV_IORGN_F_HANDLE_MASK)
2541 {
2542 case PDMPCIDEV_IORGN_F_IOPORT_HANDLE:
2543 rc = PDMDevHlpIoPortUnmap(pDev->Int.s.pDevInsR3, (IOMIOPORTHANDLE)pRegion->hHandle);
2544 AssertRC(rc);
2545 break;
2546
2547 case PDMPCIDEV_IORGN_F_MMIO_HANDLE:
2548 rc = PDMDevHlpMmioUnmap(pDev->Int.s.pDevInsR3, (IOMMMIOHANDLE)pRegion->hHandle);
2549 AssertRC(rc);
2550 break;
2551
2552 case PDMPCIDEV_IORGN_F_MMIO2_HANDLE:
2553 rc = PDMDevHlpMmio2Unmap(pDev->Int.s.pDevInsR3, (PGMMMIO2HANDLE)pRegion->hHandle);
2554 AssertRC(rc);
2555 break;
2556
2557 case PDMPCIDEV_IORGN_F_NO_HANDLE:
2558 Assert(pRegion->fFlags & PDMPCIDEV_IORGN_F_NEW_STYLE);
2559 Assert(pRegion->hHandle == UINT64_MAX);
2560 break;
2561
2562 default:
2563 AssertLogRelFailed();
2564 }
2565 }
2566 else
2567 {
2568 /*
2569 * Old style device, no handle here and only MMIOEx gets callouts.
2570 */
2571 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
2572 {
2573 /* Port IO */
2574 rc = PDMDevHlpIOPortDeregister(pDev->Int.s.pDevInsR3, pRegion->addr, pRegion->size);
2575 AssertRC(rc);
2576 }
2577 else
2578 {
2579 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
2580 RTGCPHYS GCPhysBase = pRegion->addr;
2581 if (pBusCC->pPciHlpR3->pfnIsMMIOExBase(pDevIns, pDev->Int.s.pDevInsR3, GCPhysBase))
2582 {
2583 /* unmap it. */
2584 rc = pRegion->pfnMap(pDev->Int.s.pDevInsR3, pDev, iRegion,
2585 NIL_RTGCPHYS, pRegion->size, (PCIADDRESSSPACE)(pRegion->type));
2586 AssertRC(rc);
2587 rc = PDMDevHlpMMIOExUnmap(pDev->Int.s.pDevInsR3, pDev, iRegion, GCPhysBase);
2588 }
2589 else
2590 rc = PDMDevHlpMMIODeregister(pDev->Int.s.pDevInsR3, GCPhysBase, pRegion->size);
2591 AssertRC(rc);
2592 }
2593 }
2594 pRegion->addr = INVALID_PCI_ADDRESS;
2595 }
2596 return rc;
2597}
2598
2599
2600/**
2601 * Worker for devpciR3CommonDefaultConfigWrite that updates BAR and ROM mappings.
2602 *
2603 * @returns VINF_SUCCESS of DBGFSTOP result.
2604 * @param pDevIns The PCI bus device instance.
2605 * @param pPciDev The PCI device to update the mappings for.
2606 * @param fP2PBridge Whether this is a PCI to PCI bridge or not.
2607 */
2608static VBOXSTRICTRC devpciR3UpdateMappings(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, bool fP2PBridge)
2609{
2610 /* safe, only needs to go to the config space array */
2611 uint16_t const u16Cmd = PDMPciDevGetWord(pPciDev, VBOX_PCI_COMMAND);
2612 Log4(("devpciR3UpdateMappings: dev %u/%u (%s): u16Cmd=%#x\n",
2613 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK, pPciDev->pszNameR3, u16Cmd));
2614 for (unsigned iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
2615 {
2616 /* Skip over BAR2..BAR5 for bridges, as they have a different meaning there. */
2617 if (fP2PBridge && iRegion >= 2 && iRegion <= 5)
2618 continue;
2619 PCIIOREGION *pRegion = &pPciDev->Int.s.aIORegions[iRegion];
2620 uint64_t const cbRegion = pRegion->size;
2621 if (cbRegion != 0)
2622 {
2623 uint32_t const offCfgReg = devpciGetRegionReg(iRegion);
2624 bool const f64Bit = (pRegion->type & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
2625 == PCI_ADDRESS_SPACE_BAR64;
2626 uint64_t uNew = INVALID_PCI_ADDRESS;
2627
2628 /*
2629 * Port I/O region. Check if mapped and within 1..65535 range.
2630 */
2631 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
2632 {
2633 if (u16Cmd & VBOX_PCI_COMMAND_IO)
2634 {
2635 /* safe, only needs to go to the config space array */
2636 uint32_t uIoBase = PDMPciDevGetDWord(pPciDev, offCfgReg);
2637 uIoBase &= ~(uint32_t)(cbRegion - 1);
2638
2639 uint64_t uLast = cbRegion - 1 + uIoBase;
2640 if ( uLast < _64K
2641 && uIoBase < uLast
2642 && uIoBase > 0)
2643 uNew = uIoBase;
2644 else
2645 Log4(("devpciR3UpdateMappings: dev %u/%u (%s): region #%u: Disregarding invalid I/O port range: %#RX32..%#RX64\n",
2646 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2647 pPciDev->pszNameR3, iRegion, uIoBase, uLast));
2648 }
2649 }
2650 /*
2651 * MMIO or ROM. Check ROM enable bit and range.
2652 *
2653 * Note! We exclude the I/O-APIC/HPET/ROM area at the end of the first 4GB to
2654 * prevent the (fake) PCI BIOS and others from making a mess. Pure paranoia.
2655 * Additionally addresses with the top 32 bits all set are excluded, to
2656 * catch silly OSes which probe 64-bit BARs without disabling the
2657 * corresponding transactions.
2658 *
2659 * Update: The pure paranoia above broke NT 3.51, so it was changed to only
2660 * exclude the 64KB BIOS mapping at the top. NT 3.51 excludes the
2661 * top 256KB, btw.
2662 */
2663 /** @todo Query upper boundrary from CPUM and PGMPhysRom instead of making
2664 * incorrect assumptions. */
2665 else if (u16Cmd & VBOX_PCI_COMMAND_MEMORY)
2666 {
2667 /* safe, only needs to go to the config space array */
2668 uint64_t uMemBase = PDMPciDevGetDWord(pPciDev, offCfgReg);
2669 if (f64Bit)
2670 {
2671 Assert(iRegion < VBOX_PCI_ROM_SLOT);
2672 /* safe, only needs to go to the config space array */
2673 uMemBase |= (uint64_t)PDMPciDevGetDWord(pPciDev, offCfgReg + 4) << 32;
2674 }
2675 if ( iRegion != PCI_ROM_SLOT
2676 || (uMemBase & RT_BIT_32(0))) /* ROM enable bit. */
2677 {
2678 uMemBase &= ~(cbRegion - 1);
2679
2680 uint64_t uLast = uMemBase + cbRegion - 1;
2681 if ( uMemBase < uLast
2682 && uMemBase > 0)
2683 {
2684 if ( ( uMemBase > UINT32_C(0xffffffff)
2685 || uLast < UINT32_C(0xffff0000) ) /* UINT32_C(0xfec00000) - breaks NT3.51! */
2686 && uMemBase < UINT64_C(0xffffffff00000000) )
2687 uNew = uMemBase;
2688 else
2689 Log(("devpciR3UpdateMappings: dev %u/%u (%s): region #%u: Rejecting address range: %#RX64..%#RX64!\n",
2690 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2691 pPciDev->pszNameR3, iRegion, uMemBase, uLast));
2692 }
2693 else
2694 Log2(("devpciR3UpdateMappings: dev %u/%u (%s): region #%u: Disregarding invalid address range: %#RX64..%#RX64\n",
2695 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2696 pPciDev->pszNameR3, iRegion, uMemBase, uLast));
2697 }
2698 }
2699
2700 /*
2701 * Do real unmapping and/or mapping if the address change.
2702 *
2703 * For new style device we'll do the actual mapping, whereas old ones
2704 * are expected to do it themselves via the callback.
2705 */
2706 Log4(("devpciR3UpdateMappings: dev %u/%u (%s): iRegion=%u addr=%#RX64 uNew=%#RX64\n",
2707 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK, pPciDev->pszNameR3,
2708 iRegion, pRegion->addr, uNew));
2709 if (uNew != pRegion->addr)
2710 {
2711 LogRel2(("PCI: config dev %u/%u (%s) BAR%i: %#RX64 -> %#RX64 (LB %RX64 (%RU64))\n",
2712 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2713 pPciDev->pszNameR3, iRegion, pRegion->addr, uNew, cbRegion, cbRegion));
2714
2715 int rc = devpciR3UnmapRegion(pDevIns, pPciDev, iRegion);
2716 AssertLogRelRC(rc);
2717 pRegion->addr = uNew;
2718 if (uNew != INVALID_PCI_ADDRESS)
2719 {
2720 /* The callout is optional with new style devices: */
2721 if (!pRegion->pfnMap)
2722 rc = VINF_SUCCESS;
2723 else
2724 {
2725 rc = pRegion->pfnMap(pPciDev->Int.s.pDevInsR3, pPciDev, iRegion,
2726 uNew, cbRegion, (PCIADDRESSSPACE)(pRegion->type));
2727 AssertLogRelRC(rc);
2728 }
2729
2730 /* We do the mapping for new-style devices: */
2731 if (pRegion->hHandle != UINT64_MAX && rc != VINF_PCI_MAPPING_DONE)
2732 {
2733 switch (pRegion->fFlags & PDMPCIDEV_IORGN_F_HANDLE_MASK)
2734 {
2735 case PDMPCIDEV_IORGN_F_IOPORT_HANDLE:
2736 rc = PDMDevHlpIoPortMap(pPciDev->Int.s.pDevInsR3, (IOMIOPORTHANDLE)pRegion->hHandle, (RTIOPORT)uNew);
2737 AssertLogRelRC(rc);
2738 break;
2739
2740 case PDMPCIDEV_IORGN_F_MMIO_HANDLE:
2741 rc = PDMDevHlpMmioMap(pPciDev->Int.s.pDevInsR3, (IOMMMIOHANDLE)pRegion->hHandle, uNew);
2742 AssertLogRelRC(rc);
2743 break;
2744
2745 case PDMPCIDEV_IORGN_F_MMIO2_HANDLE:
2746 rc = PDMDevHlpMmio2Map(pPciDev->Int.s.pDevInsR3, (PGMMMIO2HANDLE)pRegion->hHandle, uNew);
2747 AssertRC(rc);
2748 break;
2749
2750 default:
2751 AssertLogRelFailed();
2752 }
2753 }
2754 }
2755 }
2756
2757 if (f64Bit)
2758 iRegion++;
2759 }
2760 /* else: size == 0: unused region */
2761 }
2762
2763 return VINF_SUCCESS;
2764}
2765
2766
2767/**
2768 * Worker for devpciR3CommonDefaultConfigWrite that write a byte to a BAR.
2769 *
2770 * @param pPciDev The PCI device.
2771 * @param iRegion The region.
2772 * @param off The BAR offset.
2773 * @param bVal The byte to write.
2774 */
2775DECLINLINE(void) devpciR3WriteBarByte(PPDMPCIDEV pPciDev, uint32_t iRegion, uint32_t off, uint8_t bVal)
2776{
2777 PCIIOREGION *pRegion = &pPciDev->Int.s.aIORegions[iRegion];
2778 Log3Func(("region=%d off=%d val=%#x size=%#llx\n", iRegion, off, bVal, pRegion->size));
2779 Assert(off <= 3);
2780
2781 /* Check if we're writing to upper part of 64-bit BAR. */
2782 if (pRegion->type == 0xff)
2783 {
2784 AssertLogRelReturnVoid(iRegion > 0 && iRegion < VBOX_PCI_ROM_SLOT);
2785 pRegion--;
2786 iRegion--;
2787 off += 4;
2788 Assert(pRegion->type & PCI_ADDRESS_SPACE_BAR64);
2789 }
2790
2791 /* Ignore zero sized regions (they don't exist). */
2792 if (pRegion->size != 0)
2793 {
2794 uint32_t uAddr = devpciGetRegionReg(iRegion) + off;
2795 Assert((pRegion->size & (pRegion->size - 1)) == 0); /* Region size must be power of two. */
2796 uint8_t bMask = ( (pRegion->size - 1) >> (off * 8) ) & 0xff;
2797 if (off == 0)
2798 bMask |= (pRegion->type & PCI_ADDRESS_SPACE_IO)
2799 ? (1 << 2) - 1 /* 2 lowest bits for IO region */ :
2800 (1 << 4) - 1 /* 4 lowest bits for memory region, also ROM enable bit for ROM region */;
2801
2802 /* safe, only needs to go to the config space array */
2803 uint8_t bOld = PDMPciDevGetByte(pPciDev, uAddr) & bMask;
2804 bVal = (bOld & bMask) | (bVal & ~bMask);
2805
2806 Log3Func(("%x changed to %x\n", bOld, bVal));
2807
2808 /* safe, only needs to go to the config space array */
2809 PDMPciDevSetByte(pPciDev, uAddr, bVal);
2810 }
2811}
2812
2813
2814/**
2815 * Checks if the given configuration byte is writable.
2816 *
2817 * @returns true if writable, false if not
2818 * @param uAddress The config space byte byte.
2819 * @param bHeaderType The device header byte.
2820 */
2821DECLINLINE(bool) devpciR3IsConfigByteWritable(uint32_t uAddress, uint8_t bHeaderType)
2822{
2823 switch (bHeaderType)
2824 {
2825 case 0x00: /* normal device */
2826 case 0x80: /* multi-function device */
2827 switch (uAddress)
2828 {
2829 /* Read-only registers. */
2830 case VBOX_PCI_VENDOR_ID:
2831 case VBOX_PCI_VENDOR_ID+1:
2832 case VBOX_PCI_DEVICE_ID:
2833 case VBOX_PCI_DEVICE_ID+1:
2834 case VBOX_PCI_REVISION_ID:
2835 case VBOX_PCI_CLASS_PROG:
2836 case VBOX_PCI_CLASS_SUB:
2837 case VBOX_PCI_CLASS_BASE:
2838 case VBOX_PCI_HEADER_TYPE:
2839 case VBOX_PCI_SUBSYSTEM_VENDOR_ID:
2840 case VBOX_PCI_SUBSYSTEM_VENDOR_ID+1:
2841 case VBOX_PCI_SUBSYSTEM_ID:
2842 case VBOX_PCI_SUBSYSTEM_ID+1:
2843 case VBOX_PCI_ROM_ADDRESS:
2844 case VBOX_PCI_ROM_ADDRESS+1:
2845 case VBOX_PCI_ROM_ADDRESS+2:
2846 case VBOX_PCI_ROM_ADDRESS+3:
2847 case VBOX_PCI_CAPABILITY_LIST:
2848 case VBOX_PCI_INTERRUPT_PIN:
2849 return false;
2850 /* Other registers can be written. */
2851 default:
2852 return true;
2853 }
2854 break;
2855 case 0x01: /* PCI-PCI bridge */
2856 switch (uAddress)
2857 {
2858 /* Read-only registers. */
2859 case VBOX_PCI_VENDOR_ID:
2860 case VBOX_PCI_VENDOR_ID+1:
2861 case VBOX_PCI_DEVICE_ID:
2862 case VBOX_PCI_DEVICE_ID+1:
2863 case VBOX_PCI_REVISION_ID:
2864 case VBOX_PCI_CLASS_PROG:
2865 case VBOX_PCI_CLASS_SUB:
2866 case VBOX_PCI_CLASS_BASE:
2867 case VBOX_PCI_HEADER_TYPE:
2868 case VBOX_PCI_ROM_ADDRESS_BR:
2869 case VBOX_PCI_ROM_ADDRESS_BR+1:
2870 case VBOX_PCI_ROM_ADDRESS_BR+2:
2871 case VBOX_PCI_ROM_ADDRESS_BR+3:
2872 case VBOX_PCI_INTERRUPT_PIN:
2873 return false;
2874 /* Other registers can be written. */
2875 default:
2876 return true;
2877 }
2878 break;
2879 default:
2880 AssertMsgFailed(("Unknown header type %#x\n", bHeaderType));
2881 return false;
2882 }
2883}
2884
2885
2886/**
2887 * Writes config space for a device, ignoring interceptors.
2888 *
2889 * See paragraph 7.5 of PCI Express specification (p. 349) for
2890 * definition of registers and their writability policy.
2891 */
2892DECLHIDDEN(VBOXSTRICTRC) devpciR3CommonConfigWriteWorker(PPDMDEVINS pDevIns, PDEVPCIBUSCC pBusCC,
2893 PPDMPCIDEV pPciDev, uint32_t uAddress, unsigned cb, uint32_t u32Value)
2894{
2895 Assert(cb <= 4 && cb != 3);
2896 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2897
2898 if (uAddress + cb <= RT_MIN(pPciDev->cbConfig, sizeof(pPciDev->abConfig)))
2899 {
2900 /*
2901 * MSI and MSI-X capabilites needs to be handled separately.
2902 */
2903 if ( pciDevIsMsiCapable(pPciDev)
2904 && uAddress - (uint32_t)pPciDev->Int.s.u8MsiCapOffset < (uint32_t)pPciDev->Int.s.u8MsiCapSize)
2905 MsiR3PciConfigWrite(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, uAddress, u32Value, cb);
2906 else if ( pciDevIsMsixCapable(pPciDev)
2907 && uAddress - (uint32_t)pPciDev->Int.s.u8MsixCapOffset < (uint32_t)pPciDev->Int.s.u8MsixCapSize)
2908 MsixR3PciConfigWrite(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, uAddress, u32Value, cb);
2909 else
2910 {
2911 /*
2912 * Handle the writes byte-by-byte to catch all possible cases.
2913 *
2914 * Note! Real hardware may not necessarily handle non-dword writes like
2915 * we do here and even produce erratic behavior. We don't (yet)
2916 * try emulate that.
2917 */
2918 uint8_t const bHeaderType = devpciR3GetByte(pPciDev, VBOX_PCI_HEADER_TYPE);
2919 bool const fP2PBridge = bHeaderType == 0x01; /* PCI-PCI bridge */
2920 bool fUpdateMappings = false;
2921 while (cb-- > 0)
2922 {
2923 bool fWritable = devpciR3IsConfigByteWritable(uAddress, bHeaderType);
2924 uint8_t bVal = (uint8_t)u32Value;
2925 bool fRom = false;
2926 switch (uAddress)
2927 {
2928 case VBOX_PCI_COMMAND: /* Command register, bits 0-7. */
2929 if (fWritable)
2930 {
2931 /* safe, only needs to go to the config space array */
2932 PDMPciDevSetByte(pPciDev, uAddress, bVal);
2933 fUpdateMappings = true;
2934 }
2935 break;
2936
2937 case VBOX_PCI_COMMAND+1: /* Command register, bits 8-15. */
2938 if (fWritable)
2939 {
2940 /* don't change reserved bits (11-15) */
2941 bVal &= ~UINT8_C(0xf8);
2942 /* safe, only needs to go to the config space array */
2943 PDMPciDevSetByte(pPciDev, uAddress, bVal);
2944 fUpdateMappings = true;
2945 }
2946 break;
2947
2948 case VBOX_PCI_STATUS: /* Status register, bits 0-7. */
2949 /* don't change read-only bits => actually all lower bits are read-only */
2950 bVal &= ~UINT8_C(0xff);
2951 /* status register, low part: clear bits by writing a '1' to the corresponding bit */
2952 pPciDev->abConfig[uAddress] &= ~bVal;
2953 break;
2954
2955 case VBOX_PCI_STATUS+1: /* Status register, bits 8-15. */
2956 /* don't change read-only bits */
2957 bVal &= ~UINT8_C(0x06);
2958 /* status register, high part: clear bits by writing a '1' to the corresponding bit */
2959 pPciDev->abConfig[uAddress] &= ~bVal;
2960 break;
2961
2962 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS +1: case VBOX_PCI_ROM_ADDRESS +2: case VBOX_PCI_ROM_ADDRESS +3:
2963 fRom = true;
2964 RT_FALL_THRU();
2965 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:
2966 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:
2967 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:
2968 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:
2969 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:
2970 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:
2971 /* We check that, as same PCI register numbers as BARs may mean different registers for bridges */
2972 if (!fP2PBridge)
2973 {
2974 uint32_t iRegion = fRom ? VBOX_PCI_ROM_SLOT : (uAddress - VBOX_PCI_BASE_ADDRESS_0) >> 2;
2975 devpciR3WriteBarByte(pPciDev, iRegion, uAddress & 0x3, bVal);
2976 fUpdateMappings = true;
2977 break;
2978 }
2979 if (uAddress < VBOX_PCI_BASE_ADDRESS_2 || uAddress > VBOX_PCI_BASE_ADDRESS_5+3)
2980 {
2981 /* PCI bridges have only BAR0, BAR1 and ROM */
2982 uint32_t iRegion = fRom ? VBOX_PCI_ROM_SLOT : (uAddress - VBOX_PCI_BASE_ADDRESS_0) >> 2;
2983 devpciR3WriteBarByte(pPciDev, iRegion, uAddress & 0x3, bVal);
2984 fUpdateMappings = true;
2985 break;
2986 }
2987 if ( uAddress == VBOX_PCI_IO_BASE
2988 || uAddress == VBOX_PCI_IO_LIMIT
2989 || uAddress == VBOX_PCI_MEMORY_BASE
2990 || uAddress == VBOX_PCI_MEMORY_LIMIT
2991 || uAddress == VBOX_PCI_PREF_MEMORY_BASE
2992 || uAddress == VBOX_PCI_PREF_MEMORY_LIMIT)
2993 {
2994 /* All bridge address decoders have the low 4 bits
2995 * as readonly, and all but the prefetchable ones
2996 * have the low 4 bits as 0 (the prefetchable have
2997 * it as 1 to show the 64-bit decoder support. */
2998 bVal &= 0xf0;
2999 if ( uAddress == VBOX_PCI_PREF_MEMORY_BASE
3000 || uAddress == VBOX_PCI_PREF_MEMORY_LIMIT)
3001 bVal |= 0x01;
3002 }
3003 /* (bridge config space which isn't a BAR) */
3004 RT_FALL_THRU();
3005 default:
3006 if (fWritable)
3007 /* safe, only needs to go to the config space array */
3008 PDMPciDevSetByte(pPciDev, uAddress, bVal);
3009 break;
3010 }
3011 uAddress++;
3012 u32Value >>= 8;
3013 }
3014
3015 /*
3016 * Update the region mappings if anything changed related to them (command, BARs, ROM).
3017 */
3018 if (fUpdateMappings)
3019 rcStrict = devpciR3UpdateMappings(pDevIns, pPciDev, fP2PBridge);
3020 }
3021 }
3022 else
3023 AssertMsgFailed(("Write after end of PCI config space: %#x LB %u\n", uAddress, cb));
3024
3025 return rcStrict;
3026}
3027
3028
3029/**
3030 * @interface_method_impl{PDMPCIBUSREGR3,pfnConfigWrite}
3031 */
3032DECLCALLBACK(VBOXSTRICTRC) devpciR3CommonConfigWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
3033 uint32_t uAddress, unsigned cb, uint32_t u32Value)
3034{
3035 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3036 return devpciR3CommonConfigWriteWorker(pDevIns, pBusCC, pPciDev, uAddress, cb, u32Value);
3037}
3038
3039
3040/* -=-=-=-=-=- Debug Info Handlers -=-=-=-=-=- */
3041
3042/**
3043 * Indents an info line.
3044 * @param pHlp The info helper.
3045 * @param iIndentLvl The desired indentation level.
3046 */
3047static void devpciR3InfoIndent(PCDBGFINFOHLP pHlp, unsigned iIndentLvl)
3048{
3049 for (unsigned i = 0; i < iIndentLvl; i++)
3050 pHlp->pfnPrintf(pHlp, " ");
3051}
3052
3053static const char *devpciR3InInfoPciBusClassName(uint8_t iBaseClass)
3054{
3055 static const char *s_szBaseClass[] =
3056 {
3057 /* 00h */ "unknown",
3058 /* 01h */ "mass storage controller",
3059 /* 02h */ "network controller",
3060 /* 03h */ "display controller",
3061 /* 04h */ "multimedia controller",
3062 /* 05h */ "memory controller",
3063 /* 06h */ "bridge device",
3064 /* 07h */ "simple communication controllers",
3065 /* 08h */ "base system peripherals",
3066 /* 09h */ "input devices",
3067 /* 0Ah */ "docking stations",
3068 /* 0Bh */ "processors",
3069 /* 0Ch */ "serial bus controllers",
3070 /* 0Dh */ "wireless controller",
3071 /* 0Eh */ "intelligent I/O controllers",
3072 /* 0Fh */ "satellite communication controllers",
3073 /* 10h */ "encryption/decryption controllers",
3074 /* 11h */ "data acquisition and signal processing controllers"
3075 };
3076 if (iBaseClass < RT_ELEMENTS(s_szBaseClass))
3077 return s_szBaseClass[iBaseClass];
3078 if (iBaseClass < 0xFF)
3079 return "reserved";
3080 return "device does not fit in any defined classes";
3081}
3082
3083
3084/**
3085 * Recursive worker for devpciR3InfoPci.
3086 *
3087 * @param pBus The bus to show info for.
3088 * @param pHlp The info helpers.
3089 * @param iIndentLvl The indentation level.
3090 * @param fRegisters Whether to show device registers or not.
3091 */
3092static void devpciR3InfoPciBus(PDEVPCIBUS pBus, PCDBGFINFOHLP pHlp, unsigned iIndentLvl, bool fRegisters)
3093{
3094 /* This has to use the callbacks for accuracy reasons. Otherwise it can get
3095 * confusing in the passthrough case or when the callbacks for some device
3096 * are doing something non-trivial (like implementing an indirect
3097 * passthrough approach), because then the abConfig array is an imprecise
3098 * cache needed for efficiency (so that certain reads can be done from
3099 * R0/RC), but far from authoritative or what the guest would see. */
3100
3101 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
3102 {
3103 PPDMPCIDEV pPciDev = pBus->apDevices[uDevFn];
3104 if (pPciDev != NULL)
3105 {
3106 devpciR3InfoIndent(pHlp, iIndentLvl);
3107
3108 /*
3109 * For passthrough devices MSI/MSI-X mostly reflects the way interrupts delivered to the guest,
3110 * as host driver handles real devices interrupts.
3111 */
3112 pHlp->pfnPrintf(pHlp, "%02x:%02x.%d %s%s: %04x-%04x %s%s%s",
3113 pBus->iBus, (uDevFn >> 3) & 0xff, uDevFn & 0x7,
3114 pPciDev->pszNameR3,
3115 pciDevIsPassthrough(pPciDev) ? " (PASSTHROUGH)" : "",
3116 devpciR3GetWord(pPciDev, VBOX_PCI_VENDOR_ID), devpciR3GetWord(pPciDev, VBOX_PCI_DEVICE_ID),
3117 pBus->fTypeIch9 ? "ICH9" : pBus->fTypePiix3 ? "PIIX3" : "?type?",
3118 pciDevIsMsiCapable(pPciDev) ? " MSI" : "",
3119 pciDevIsMsixCapable(pPciDev) ? " MSI-X" : ""
3120 );
3121 if (devpciR3GetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN) != 0)
3122 {
3123 pHlp->pfnPrintf(pHlp, " IRQ%d", devpciR3GetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE));
3124 pHlp->pfnPrintf(pHlp, " (INTA#->IRQ%d)", 0x10 + ich9pciSlot2ApicIrq(uDevFn >> 3, 0));
3125 }
3126 pHlp->pfnPrintf(pHlp, "\n");
3127 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3128 uint8_t uClassBase = devpciR3GetByte(pPciDev, VBOX_PCI_CLASS_BASE);
3129 uint8_t uClassSub = devpciR3GetByte(pPciDev, VBOX_PCI_CLASS_SUB);
3130 pHlp->pfnPrintf(pHlp, "Class base/sub: %02x%02x (%s)\n",
3131 uClassBase, uClassSub, devpciR3InInfoPciBusClassName(uClassBase));
3132
3133 if (pciDevIsMsiCapable(pPciDev) || pciDevIsMsixCapable(pPciDev))
3134 {
3135 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3136
3137 if (pciDevIsMsiCapable(pPciDev))
3138 pHlp->pfnPrintf(pHlp, "MSI: %s ", MsiIsEnabled(pPciDev) ? "on" : "off");
3139
3140 if (pciDevIsMsixCapable(pPciDev))
3141 pHlp->pfnPrintf(pHlp, "MSI-X: %s ", MsixIsEnabled(pPciDev) ? "on" : "off");
3142
3143 pHlp->pfnPrintf(pHlp, "\n");
3144 }
3145
3146 for (unsigned iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
3147 {
3148 PCIIOREGION const *pRegion = &pPciDev->Int.s.aIORegions[iRegion];
3149 uint64_t const cbRegion = pRegion->size;
3150
3151 if (cbRegion == 0)
3152 continue;
3153
3154 uint32_t uAddr = devpciR3GetDWord(pPciDev, devpciGetRegionReg(iRegion));
3155 const char * pszDesc;
3156 char szDescBuf[128];
3157
3158 bool f64Bit = (pRegion->type & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
3159 == PCI_ADDRESS_SPACE_BAR64;
3160 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
3161 {
3162 pszDesc = "IO";
3163 uAddr &= ~0x3;
3164 }
3165 else
3166 {
3167 RTStrPrintf(szDescBuf, sizeof(szDescBuf), "MMIO%s%s",
3168 f64Bit ? "64" : "32",
3169 pRegion->type & PCI_ADDRESS_SPACE_MEM_PREFETCH ? " PREFETCH" : "");
3170 pszDesc = szDescBuf;
3171 uAddr &= ~0xf;
3172 }
3173
3174 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3175 pHlp->pfnPrintf(pHlp, "%s region #%u: ", pszDesc, iRegion);
3176 if (f64Bit)
3177 {
3178 uint32_t u32High = devpciR3GetDWord(pPciDev, devpciGetRegionReg(iRegion+1));
3179 uint64_t u64Addr = RT_MAKE_U64(uAddr, u32High);
3180 pHlp->pfnPrintf(pHlp, "%RX64..%RX64\n", u64Addr, u64Addr + cbRegion - 1);
3181 iRegion++;
3182 }
3183 else
3184 pHlp->pfnPrintf(pHlp, "%x..%x\n", uAddr, uAddr + (uint32_t)cbRegion - 1);
3185 }
3186
3187 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3188 uint16_t iCmd = devpciR3GetWord(pPciDev, VBOX_PCI_COMMAND);
3189 uint16_t iStatus = devpciR3GetWord(pPciDev, VBOX_PCI_STATUS);
3190 pHlp->pfnPrintf(pHlp, "Command: %04x, Status: %04x\n", iCmd, iStatus);
3191 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3192 pHlp->pfnPrintf(pHlp, "Bus master: %s\n", iCmd & VBOX_PCI_COMMAND_MASTER ? "Yes" : "No");
3193 if (iCmd != PDMPciDevGetCommand(pPciDev))
3194 {
3195 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3196 pHlp->pfnPrintf(pHlp, "CACHE INCONSISTENCY: Command: %04x\n", PDMPciDevGetCommand(pPciDev));
3197 }
3198
3199 if (fRegisters)
3200 {
3201 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3202 pHlp->pfnPrintf(pHlp, "PCI registers:\n");
3203 for (unsigned iReg = 0; iReg < 0x100; )
3204 {
3205 unsigned iPerLine = 0x10;
3206 Assert(0x100 % iPerLine == 0);
3207 devpciR3InfoIndent(pHlp, iIndentLvl + 3);
3208
3209 while (iPerLine-- > 0)
3210 pHlp->pfnPrintf(pHlp, "%02x ", devpciR3GetByte(pPciDev, iReg++));
3211 pHlp->pfnPrintf(pHlp, "\n");
3212 }
3213 }
3214 }
3215 }
3216
3217 if (pBus->cBridges > 0)
3218 {
3219 devpciR3InfoIndent(pHlp, iIndentLvl);
3220 pHlp->pfnPrintf(pHlp, "Registered %d bridges, subordinate buses info follows\n", pBus->cBridges);
3221 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
3222 {
3223 PPDMDEVINS pDevInsSub = pBus->papBridgesR3[iBridge]->Int.s.CTX_SUFF(pDevIns);
3224 PPDMPCIDEV pPciDevSub = pDevInsSub->apPciDevs[0];
3225 PDEVPCIBUS pBusSub = PDMINS_2_DATA(pDevInsSub, PDEVPCIBUS);
3226 uint8_t uPrimary = devpciR3GetByte(pPciDevSub, VBOX_PCI_PRIMARY_BUS);
3227 uint8_t uSecondary = devpciR3GetByte(pPciDevSub, VBOX_PCI_SECONDARY_BUS);
3228 uint8_t uSubordinate = devpciR3GetByte(pPciDevSub, VBOX_PCI_SUBORDINATE_BUS);
3229 devpciR3InfoIndent(pHlp, iIndentLvl);
3230 pHlp->pfnPrintf(pHlp, "%02x:%02x.%d: bridge topology: primary=%d secondary=%d subordinate=%d\n",
3231 uPrimary, pPciDevSub->uDevFn >> 3, pPciDevSub->uDevFn & 7,
3232 uPrimary, uSecondary, uSubordinate);
3233 if ( uPrimary != PDMPciDevGetByte(pPciDevSub, VBOX_PCI_PRIMARY_BUS)
3234 || uSecondary != PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SECONDARY_BUS)
3235 || uSubordinate != PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SUBORDINATE_BUS))
3236 {
3237 devpciR3InfoIndent(pHlp, iIndentLvl);
3238 pHlp->pfnPrintf(pHlp, "CACHE INCONSISTENCY: primary=%d secondary=%d subordinate=%d\n",
3239 PDMPciDevGetByte(pPciDevSub, VBOX_PCI_PRIMARY_BUS),
3240 PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SECONDARY_BUS),
3241 PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SUBORDINATE_BUS));
3242 }
3243 devpciR3InfoIndent(pHlp, iIndentLvl);
3244 pHlp->pfnPrintf(pHlp, "behind bridge: ");
3245 uint8_t uIoBase = devpciR3GetByte(pPciDevSub, VBOX_PCI_IO_BASE);
3246 uint8_t uIoLimit = devpciR3GetByte(pPciDevSub, VBOX_PCI_IO_LIMIT);
3247 pHlp->pfnPrintf(pHlp, "I/O %#06x..%#06x",
3248 (uIoBase & 0xf0) << 8,
3249 (uIoLimit & 0xf0) << 8 | 0xfff);
3250 if (uIoBase > uIoLimit)
3251 pHlp->pfnPrintf(pHlp, " (IGNORED)");
3252 pHlp->pfnPrintf(pHlp, "\n");
3253 devpciR3InfoIndent(pHlp, iIndentLvl);
3254 pHlp->pfnPrintf(pHlp, "behind bridge: ");
3255 uint32_t uMemoryBase = devpciR3GetWord(pPciDevSub, VBOX_PCI_MEMORY_BASE);
3256 uint32_t uMemoryLimit = devpciR3GetWord(pPciDevSub, VBOX_PCI_MEMORY_LIMIT);
3257 pHlp->pfnPrintf(pHlp, "memory %#010x..%#010x",
3258 (uMemoryBase & 0xfff0) << 16,
3259 (uMemoryLimit & 0xfff0) << 16 | 0xfffff);
3260 if (uMemoryBase > uMemoryLimit)
3261 pHlp->pfnPrintf(pHlp, " (IGNORED)");
3262 pHlp->pfnPrintf(pHlp, "\n");
3263 devpciR3InfoIndent(pHlp, iIndentLvl);
3264 pHlp->pfnPrintf(pHlp, "behind bridge: ");
3265 uint32_t uPrefMemoryRegBase = devpciR3GetWord(pPciDevSub, VBOX_PCI_PREF_MEMORY_BASE);
3266 uint32_t uPrefMemoryRegLimit = devpciR3GetWord(pPciDevSub, VBOX_PCI_PREF_MEMORY_LIMIT);
3267 uint64_t uPrefMemoryBase = (uPrefMemoryRegBase & 0xfff0) << 16;
3268 uint64_t uPrefMemoryLimit = (uPrefMemoryRegLimit & 0xfff0) << 16 | 0xfffff;
3269 if ( (uPrefMemoryRegBase & 0xf) == 1
3270 && (uPrefMemoryRegLimit & 0xf) == 1)
3271 {
3272 uPrefMemoryBase |= (uint64_t)devpciR3GetDWord(pPciDevSub, VBOX_PCI_PREF_BASE_UPPER32) << 32;
3273 uPrefMemoryLimit |= (uint64_t)devpciR3GetDWord(pPciDevSub, VBOX_PCI_PREF_LIMIT_UPPER32) << 32;
3274 pHlp->pfnPrintf(pHlp, "64-bit ");
3275 }
3276 else
3277 pHlp->pfnPrintf(pHlp, "32-bit ");
3278 pHlp->pfnPrintf(pHlp, "prefetch memory %#018llx..%#018llx", uPrefMemoryBase, uPrefMemoryLimit);
3279 if (uPrefMemoryBase > uPrefMemoryLimit)
3280 pHlp->pfnPrintf(pHlp, " (IGNORED)");
3281 pHlp->pfnPrintf(pHlp, "\n");
3282 devpciR3InfoPciBus(pBusSub, pHlp, iIndentLvl + 1, fRegisters);
3283 }
3284 }
3285}
3286
3287
3288/**
3289 * @callback_method_impl{FNDBGFHANDLERDEV, 'pci'}
3290 */
3291DECLCALLBACK(void) devpciR3InfoPci(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3292{
3293 PDEVPCIBUS pBus = DEVINS_2_DEVPCIBUS(pDevIns);
3294
3295 if (pszArgs == NULL || !*pszArgs || !strcmp(pszArgs, "basic"))
3296 devpciR3InfoPciBus(pBus, pHlp, 0 /*iIndentLvl*/, false /*fRegisters*/);
3297 else if (!strcmp(pszArgs, "verbose"))
3298 devpciR3InfoPciBus(pBus, pHlp, 0 /*iIndentLvl*/, true /*fRegisters*/);
3299 else
3300 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'verbose'.\n");
3301}
3302
3303
3304/**
3305 * @callback_method_impl{FNDBGFHANDLERDEV, 'pciirq'}
3306 */
3307DECLCALLBACK(void) devpciR3InfoPciIrq(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3308{
3309 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3310 NOREF(pszArgs);
3311
3312 pHlp->pfnPrintf(pHlp, "PCI I/O APIC IRQ levels:\n");
3313 for (int i = 0; i < DEVPCI_APIC_IRQ_PINS; ++i)
3314 pHlp->pfnPrintf(pHlp, " IRQ%02d: %u\n", 0x10 + i, pPciRoot->auPciApicIrqLevels[i]);
3315}
3316
3317
3318/**
3319 * @interface_method_impl{PDMDEVREG,pfnConstruct}
3320 */
3321static DECLCALLBACK(int) ich9pciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
3322{
3323 RT_NOREF1(iInstance);
3324 Assert(iInstance == 0);
3325 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3326
3327 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3328 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3329 PDEVPCIBUS pBus = &pPciRoot->PciBus;
3330 Assert(ASMMemIsZero(pPciRoot, sizeof(*pPciRoot))); /* code used to memset it for some funny reason. just temp insurance. */
3331
3332 /*
3333 * Validate and read configuration.
3334 */
3335 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IOAPIC|McfgBase|McfgLength", "");
3336
3337 /* query whether we got an IOAPIC */
3338 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &pPciRoot->fUseIoApic, false /** @todo default to true? */);
3339 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to query boolean value \"IOAPIC\"")));
3340
3341 if (!pPciRoot->fUseIoApic)
3342 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Must use IO-APIC with ICH9 chipset"));
3343
3344 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pPciRoot->u64PciConfigMMioAddress, 0);
3345 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"McfgBase\"")));
3346
3347 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pPciRoot->u64PciConfigMMioLength, 0);
3348 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"McfgLength\"")));
3349
3350 Log(("PCI: fUseIoApic=%RTbool McfgBase=%#RX64 McfgLength=%#RX64 fR0Enabled=%RTbool fRCEnabled=%RTbool\n", pPciRoot->fUseIoApic,
3351 pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength, pDevIns->fR0Enabled, pDevIns->fRCEnabled));
3352
3353 /*
3354 * Init data.
3355 */
3356 /* And fill values */
3357 pBusCC->pDevInsR3 = pDevIns;
3358 pPciRoot->hIoPortAddress = NIL_IOMIOPORTHANDLE;
3359 pPciRoot->hIoPortData = NIL_IOMIOPORTHANDLE;
3360 pPciRoot->hIoPortMagic = NIL_IOMIOPORTHANDLE;
3361 pPciRoot->hMmioMcfg = NIL_IOMMMIOHANDLE;
3362 pPciRoot->PciBus.fTypePiix3 = false;
3363 pPciRoot->PciBus.fTypeIch9 = true;
3364 pPciRoot->PciBus.fPureBridge = false;
3365 pPciRoot->PciBus.papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pPciRoot->PciBus.apDevices));
3366 AssertLogRelReturn(pPciRoot->PciBus.papBridgesR3, VERR_NO_MEMORY);
3367
3368 /*
3369 * Disable default device locking.
3370 */
3371 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3372 AssertRCReturn(rc, rc);
3373
3374 /*
3375 * Register bus
3376 */
3377 PDMPCIBUSREGCC PciBusReg;
3378 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3379 PciBusReg.pfnRegisterR3 = devpciR3CommonRegisterDevice;
3380 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
3381 PciBusReg.pfnIORegionRegisterR3 = devpciR3CommonIORegionRegister;
3382 PciBusReg.pfnInterceptConfigAccesses = devpciR3CommonInterceptConfigAccesses;
3383 PciBusReg.pfnConfigRead = devpciR3CommonConfigRead;
3384 PciBusReg.pfnConfigWrite = devpciR3CommonConfigWrite;
3385 PciBusReg.pfnSetIrqR3 = ich9pciSetIrq;
3386 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3387 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBusCC->pPciHlpR3, &pBus->iBus);
3388 if (RT_FAILURE(rc))
3389 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as a PCI Bus"));
3390 Assert(pBus->iBus == 0);
3391 if (pBusCC->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
3392 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
3393 N_("PCI helper version mismatch; got %#x expected %#x"),
3394 pBusCC->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
3395
3396 /*
3397 * Fill in PCI configs and add them to the bus.
3398 */
3399 /** @todo Disabled for now because this causes error messages with Linux guests.
3400 * The guest loads the x38_edac device which tries to map a memory region
3401 * using an address given at place 0x48 - 0x4f in the PCI config space.
3402 * This fails. because we don't register such a region.
3403 */
3404#if 0
3405 /* Host bridge device */
3406 PDMPciDevSetVendorId( &pBus->PciDev, 0x8086); /* Intel */
3407 PDMPciDevSetDeviceId( &pBus->PciDev, 0x29e0); /* Desktop */
3408 PDMPciDevSetRevisionId(&pBus->PciDev, 0x01); /* rev. 01 */
3409 PDMPciDevSetClassBase( &pBus->PciDev, 0x06); /* bridge */
3410 PDMPciDevSetClassSub( &pBus->PciDev, 0x00); /* Host/PCI bridge */
3411 PDMPciDevSetClassProg( &pBus->PciDev, 0x00); /* Host/PCI bridge */
3412 PDMPciDevSetHeaderType(&pBus->PciDev, 0x00); /* bridge */
3413 PDMPciDevSetWord(&pBus->PciDev, VBOX_PCI_SEC_STATUS, 0x0280); /* secondary status */
3414
3415 pBus->PciDev.pDevIns = pDevIns;
3416 /* We register Host<->PCI controller on the bus */
3417 ich9pciRegisterInternal(pBus, 0, &pBus->PciDev, "dram");
3418#endif
3419
3420 /*
3421 * Register I/O ports.
3422 */
3423 static const IOMIOPORTDESC s_aAddrDesc[] = { { "PCI address", "PCI address", NULL, NULL }, { NULL, NULL, NULL, NULL } };
3424 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x0cf8, 1, ich9pciIOPortAddressWrite, ich9pciIOPortAddressRead,
3425 "ICH9 (PCI)", s_aAddrDesc, &pPciRoot->hIoPortAddress);
3426 AssertLogRelRCReturn(rc, rc);
3427
3428 static const IOMIOPORTDESC s_aDataDesc[] = { { "PCI data", "PCI data", NULL, NULL }, { NULL, NULL, NULL, NULL } };
3429 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x0cfc, 4, ich9pciIOPortDataWrite, ich9pciIOPortDataRead,
3430 "ICH9 (PCI)", s_aDataDesc, &pPciRoot->hIoPortData);
3431 AssertLogRelRCReturn(rc, rc);
3432
3433 static const IOMIOPORTDESC s_aMagicDesc[] = { { "PCI magic", NULL, NULL, NULL }, { NULL, NULL, NULL, NULL } };
3434 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x0410, 1, ich9pciR3IOPortMagicPCIWrite, ich9pciR3IOPortMagicPCIRead,
3435 "ICH9 (Fake PCI BIOS trigger)", s_aMagicDesc, &pPciRoot->hIoPortMagic);
3436 AssertLogRelRCReturn(rc, rc);
3437
3438 /*
3439 * MMIO handlers.
3440 */
3441 if (pPciRoot->u64PciConfigMMioAddress != 0)
3442 {
3443 rc = PDMDevHlpMmioCreateAndMap(pDevIns, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength,
3444 ich9pciMcfgMMIOWrite, ich9pciMcfgMMIORead,
3445 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
3446 "MCFG ranges", &pPciRoot->hMmioMcfg);
3447 AssertMsgRCReturn(rc, ("rc=%Rrc %#RX64/%#RX64\n", rc, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength), rc);
3448 }
3449
3450 /*
3451 * Saved state and info handlers.
3452 */
3453 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION,
3454 sizeof(*pBus) + 16*128, "pgm",
3455 NULL, NULL, NULL,
3456 NULL, ich9pciR3SaveExec, NULL,
3457 NULL, ich9pciR3LoadExec, NULL);
3458 AssertRCReturn(rc, rc);
3459
3460 /** @todo other chipset devices shall be registered too */
3461
3462 PDMDevHlpDBGFInfoRegister(pDevIns, "pci",
3463 "Display PCI bus status. Recognizes 'basic' or 'verbose' as arguments, defaults to 'basic'.",
3464 devpciR3InfoPci);
3465 PDMDevHlpDBGFInfoRegister(pDevIns, "pciirq", "Display PCI IRQ state. (no arguments)", devpciR3InfoPciIrq);
3466
3467 return VINF_SUCCESS;
3468}
3469
3470
3471/**
3472 * @interface_method_impl{PDMDEVREG,pfnDestruct}
3473 */
3474static DECLCALLBACK(int) ich9pciR3Destruct(PPDMDEVINS pDevIns)
3475{
3476 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3477 if (pPciRoot->PciBus.papBridgesR3)
3478 {
3479 PDMDevHlpMMHeapFree(pDevIns, pPciRoot->PciBus.papBridgesR3);
3480 pPciRoot->PciBus.papBridgesR3 = NULL;
3481 }
3482 return VINF_SUCCESS;
3483}
3484
3485
3486/**
3487 * @param pDevIns The PCI bus device instance.
3488 * @param pDev The PCI device to reset.
3489 */
3490void devpciR3ResetDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pDev)
3491{
3492 /* Clear regions */
3493 for (int iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
3494 {
3495 PCIIOREGION *pRegion = &pDev->Int.s.aIORegions[iRegion];
3496 if (pRegion->size == 0)
3497 continue;
3498 bool const f64Bit = (pRegion->type & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
3499 == PCI_ADDRESS_SPACE_BAR64;
3500
3501 devpciR3UnmapRegion(pDevIns, pDev, iRegion);
3502
3503 if (f64Bit)
3504 iRegion++;
3505 }
3506
3507 if (pciDevIsPassthrough(pDev))
3508 {
3509 // no reset handler - we can do what we need in PDM reset handler
3510 /// @todo is it correct?
3511 }
3512 else
3513 {
3514 devpciR3SetWord(pDevIns, pDev, VBOX_PCI_COMMAND,
3515 devpciR3GetWord(pDev, VBOX_PCI_COMMAND)
3516 & ~(VBOX_PCI_COMMAND_IO | VBOX_PCI_COMMAND_MEMORY |
3517 VBOX_PCI_COMMAND_MASTER | VBOX_PCI_COMMAND_SPECIAL |
3518 VBOX_PCI_COMMAND_PARITY | VBOX_PCI_COMMAND_SERR |
3519 VBOX_PCI_COMMAND_FAST_BACK | VBOX_PCI_COMMAND_INTX_DISABLE));
3520
3521 /* Bridge device reset handlers processed later */
3522 if (!pciDevIsPci2PciBridge(pDev))
3523 {
3524 devpciR3SetByte(pDevIns, pDev, VBOX_PCI_CACHE_LINE_SIZE, 0x0);
3525 devpciR3SetByte(pDevIns, pDev, VBOX_PCI_INTERRUPT_LINE, 0x0);
3526 }
3527
3528 /* Reset MSI message control. */
3529 if (pciDevIsMsiCapable(pDev))
3530 devpciR3SetWord(pDevIns, pDev, pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL,
3531 devpciR3GetWord(pDev, pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL) & 0xff8e);
3532
3533 /* Reset MSI-X message control. */
3534 if (pciDevIsMsixCapable(pDev))
3535 devpciR3SetWord(pDevIns, pDev, pDev->Int.s.u8MsixCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL,
3536 devpciR3GetWord(pDev, pDev->Int.s.u8MsixCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL) & 0x3fff);
3537 }
3538}
3539
3540/**
3541 * Returns the PCI express encoding for the given PCI Express Device/Port type string.
3542 *
3543 * @returns PCI express encoding.
3544 * @param pszExpressPortType The string identifier for the port/device type.
3545 */
3546static uint8_t ich9pcibridgeR3GetExpressPortTypeFromString(const char *pszExpressPortType)
3547{
3548 if (!RTStrCmp(pszExpressPortType, "EndPtDev"))
3549 return VBOX_PCI_EXP_TYPE_ENDPOINT;
3550 if (!RTStrCmp(pszExpressPortType, "LegEndPtDev"))
3551 return VBOX_PCI_EXP_TYPE_LEG_END;
3552 if (!RTStrCmp(pszExpressPortType, "RootCmplxRootPort"))
3553 return VBOX_PCI_EXP_TYPE_ROOT_PORT;
3554 if (!RTStrCmp(pszExpressPortType, "ExpressSwUpstream"))
3555 return VBOX_PCI_EXP_TYPE_UPSTREAM;
3556 if (!RTStrCmp(pszExpressPortType, "ExpressSwDownstream"))
3557 return VBOX_PCI_EXP_TYPE_DOWNSTREAM;
3558 if (!RTStrCmp(pszExpressPortType, "Express2PciBridge"))
3559 return VBOX_PCI_EXP_TYPE_PCI_BRIDGE;
3560 if (!RTStrCmp(pszExpressPortType, "Pci2ExpressBridge"))
3561 return VBOX_PCI_EXP_TYPE_PCIE_BRIDGE;
3562 if (!RTStrCmp(pszExpressPortType, "RootCmplxIntEp"))
3563 return VBOX_PCI_EXP_TYPE_ROOT_INT_EP;
3564 if (!RTStrCmp(pszExpressPortType, "RootCmplxEc"))
3565 return VBOX_PCI_EXP_TYPE_ROOT_EC;
3566
3567 AssertLogRelMsgFailedReturn(("Unknown express port type specified"), VBOX_PCI_EXP_TYPE_ROOT_INT_EP);
3568}
3569
3570/**
3571 * Recursive worker for ich9pciReset.
3572 *
3573 * @param pDevIns ICH9 bridge (root or PCI-to-PCI) instance.
3574 */
3575static void ich9pciResetBridge(PPDMDEVINS pDevIns)
3576{
3577 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3578
3579 /* PCI-specific reset for each device. */
3580 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
3581 {
3582 if (pBus->apDevices[uDevFn])
3583 devpciR3ResetDevice(pDevIns, pBus->apDevices[uDevFn]);
3584 }
3585
3586 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
3587 {
3588 if (pBus->papBridgesR3[iBridge])
3589 ich9pciResetBridge(pBus->papBridgesR3[iBridge]->Int.s.CTX_SUFF(pDevIns));
3590 }
3591
3592 /* Reset topology config for non-root bridge. Last thing to do, otherwise
3593 * the secondary and subordinate are instantly unreachable. */
3594 if (pBus->iBus != 0)
3595 {
3596 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
3597
3598 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_PRIMARY_BUS, 0);
3599 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_SECONDARY_BUS, 0);
3600 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_SUBORDINATE_BUS, 0);
3601 /* Not resetting the address decoders of the bridge to 0, since the
3602 * PCI-to-PCI Bridge spec says that there is no default value. */
3603 }
3604}
3605
3606
3607/**
3608 * @interface_method_impl{PDMDEVREG,pfnReset}
3609 */
3610static DECLCALLBACK(void) ich9pciReset(PPDMDEVINS pDevIns)
3611{
3612 /* Reset everything under the root bridge. */
3613 ich9pciResetBridge(pDevIns);
3614}
3615
3616
3617/**
3618 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
3619 */
3620static DECLCALLBACK(void *) ich9pcibridgeQueryInterface(PPDMIBASE pInterface, const char *pszIID)
3621{
3622 PPDMDEVINS pDevIns = RT_FROM_MEMBER(pInterface, PDMDEVINS, IBase);
3623 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevIns->IBase);
3624
3625 /* HACK ALERT! Special access to the PDMPCIDEV structure of an ich9pcibridge
3626 instance (see PDMIICH9BRIDGEPDMPCIDEV_IID for details). */
3627 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIICH9BRIDGEPDMPCIDEV, pDevIns->apPciDevs[0]);
3628 return NULL;
3629}
3630
3631
3632/**
3633 * @interface_method_impl{PDMDEVREG,pfnDestruct}
3634 */
3635static DECLCALLBACK(int) ich9pcibridgeR3Destruct(PPDMDEVINS pDevIns)
3636{
3637 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3638 if (pBus->papBridgesR3)
3639 {
3640 PDMDevHlpMMHeapFree(pDevIns, pBus->papBridgesR3);
3641 pBus->papBridgesR3 = NULL;
3642 }
3643 return VINF_SUCCESS;
3644}
3645
3646
3647/**
3648 * @interface_method_impl{PDMDEVREG,pfnConstruct}
3649 */
3650static DECLCALLBACK(int) ich9pcibridgeR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
3651{
3652 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3653
3654 /*
3655 * Validate and read configuration.
3656 */
3657 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "ExpressEnabled|ExpressPortType", "");
3658
3659 /* check if we're supposed to implement a PCIe bridge. */
3660 bool fExpress;
3661 int rc = CFGMR3QueryBoolDef(pCfg, "ExpressEnabled", &fExpress, false);
3662 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to query boolean value \"ExpressEnabled\"")));
3663
3664 char szExpressPortType[80];
3665 rc = CFGMR3QueryStringDef(pCfg, "ExpressPortType", szExpressPortType, sizeof(szExpressPortType), "RootCmplxIntEp");
3666 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: failed to read \"ExpressPortType\" as string")));
3667
3668 uint8_t const uExpressPortType = ich9pcibridgeR3GetExpressPortTypeFromString(szExpressPortType);
3669 Log(("PCI/bridge#%u: fR0Enabled=%RTbool fRCEnabled=%RTbool fExpress=%RTbool uExpressPortType=%u (%s)\n",
3670 iInstance, pDevIns->fR0Enabled, pDevIns->fRCEnabled, fExpress, uExpressPortType, szExpressPortType));
3671
3672 /*
3673 * Init data and register the PCI bus.
3674 */
3675 pDevIns->IBase.pfnQueryInterface = ich9pcibridgeQueryInterface;
3676
3677 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3678 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3679
3680 pBus->fTypePiix3 = false;
3681 pBus->fTypeIch9 = true;
3682 pBus->fPureBridge = true;
3683 pBusCC->pDevInsR3 = pDevIns;
3684 pBus->papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pBus->apDevices));
3685 AssertLogRelReturn(pBus->papBridgesR3, VERR_NO_MEMORY);
3686
3687 PDMPCIBUSREGCC PciBusReg;
3688 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3689 PciBusReg.pfnRegisterR3 = devpcibridgeR3CommonRegisterDevice;
3690 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
3691 PciBusReg.pfnIORegionRegisterR3 = devpciR3CommonIORegionRegister;
3692 PciBusReg.pfnInterceptConfigAccesses = devpciR3CommonInterceptConfigAccesses;
3693 PciBusReg.pfnConfigWrite = devpciR3CommonConfigWrite;
3694 PciBusReg.pfnConfigRead = devpciR3CommonConfigRead;
3695 PciBusReg.pfnSetIrqR3 = ich9pcibridgeSetIrq;
3696 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3697 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBusCC->pPciHlpR3, &pBus->iBus);
3698 if (RT_FAILURE(rc))
3699 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as a PCI Bus"));
3700 Assert(pBus->iBus == (uint32_t)iInstance + 1); /* Can be removed when adding support for multiple bridge implementations. */
3701 if (pBusCC->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
3702 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
3703 N_("PCI helper version mismatch; got %#x expected %#x"),
3704 pBusCC->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
3705
3706 LogRel(("PCI: Registered bridge instance #%u as PDM bus no %u.\n", iInstance, pBus->iBus));
3707
3708
3709 /* Disable default device locking. */
3710 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3711 AssertRCReturn(rc, rc);
3712
3713 /*
3714 * Fill in PCI configs and add them to the bus.
3715 */
3716 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
3717 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
3718
3719 PDMPciDevSetVendorId( pPciDev, 0x8086); /* Intel */
3720 if (fExpress)
3721 {
3722 PDMPciDevSetDeviceId(pPciDev, 0x29e1); /* 82X38/X48 Express Host-Primary PCI Express Bridge. */
3723 PDMPciDevSetRevisionId(pPciDev, 0x01);
3724 }
3725 else
3726 {
3727 PDMPciDevSetDeviceId(pPciDev, 0x2448); /* 82801 Mobile PCI bridge. */
3728 PDMPciDevSetRevisionId(pPciDev, 0xf2);
3729 }
3730 PDMPciDevSetClassSub( pPciDev, 0x04); /* pci2pci */
3731 PDMPciDevSetClassBase( pPciDev, 0x06); /* PCI_bridge */
3732 if (fExpress)
3733 PDMPciDevSetClassProg(pPciDev, 0x00); /* Normal decoding. */
3734 else
3735 PDMPciDevSetClassProg(pPciDev, 0x01); /* Supports subtractive decoding. */
3736 PDMPciDevSetHeaderType(pPciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
3737 if (fExpress)
3738 {
3739 PDMPciDevSetCommand(pPciDev, VBOX_PCI_COMMAND_SERR);
3740 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST); /* Has capabilities. */
3741 PDMPciDevSetByte(pPciDev, VBOX_PCI_CACHE_LINE_SIZE, 8); /* 32 bytes */
3742 /* PCI Express */
3743 PDMPciDevSetByte(pPciDev, 0xa0 + 0, VBOX_PCI_CAP_ID_EXP); /* PCI_Express */
3744 PDMPciDevSetByte(pPciDev, 0xa0 + 1, 0); /* next */
3745 PDMPciDevSetWord(pPciDev, 0xa0 + 2,
3746 /* version */ 0x2
3747 | (uExpressPortType << 4));
3748 PDMPciDevSetDWord(pPciDev, 0xa0 + 4, VBOX_PCI_EXP_DEVCAP_RBE); /* Device capabilities. */
3749 PDMPciDevSetWord(pPciDev, 0xa0 + 8, 0x0000); /* Device control. */
3750 PDMPciDevSetWord(pPciDev, 0xa0 + 10, 0x0000); /* Device status. */
3751 PDMPciDevSetDWord(pPciDev, 0xa0 + 12,
3752 /* Max Link Speed */ 2
3753 | /* Maximum Link Width */ (16 << 4)
3754 | /* Active State Power Management (ASPM) Sopport */ (0 << 10)
3755 | VBOX_PCI_EXP_LNKCAP_LBNC
3756 | /* Port Number */ ((2 + iInstance) << 24)); /* Link capabilities. */
3757 PDMPciDevSetWord(pPciDev, 0xa0 + 16, VBOX_PCI_EXP_LNKCTL_CLOCK); /* Link control. */
3758 PDMPciDevSetWord(pPciDev, 0xa0 + 18,
3759 /* Current Link Speed */ 2
3760 | /* Negotiated Link Width */ (16 << 4)
3761 | VBOX_PCI_EXP_LNKSTA_SL_CLK); /* Link status. */
3762 PDMPciDevSetDWord(pPciDev, 0xa0 + 20,
3763 /* Slot Power Limit Value */ (75 << 7)
3764 | /* Physical Slot Number */ (0 << 19)); /* Slot capabilities. */
3765 PDMPciDevSetWord(pPciDev, 0xa0 + 24, 0x0000); /* Slot control. */
3766 PDMPciDevSetWord(pPciDev, 0xa0 + 26, 0x0000); /* Slot status. */
3767 PDMPciDevSetWord(pPciDev, 0xa0 + 28, 0x0000); /* Root control. */
3768 PDMPciDevSetWord(pPciDev, 0xa0 + 30, 0x0000); /* Root capabilities. */
3769 PDMPciDevSetDWord(pPciDev, 0xa0 + 32, 0x00000000); /* Root status. */
3770 PDMPciDevSetDWord(pPciDev, 0xa0 + 36, 0x00000000); /* Device capabilities 2. */
3771 PDMPciDevSetWord(pPciDev, 0xa0 + 40, 0x0000); /* Device control 2. */
3772 PDMPciDevSetWord(pPciDev, 0xa0 + 42, 0x0000); /* Device status 2. */
3773 PDMPciDevSetDWord(pPciDev, 0xa0 + 44,
3774 /* Supported Link Speeds Vector */ (2 << 1)); /* Link capabilities 2. */
3775 PDMPciDevSetWord(pPciDev, 0xa0 + 48,
3776 /* Target Link Speed */ 2); /* Link control 2. */
3777 PDMPciDevSetWord(pPciDev, 0xa0 + 50, 0x0000); /* Link status 2. */
3778 PDMPciDevSetDWord(pPciDev, 0xa0 + 52, 0x00000000); /* Slot capabilities 2. */
3779 PDMPciDevSetWord(pPciDev, 0xa0 + 56, 0x0000); /* Slot control 2. */
3780 PDMPciDevSetWord(pPciDev, 0xa0 + 58, 0x0000); /* Slot status 2. */
3781 PDMPciDevSetCapabilityList(pPciDev, 0xa0);
3782 }
3783 else
3784 {
3785 PDMPciDevSetCommand(pPciDev, 0x00);
3786 PDMPciDevSetStatus(pPciDev, 0x20); /* 66MHz Capable. */
3787 }
3788 PDMPciDevSetInterruptLine(pPciDev, 0x00); /* This device does not assert interrupts. */
3789
3790 /*
3791 * This device does not generate interrupts. Interrupt delivery from
3792 * devices attached to the bus is unaffected.
3793 */
3794 PDMPciDevSetInterruptPin (pPciDev, 0x00);
3795
3796 if (fExpress)
3797 {
3798 /** @todo r=klaus set up the PCIe config space beyond the old 256 byte
3799 * limit, containing additional capability descriptors. */
3800 }
3801
3802 /*
3803 * Register this PCI bridge. The called function will take care on which bus we will get registered.
3804 */
3805 rc = PDMDevHlpPCIRegisterEx(pDevIns, pPciDev, PDMPCIDEVREG_F_PCI_BRIDGE, PDMPCIDEVREG_DEV_NO_FIRST_UNUSED,
3806 PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, "ich9pcibridge");
3807 AssertLogRelRCReturn(rc, rc);
3808
3809 pPciDev->Int.s.pfnBridgeConfigRead = ich9pcibridgeConfigRead;
3810 pPciDev->Int.s.pfnBridgeConfigWrite = ich9pcibridgeConfigWrite;
3811
3812 /*
3813 * Register SSM handlers. We use the same saved state version as for the host bridge
3814 * to make changes easier.
3815 */
3816 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION,
3817 sizeof(*pBus) + 16*128,
3818 "pgm" /* before */,
3819 NULL, NULL, NULL,
3820 NULL, ich9pcibridgeR3SaveExec, NULL,
3821 NULL, ich9pcibridgeR3LoadExec, NULL);
3822 AssertLogRelRCReturn(rc, rc);
3823
3824 return VINF_SUCCESS;
3825}
3826
3827#else /* !IN_RING3 */
3828
3829/**
3830 * @interface_method_impl{PDMDEVREGR0,pfnConstruct}
3831 */
3832DECLCALLBACK(int) ich9pciRZConstruct(PPDMDEVINS pDevIns)
3833{
3834 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3835 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3836 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3837
3838 /* Mirror the ring-3 device lock disabling: */
3839 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3840 AssertRCReturn(rc, rc);
3841
3842 /* Set up the RZ PCI bus callbacks: */
3843 PDMPCIBUSREGCC PciBusReg;
3844 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3845 PciBusReg.iBus = pPciRoot->PciBus.iBus;
3846 PciBusReg.pfnSetIrq = ich9pciSetIrq;
3847 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3848 rc = PDMDevHlpPCIBusSetUpContext(pDevIns, &PciBusReg, &pBusCC->CTX_SUFF(pPciHlp));
3849 AssertRCReturn(rc, rc);
3850
3851 /* Set up I/O port callbacks, except for the magic port: */
3852 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pPciRoot->hIoPortAddress, ich9pciIOPortAddressWrite, ich9pciIOPortAddressRead, NULL);
3853 AssertLogRelRCReturn(rc, rc);
3854
3855 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pPciRoot->hIoPortData, ich9pciIOPortDataWrite, ich9pciIOPortDataRead, NULL);
3856 AssertLogRelRCReturn(rc, rc);
3857
3858 /* Set up MMIO callbacks: */
3859 if (pPciRoot->hMmioMcfg != NIL_IOMMMIOHANDLE)
3860 {
3861 rc = PDMDevHlpMmioSetUpContext(pDevIns, pPciRoot->hMmioMcfg, ich9pciMcfgMMIOWrite, ich9pciMcfgMMIORead, NULL /*pvUser*/);
3862 AssertLogRelRCReturn(rc, rc);
3863 }
3864
3865 return rc;
3866}
3867
3868
3869/**
3870 * @interface_method_impl{PDMDEVREGR0,pfnConstruct}
3871 */
3872DECLCALLBACK(int) ich9pcibridgeRZConstruct(PPDMDEVINS pDevIns)
3873{
3874 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3875 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3876 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3877
3878 /* Mirror the ring-3 device lock disabling: */
3879 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3880 AssertRCReturn(rc, rc);
3881
3882 /* Set up the RZ PCI bus callbacks: */
3883 PDMPCIBUSREGCC PciBusReg;
3884 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3885 PciBusReg.iBus = pBus->iBus;
3886 PciBusReg.pfnSetIrq = ich9pcibridgeSetIrq;
3887 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3888 rc = PDMDevHlpPCIBusSetUpContext(pDevIns, &PciBusReg, &pBusCC->CTX_SUFF(pPciHlp));
3889 AssertRCReturn(rc, rc);
3890
3891 return rc;
3892}
3893
3894#endif /* !IN_RING3 */
3895
3896/**
3897 * The PCI bus device registration structure.
3898 */
3899const PDMDEVREG g_DevicePciIch9 =
3900{
3901 /* .u32Version = */ PDM_DEVREG_VERSION,
3902 /* .uReserved0 = */ 0,
3903 /* .szName = */ "ich9pci",
3904 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
3905 /* .fClass = */ PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
3906 /* .cMaxInstances = */ 1,
3907 /* .uSharedVersion = */ 42,
3908 /* .cbInstanceShared = */ sizeof(DEVPCIROOT),
3909 /* .cbInstanceCC = */ sizeof(CTX_SUFF(DEVPCIBUS)),
3910 /* .cbInstanceRC = */ sizeof(DEVPCIBUSRC),
3911 /* .cMaxPciDevices = */ 1,
3912 /* .cMaxMsixVectors = */ 0,
3913 /* .pszDescription = */ "ICH9 PCI bridge",
3914#if defined(IN_RING3)
3915 /* .pszRCMod = */ "VBoxDDRC.rc",
3916 /* .pszR0Mod = */ "VBoxDDR0.r0",
3917 /* .pfnConstruct = */ ich9pciR3Construct,
3918 /* .pfnDestruct = */ ich9pciR3Destruct,
3919 /* .pfnRelocate = */ NULL,
3920 /* .pfnMemSetup = */ NULL,
3921 /* .pfnPowerOn = */ NULL,
3922 /* .pfnReset = */ ich9pciReset,
3923 /* .pfnSuspend = */ NULL,
3924 /* .pfnResume = */ NULL,
3925 /* .pfnAttach = */ NULL,
3926 /* .pfnDetach = */ NULL,
3927 /* .pfnQueryInterface = */ NULL,
3928 /* .pfnInitComplete = */ NULL,
3929 /* .pfnPowerOff = */ NULL,
3930 /* .pfnSoftReset = */ NULL,
3931 /* .pfnReserved0 = */ NULL,
3932 /* .pfnReserved1 = */ NULL,
3933 /* .pfnReserved2 = */ NULL,
3934 /* .pfnReserved3 = */ NULL,
3935 /* .pfnReserved4 = */ NULL,
3936 /* .pfnReserved5 = */ NULL,
3937 /* .pfnReserved6 = */ NULL,
3938 /* .pfnReserved7 = */ NULL,
3939#elif defined(IN_RING0)
3940 /* .pfnEarlyConstruct = */ NULL,
3941 /* .pfnConstruct = */ ich9pciRZConstruct,
3942 /* .pfnDestruct = */ NULL,
3943 /* .pfnFinalDestruct = */ NULL,
3944 /* .pfnRequest = */ NULL,
3945 /* .pfnReserved0 = */ NULL,
3946 /* .pfnReserved1 = */ NULL,
3947 /* .pfnReserved2 = */ NULL,
3948 /* .pfnReserved3 = */ NULL,
3949 /* .pfnReserved4 = */ NULL,
3950 /* .pfnReserved5 = */ NULL,
3951 /* .pfnReserved6 = */ NULL,
3952 /* .pfnReserved7 = */ NULL,
3953#elif defined(IN_RC)
3954 /* .pfnConstruct = */ ich9pciRZConstruct,
3955 /* .pfnReserved0 = */ NULL,
3956 /* .pfnReserved1 = */ NULL,
3957 /* .pfnReserved2 = */ NULL,
3958 /* .pfnReserved3 = */ NULL,
3959 /* .pfnReserved4 = */ NULL,
3960 /* .pfnReserved5 = */ NULL,
3961 /* .pfnReserved6 = */ NULL,
3962 /* .pfnReserved7 = */ NULL,
3963#else
3964# error "Not in IN_RING3, IN_RING0 or IN_RC!"
3965#endif
3966 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
3967};
3968
3969/**
3970 * The device registration structure
3971 * for the PCI-to-PCI bridge.
3972 */
3973const PDMDEVREG g_DevicePciIch9Bridge =
3974{
3975 /* .u32Version = */ PDM_DEVREG_VERSION,
3976 /* .uReserved0 = */ 0,
3977 /* .szName = */ "ich9pcibridge",
3978 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
3979 /* .fClass = */ PDM_DEVREG_CLASS_BUS_PCI,
3980 /* .cMaxInstances = */ ~0U,
3981 /* .uSharedVersion = */ 42,
3982 /* .cbInstanceShared = */ sizeof(DEVPCIBUS),
3983 /* .cbInstanceCC = */ sizeof(CTX_SUFF(DEVPCIBUS)),
3984 /* .cbInstanceRC = */ 0,
3985 /* .cMaxPciDevices = */ 1,
3986 /* .cMaxMsixVectors = */ 0,
3987 /* .pszDescription = */ "ICH9 PCI to PCI bridge",
3988#if defined(IN_RING3)
3989 /* .pszRCMod = */ "VBoxDDRC.rc",
3990 /* .pszR0Mod = */ "VBoxDDR0.r0",
3991 /* .pfnConstruct = */ ich9pcibridgeR3Construct,
3992 /* .pfnDestruct = */ ich9pcibridgeR3Destruct,
3993 /* .pfnRelocate = */ NULL,
3994 /* .pfnMemSetup = */ NULL,
3995 /* .pfnPowerOn = */ NULL,
3996 /* .pfnReset = */ NULL, /* Must be NULL, to make sure only bus driver handles reset */
3997 /* .pfnSuspend = */ NULL,
3998 /* .pfnResume = */ NULL,
3999 /* .pfnAttach = */ NULL,
4000 /* .pfnDetach = */ NULL,
4001 /* .pfnQueryInterface = */ NULL,
4002 /* .pfnInitComplete = */ NULL,
4003 /* .pfnPowerOff = */ NULL,
4004 /* .pfnSoftReset = */ NULL,
4005 /* .pfnReserved0 = */ NULL,
4006 /* .pfnReserved1 = */ NULL,
4007 /* .pfnReserved2 = */ NULL,
4008 /* .pfnReserved3 = */ NULL,
4009 /* .pfnReserved4 = */ NULL,
4010 /* .pfnReserved5 = */ NULL,
4011 /* .pfnReserved6 = */ NULL,
4012 /* .pfnReserved7 = */ NULL,
4013#elif defined(IN_RING0)
4014 /* .pfnEarlyConstruct = */ NULL,
4015 /* .pfnConstruct = */ ich9pcibridgeRZConstruct,
4016 /* .pfnDestruct = */ NULL,
4017 /* .pfnFinalDestruct = */ NULL,
4018 /* .pfnRequest = */ NULL,
4019 /* .pfnReserved0 = */ NULL,
4020 /* .pfnReserved1 = */ NULL,
4021 /* .pfnReserved2 = */ NULL,
4022 /* .pfnReserved3 = */ NULL,
4023 /* .pfnReserved4 = */ NULL,
4024 /* .pfnReserved5 = */ NULL,
4025 /* .pfnReserved6 = */ NULL,
4026 /* .pfnReserved7 = */ NULL,
4027#elif defined(IN_RC)
4028 /* .pfnConstruct = */ ich9pcibridgeRZConstruct,
4029 /* .pfnReserved0 = */ NULL,
4030 /* .pfnReserved1 = */ NULL,
4031 /* .pfnReserved2 = */ NULL,
4032 /* .pfnReserved3 = */ NULL,
4033 /* .pfnReserved4 = */ NULL,
4034 /* .pfnReserved5 = */ NULL,
4035 /* .pfnReserved6 = */ NULL,
4036 /* .pfnReserved7 = */ NULL,
4037#else
4038# error "Not in IN_RING3, IN_RING0 or IN_RC!"
4039#endif
4040 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
4041};
4042
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette