VirtualBox

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

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

DevPci: There are no more old style I/O port or MMIOEx ranges anymore. [build fix] bugref:9218

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

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