VirtualBox

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

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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

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