VirtualBox

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

Last change on this file since 67680 was 67680, checked in by vboxsync, 8 years ago

DevPciIch9: also print base/sub class on 'info pci'

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