VirtualBox

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

最後變更 在這個檔案從82116是 82073,由 vboxsync 提交於 5 年 前

DevPCI: Added a special return code to FNPCIIOREGIONMAP for telling the bus that the callback did the mapping and it should not use the registered handle to do so again. Needed for VGA (alternative was to reorder the callout order). bugref:9218

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

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