VirtualBox

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

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

MsixCommon: Refactored the MMIO bits, changing the registration flags and code to make more sense (don't know it is correct). bugref:9218

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