VirtualBox

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

Last change on this file since 103914 was 103005, checked in by vboxsync, 9 months ago

iprt/asm.h,*: Split out the ASMMem* and related stuff into a separate header, asm-mem.h, so that we can get the RT_ASM_PAGE_SIZE stuff out of the way.

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

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