VirtualBox

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

Last change on this file since 77813 was 77300, checked in by vboxsync, 6 years ago

DevVGA,PCI,PGM: Hacks for making it possible to load saved states of the VBoxSVGA device with the 'wrong' BAR layout. bugref:9359

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