VirtualBox

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

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