VirtualBox

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

Last change on this file since 100897 was 100897, checked in by vboxsync, 16 months ago

Devices/Bus/DevPciIch9: Initialize the PCI bus type with the correct enum, r158637 regression

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