VirtualBox

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

Last change on this file since 81375 was 81375, checked in by vboxsync, 5 years ago

IOM,PDM,PCI: Making new MMIO code work with PCI. bugref:9218

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