VirtualBox

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

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

Devices/PCI: Device model refactoring, part I. bugref:9218

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