VirtualBox

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

Last change on this file since 89476 was 85912, checked in by vboxsync, 4 years ago

AMD IOMMU: bugref:9654 Split IOMMU data into relevant headers to share it with other devices/VMM (ACPI, chipset, maybe Main and firmware in the future).

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