VirtualBox

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

Last change on this file since 100347 was 99775, checked in by vboxsync, 22 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

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