VirtualBox

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

Last change on this file since 94068 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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

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