VirtualBox

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

Last change on this file since 50782 was 50654, checked in by vboxsync, 11 years ago

Add some comments and minor cosmetics to improve chances of mere
mortals to understand what's going on. No functional change intended.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 109.1 KB
Line 
1/* $Id: DevPciIch9.cpp 50654 2014-02-28 16:19:29Z vboxsync $ */
2/** @file
3 * DevPCI - ICH9 southbridge PCI bus emulation device.
4 *
5 * @note bird: I've cleaned up DevPCI.cpp to some extend, this file has not
6 * be cleaned up and because of pending code merge.
7 */
8
9/*
10 * Copyright (C) 2010-2013 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 */
20
21/*******************************************************************************
22* Header Files *
23*******************************************************************************/
24#define LOG_GROUP LOG_GROUP_DEV_PCI
25/* Hack to get PCIDEVICEINT declared at the right point - include "PCIInternal.h". */
26#define PCI_INCLUDE_PRIVATE
27#define PCIBus ICH9PCIBus
28#include <VBox/pci.h>
29#include <VBox/msi.h>
30#include <VBox/vmm/pdmdev.h>
31#include <iprt/asm.h>
32#include <iprt/assert.h>
33#include <iprt/string.h>
34#ifdef IN_RING3
35#include <iprt/alloc.h>
36#endif
37
38#include "VBoxDD.h"
39#include "MsiCommon.h"
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45/**
46 * PCI Bus instance.
47 */
48typedef struct ICH9PCIBus
49{
50 /** Bus number. */
51 int32_t iBus;
52 /** Number of bridges attached to the bus. */
53 uint32_t cBridges;
54
55 /** Array of PCI devices. We assume 32 slots, each with 8 functions. */
56 R3PTRTYPE(PPCIDEVICE) apDevices[256];
57 /** Array of bridges attached to the bus. */
58 R3PTRTYPE(PPCIDEVICE *) papBridgesR3;
59
60 /** R3 pointer to the device instance. */
61 PPDMDEVINSR3 pDevInsR3;
62 /** Pointer to the PCI R3 helpers. */
63 PCPDMPCIHLPR3 pPciHlpR3;
64
65 /** R0 pointer to the device instance. */
66 PPDMDEVINSR0 pDevInsR0;
67 /** Pointer to the PCI R0 helpers. */
68 PCPDMPCIHLPR0 pPciHlpR0;
69
70 /** RC pointer to the device instance. */
71 PPDMDEVINSRC pDevInsRC;
72 /** Pointer to the PCI RC helpers. */
73 PCPDMPCIHLPRC pPciHlpRC;
74
75 /** The PCI device for the PCI bridge. */
76 PCIDEVICE aPciDev;
77
78} ICH9PCIBUS, *PICH9PCIBUS;
79
80
81/** @def PCI_APIC_IRQ_PINS
82 * Number of pins for interrupts if the APIC is used.
83 */
84#define PCI_APIC_IRQ_PINS 8
85
86/**
87 * PCI Globals - This is the host-to-pci bridge and the root bus.
88 */
89typedef struct
90{
91 /** R3 pointer to the device instance. */
92 PPDMDEVINSR3 pDevInsR3;
93 /** R0 pointer to the device instance. */
94 PPDMDEVINSR0 pDevInsR0;
95 /** RC pointer to the device instance. */
96 PPDMDEVINSRC pDevInsRC;
97
98#if HC_ARCH_BITS == 64
99 uint32_t Alignment0;
100#endif
101
102 /** Value latched in Configuration Address Port (0CF8h) */
103 uint32_t uConfigReg;
104
105 /** I/O APIC irq levels */
106 volatile uint32_t uaPciApicIrqLevels[PCI_APIC_IRQ_PINS];
107
108#if 1 /* Will be moved into the BIOS soon. */
109 /** The next I/O port address which the PCI BIOS will use. */
110 uint32_t uPciBiosIo;
111 /** The next MMIO address which the PCI BIOS will use. */
112 uint32_t uPciBiosMmio;
113 /** Actual bus number. */
114 uint8_t uBus;
115#endif
116 /** Physical address of PCI config space MMIO region. */
117 uint64_t u64PciConfigMMioAddress;
118 /** Length of PCI config space MMIO region. */
119 uint64_t u64PciConfigMMioLength;
120
121 /** PCI bus which is attached to the host-to-PCI bridge. */
122 ICH9PCIBUS aPciBus;
123} ICH9PCIGLOBALS, *PICH9PCIGLOBALS;
124
125
126/**
127 * PCI configuration space address.
128 */
129typedef struct
130{
131 uint8_t iBus;
132 uint8_t iDeviceFunc;
133 uint16_t iRegister;
134} PciAddress;
135
136#ifndef VBOX_DEVICE_STRUCT_TESTCASE
137
138/*******************************************************************************
139* Defined Constants And Macros *
140*******************************************************************************/
141
142/** @def VBOX_ICH9PCI_SAVED_STATE_VERSION
143 * Saved state version of the ICH9 PCI bus device.
144 */
145#define VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI 1
146#define VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI 2
147#define VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI
148
149/** Converts a bus instance pointer to a device instance pointer. */
150#define PCIBUS_2_DEVINS(pPciBus) ((pPciBus)->CTX_SUFF(pDevIns))
151/** Converts a device instance pointer to a ICH9PCIGLOBALS pointer. */
152#define DEVINS_2_PCIGLOBALS(pDevIns) ((PICH9PCIGLOBALS)(PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS)))
153/** Converts a device instance pointer to a PCIBUS pointer. */
154#define DEVINS_2_PCIBUS(pDevIns) ((PICH9PCIBUS)(&PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS)->aPciBus))
155/** Converts a pointer to a PCI root bus instance to a PCIGLOBALS pointer. */
156#define PCIROOTBUS_2_PCIGLOBALS(pPciBus) ( (PICH9PCIGLOBALS)((uintptr_t)(pPciBus) - RT_OFFSETOF(ICH9PCIGLOBALS, aPciBus)) )
157
158/** @def PCI_LOCK
159 * Acquires the PDM lock. This is a NOP if locking is disabled. */
160/** @def PCI_UNLOCK
161 * Releases the PDM lock. This is a NOP if locking is disabled. */
162#define PCI_LOCK(pDevIns, rc) \
163 do { \
164 int rc2 = DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnLock((pDevIns), rc); \
165 if (rc2 != VINF_SUCCESS) \
166 return rc2; \
167 } while (0)
168#define PCI_UNLOCK(pDevIns) \
169 DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnUnlock(pDevIns)
170
171/* Prototypes */
172static void ich9pciSetIrqInternal(PICH9PCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev,
173 int iIrq, int iLevel, uint32_t uTagSrc);
174#ifdef IN_RING3
175static void ich9pcibridgeReset(PPDMDEVINS pDevIns);
176static int ich9pciRegisterInternal(PICH9PCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName);
177static void ich9pciUpdateMappings(PCIDevice *pDev);
178static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PCIDevice *aDev, uint32_t u32Address, unsigned len);
179DECLINLINE(PPCIDEVICE) ich9pciFindBridge(PICH9PCIBUS pBus, uint8_t iBus);
180static void ich9pciBiosInitDevice(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn);
181#endif
182
183// See 7.2.2. PCI Express Enhanced Configuration Mechanism for details of address
184// mapping, we take n=6 approach
185DECLINLINE(void) ich9pciPhysToPciAddr(PICH9PCIGLOBALS pGlobals, RTGCPHYS GCPhysAddr, PciAddress* pPciAddr)
186{
187 NOREF(pGlobals);
188 pPciAddr->iBus = (GCPhysAddr >> 20) & ((1<<6) - 1);
189 pPciAddr->iDeviceFunc = (GCPhysAddr >> 12) & ((1<<(5+3)) - 1); // 5 bits - device, 3 bits - function
190 pPciAddr->iRegister = (GCPhysAddr >> 0) & ((1<<(6+4+2)) - 1); // 6 bits - register, 4 bits - extended register, 2 bits -Byte Enable
191}
192
193DECLINLINE(void) ich9pciStateToPciAddr(PICH9PCIGLOBALS pGlobals, RTGCPHYS addr, PciAddress* pPciAddr)
194{
195 pPciAddr->iBus = (pGlobals->uConfigReg >> 16) & 0xff;
196 pPciAddr->iDeviceFunc = (pGlobals->uConfigReg >> 8) & 0xff;
197 pPciAddr->iRegister = (pGlobals->uConfigReg & 0xfc) | (addr & 3);
198}
199
200PDMBOTHCBDECL(void) ich9pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
201{
202 ich9pciSetIrqInternal(PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS), pPciDev->devfn, pPciDev, iIrq, iLevel, uTagSrc);
203}
204
205PDMBOTHCBDECL(void) ich9pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
206{
207 /*
208 * The PCI-to-PCI bridge specification defines how the interrupt pins
209 * are routed from the secondary to the primary bus (see chapter 9).
210 * iIrq gives the interrupt pin the pci device asserted.
211 * We change iIrq here according to the spec and call the SetIrq function
212 * of our parent passing the device which asserted the interrupt instead of the device of the bridge.
213 */
214 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
215 PPCIDEVICE pPciDevBus = pPciDev;
216 int iIrqPinBridge = iIrq;
217 uint8_t uDevFnBridge = 0;
218
219 /* Walk the chain until we reach the host bus. */
220 do
221 {
222 uDevFnBridge = pBus->aPciDev.devfn;
223 iIrqPinBridge = ((pPciDevBus->devfn >> 3) + iIrqPinBridge) & 3;
224
225 /* Get the parent. */
226 pBus = pBus->aPciDev.Int.s.CTX_SUFF(pBus);
227 pPciDevBus = &pBus->aPciDev;
228 } while (pBus->iBus != 0);
229
230 AssertMsgReturnVoid(pBus->iBus == 0, ("This is not the host pci bus iBus=%d\n", pBus->iBus));
231 ich9pciSetIrqInternal(PCIROOTBUS_2_PCIGLOBALS(pBus), uDevFnBridge, pPciDev, iIrqPinBridge, iLevel, uTagSrc);
232}
233
234
235/**
236 * Port I/O Handler for PCI address OUT operations.
237 *
238 * Emulates writes to Configuration Address Port at 0CF8h for
239 * Configuration Mechanism #1.
240 *
241 * @returns VBox status code.
242 *
243 * @param pDevIns ICH9 device instance.
244 * @param pvUser User argument - ignored.
245 * @param uPort Port number used for the OUT operation.
246 * @param u32 The value to output.
247 * @param cb The value size in bytes.
248 */
249PDMBOTHCBDECL(int) ich9pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
250{
251 LogFlow(("ich9pciIOPortAddressWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
252 NOREF(pvUser);
253 if (cb == 4)
254 {
255 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
256
257 /*
258 * bits [1:0] are hard-wired, read-only and must return zeroes
259 * when read.
260 */
261 u32 &= ~3;
262
263 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
264 pThis->uConfigReg = u32;
265 PCI_UNLOCK(pDevIns);
266 }
267
268 return VINF_SUCCESS;
269}
270
271
272/**
273 * Port I/O Handler for PCI address IN operations.
274 *
275 * Emulates reads from Configuration Address Port at 0CF8h for
276 * Configuration Mechanism #1.
277 *
278 * @returns VBox status code.
279 *
280 * @param pDevIns ICH9 device instance.
281 * @param pvUser User argument - ignored.
282 * @param uPort Port number used for the IN operation.
283 * @param pu32 Where to store the result.
284 * @param cb Number of bytes read.
285 */
286PDMBOTHCBDECL(int) ich9pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
287{
288 NOREF(pvUser);
289 if (cb == 4)
290 {
291 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
292
293 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_READ);
294 *pu32 = pThis->uConfigReg;
295 PCI_UNLOCK(pDevIns);
296
297 LogFlow(("ich9pciIOPortAddressRead: Port=%#x cb=%d -> %#x\n", Port, cb, *pu32));
298 return VINF_SUCCESS;
299 }
300
301 Log(("ich9pciIOPortAddressRead: Port=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", Port, cb));
302 return VERR_IOM_IOPORT_UNUSED;
303}
304
305
306/*
307 * Perform configuration space write.
308 */
309static int ich9pciDataWriteAddr(PICH9PCIGLOBALS pGlobals, PciAddress* pAddr,
310 uint32_t val, int cb, int rcReschedule)
311{
312 int rc = VINF_SUCCESS;
313#ifdef IN_RING3
314 NOREF(rcReschedule);
315#endif
316
317 if (pAddr->iBus != 0) /* forward to subordinate bus */
318 {
319 if (pGlobals->aPciBus.cBridges)
320 {
321#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
322 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(&pGlobals->aPciBus, pAddr->iBus);
323 if (pBridgeDevice)
324 {
325 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
326 pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, pAddr->iBus, pAddr->iDeviceFunc,
327 pAddr->iRegister, val, cb);
328 }
329#else
330 rc = rcReschedule;
331#endif
332 }
333 }
334 else /* forward to directly connected device */
335 {
336 R3PTRTYPE(PCIDevice *) aDev = pGlobals->aPciBus.apDevices[pAddr->iDeviceFunc];
337 if (aDev)
338 {
339#ifdef IN_RING3
340 aDev->Int.s.pfnConfigWrite(aDev, pAddr->iRegister, val, cb);
341#else
342 rc = rcReschedule;
343#endif
344 }
345 }
346
347 Log2(("ich9pciDataWriteAddr: %02x:%02x:%02x reg %x(%d) %x %Rrc\n",
348 pAddr->iBus, pAddr->iDeviceFunc >> 3, pAddr->iDeviceFunc & 0x7, pAddr->iRegister,
349 cb, val, rc));
350 return rc;
351}
352
353
354/*
355 * Decode value latched in Configuration Address Port and perform
356 * requsted write to the target configuration space register.
357 *
358 * XXX: This code should be probably moved to its only caller
359 * (ich9pciIOPortDataWrite) to avoid prolifiration of confusingly
360 * similarly named functions.
361 */
362static int ich9pciDataWrite(PICH9PCIGLOBALS pGlobals, uint32_t addr, uint32_t val, int len)
363{
364 LogFlow(("ich9pciDataWrite: config=%08x val=%08x len=%d\n", pGlobals->uConfigReg, val, len));
365
366 /* Configuration space mapping enabled? */
367 if (!(pGlobals->uConfigReg & (1 << 31)))
368 return VINF_SUCCESS;
369
370 /* Decode target device and configuration space register */
371 PciAddress aPciAddr;
372 ich9pciStateToPciAddr(pGlobals, addr, &aPciAddr);
373
374 /* Perform configuration space write */
375 return ich9pciDataWriteAddr(pGlobals, &aPciAddr, val, len, VINF_IOM_R3_IOPORT_WRITE);
376}
377
378
379/**
380 * Port I/O Handler for PCI data OUT operations.
381 *
382 * Emulates writes to Configuration Data Port at 0CFCh for
383 * Configuration Mechanism #1.
384 *
385 * @returns VBox status code.
386 *
387 * @param pDevIns ICH9 device instance.
388 * @param pvUser User argument - ignored.
389 * @param uPort Port number used for the OUT operation.
390 * @param u32 The value to output.
391 * @param cb The value size in bytes.
392 */
393PDMBOTHCBDECL(int) ich9pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
394{
395 LogFlow(("ich9pciIOPortDataWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
396 NOREF(pvUser);
397 int rc = VINF_SUCCESS;
398 if (!(Port % cb))
399 {
400 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
401
402 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
403 rc = ich9pciDataWrite(pThis, Port, u32, cb);
404 PCI_UNLOCK(pDevIns);
405 }
406 else
407 AssertMsgFailed(("Unaligned write to port %#x u32=%#x cb=%d\n", Port, u32, cb));
408 return rc;
409}
410
411
412static void ich9pciNoMem(void* ptr, int cb)
413{
414 for (int i = 0; i < cb; i++)
415 ((uint8_t*)ptr)[i] = 0xff;
416}
417
418
419/*
420 * Perform configuration space read.
421 */
422static int ich9pciDataReadAddr(PICH9PCIGLOBALS pGlobals, PciAddress* pPciAddr, int cb,
423 uint32_t *pu32, int rcReschedule)
424{
425 int rc = VINF_SUCCESS;
426#ifdef IN_RING3
427 NOREF(rcReschedule);
428#endif
429
430 if (pPciAddr->iBus != 0) /* forward to subordinate bus */
431 {
432 if (pGlobals->aPciBus.cBridges)
433 {
434#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
435 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(&pGlobals->aPciBus, pPciAddr->iBus);
436 if (pBridgeDevice)
437 {
438 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
439 *pu32 = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, pPciAddr->iBus, pPciAddr->iDeviceFunc, pPciAddr->iRegister, cb);
440 }
441 else
442 ich9pciNoMem(pu32, cb);
443#else
444 rc = rcReschedule;
445#endif
446 }
447 else
448 ich9pciNoMem(pu32, cb);
449 }
450 else /* forward to directly connected device */
451 {
452 R3PTRTYPE(PCIDevice *) aDev = pGlobals->aPciBus.apDevices[pPciAddr->iDeviceFunc];
453 if (aDev)
454 {
455#ifdef IN_RING3
456 *pu32 = aDev->Int.s.pfnConfigRead(aDev, pPciAddr->iRegister, cb);
457#else
458 rc = rcReschedule;
459#endif
460 }
461 else
462 ich9pciNoMem(pu32, cb);
463 }
464
465 Log3(("ich9pciDataReadAddr: %02x:%02x:%02x reg %x(%d) gave %x %Rrc\n",
466 pPciAddr->iBus, pPciAddr->iDeviceFunc >> 3, pPciAddr->iDeviceFunc & 0x7, pPciAddr->iRegister,
467 cb, *pu32, rc));
468 return rc;
469}
470
471
472/*
473 * Decode value latched in Configuration Address Port and perform
474 * requsted read from the target configuration space register.
475 *
476 * XXX: This code should be probably moved to its only caller
477 * (ich9pciIOPortDataRead) to avoid prolifiration of confusingly
478 * similarly named functions.
479 */
480static int ich9pciDataRead(PICH9PCIGLOBALS pGlobals, uint32_t addr, int cb, uint32_t *pu32)
481{
482 LogFlow(("ich9pciDataRead: config=%x cb=%d\n", pGlobals->uConfigReg, cb));
483
484 *pu32 = 0xffffffff;
485
486 /* Configuration space mapping enabled? */
487 if (!(pGlobals->uConfigReg & (1 << 31)))
488 return VINF_SUCCESS;
489
490 /* Decode target device and configuration space register */
491 PciAddress aPciAddr;
492 ich9pciStateToPciAddr(pGlobals, addr, &aPciAddr);
493
494 /* Perform configuration space read */
495 return ich9pciDataReadAddr(pGlobals, &aPciAddr, cb, pu32, VINF_IOM_R3_IOPORT_READ);
496}
497
498
499/**
500 * Port I/O Handler for PCI data IN operations.
501 *
502 * Emulates reads from Configuration Data Port at 0CFCh for
503 * Configuration Mechanism #1.
504 *
505 * @returns VBox status code.
506 *
507 * @param pDevIns ICH9 device instance.
508 * @param pvUser User argument - ignored.
509 * @param uPort Port number used for the IN operation.
510 * @param pu32 Where to store the result.
511 * @param cb Number of bytes read.
512 */
513PDMBOTHCBDECL(int) ich9pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
514{
515 NOREF(pvUser);
516 if (!(Port % cb))
517 {
518 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
519
520 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_READ);
521 int rc = ich9pciDataRead(pThis, Port, cb, pu32);
522 PCI_UNLOCK(pDevIns);
523
524 LogFlow(("ich9pciIOPortDataRead: Port=%#x cb=%#x -> %#x (%Rrc)\n", Port, cb, *pu32, rc));
525 return rc;
526 }
527 AssertMsgFailed(("Unaligned read from port %#x cb=%d\n", Port, cb));
528 return VERR_IOM_IOPORT_UNUSED;
529}
530
531
532/* Compute mapping of PCI slot and IRQ number to APIC interrupt line */
533DECLINLINE(int) ich9pciSlot2ApicIrq(uint8_t uSlot, int irq_num)
534{
535 return (irq_num + uSlot) & 7;
536}
537
538/* return the global irq number corresponding to a given device irq
539 pin. We could also use the bus number to have a more precise
540 mapping. This is the implementation note described in the PCI spec chapter 2.2.6 */
541DECLINLINE(int) ich9pciSlotGetPirq(uint8_t uBus, uint8_t uDevFn, int iIrqNum)
542{
543 NOREF(uBus);
544 int iSlotAddend = (uDevFn >> 3) - 1;
545 return (iIrqNum + iSlotAddend) & 3;
546}
547
548/* irqs corresponding to PCI irqs A-D, must match pci_irq_list in rombios.c */
549static const uint8_t aPciIrqs[4] = { 11, 10, 9, 5 };
550
551/* Add one more level up request on APIC input line */
552DECLINLINE(void) ich9pciApicLevelUp(PICH9PCIGLOBALS pGlobals, int irq_num)
553{
554 ASMAtomicIncU32(&pGlobals->uaPciApicIrqLevels[irq_num]);
555}
556
557/* Remove one level up request on APIC input line */
558DECLINLINE(void) ich9pciApicLevelDown(PICH9PCIGLOBALS pGlobals, int irq_num)
559{
560 ASMAtomicDecU32(&pGlobals->uaPciApicIrqLevels[irq_num]);
561}
562
563static void ich9pciApicSetIrq(PICH9PCIBUS pBus, uint8_t uDevFn, PCIDevice *pPciDev, int irq_num1, int iLevel,
564 uint32_t uTagSrc, int iForcedIrq)
565{
566 /* This is only allowed to be called with a pointer to the root bus. */
567 AssertMsg(pBus->iBus == 0, ("iBus=%u\n", pBus->iBus));
568
569 if (iForcedIrq == -1)
570 {
571 int apic_irq, apic_level;
572 PICH9PCIGLOBALS pGlobals = PCIROOTBUS_2_PCIGLOBALS(pBus);
573 int irq_num = ich9pciSlot2ApicIrq(uDevFn >> 3, irq_num1);
574
575 if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_HIGH)
576 ich9pciApicLevelUp(pGlobals, irq_num);
577 else if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_LOW)
578 ich9pciApicLevelDown(pGlobals, irq_num);
579
580 apic_irq = irq_num + 0x10;
581 apic_level = pGlobals->uaPciApicIrqLevels[irq_num] != 0;
582 Log3(("ich9pciApicSetIrq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d uTagSrc=%#x\n",
583 R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num, uTagSrc));
584 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level, uTagSrc);
585
586 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
587 {
588 /*
589 * we raised it few lines above, as PDM_IRQ_LEVEL_FLIP_FLOP has
590 * PDM_IRQ_LEVEL_HIGH bit set
591 */
592 ich9pciApicLevelDown(pGlobals, irq_num);
593 pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
594 apic_level = pGlobals->uaPciApicIrqLevels[irq_num] != 0;
595 Log3(("ich9pciApicSetIrq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d uTagSrc=%#x (flop)\n",
596 R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num, uTagSrc));
597 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level, uTagSrc);
598 }
599 } else {
600 Log3(("ich9pciApicSetIrq: (forced) %s: irq_num1=%d level=%d acpi_irq=%d uTagSrc=%#x\n",
601 R3STRING(pPciDev->name), irq_num1, iLevel, iForcedIrq, uTagSrc));
602 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), iForcedIrq, iLevel, uTagSrc);
603 }
604}
605
606static void ich9pciSetIrqInternal(PICH9PCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev,
607 int iIrq, int iLevel, uint32_t uTagSrc)
608{
609
610 if (PCIDevIsIntxDisabled(pPciDev))
611 {
612 if (MsiIsEnabled(pPciDev))
613 {
614 PPDMDEVINS pDevIns = pGlobals->aPciBus.CTX_SUFF(pDevIns);
615 MsiNotify(pDevIns, pGlobals->aPciBus.CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel, uTagSrc);
616 }
617
618 if (MsixIsEnabled(pPciDev))
619 {
620 PPDMDEVINS pDevIns = pGlobals->aPciBus.CTX_SUFF(pDevIns);
621 MsixNotify(pDevIns, pGlobals->aPciBus.CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel, uTagSrc);
622 }
623 return;
624 }
625
626 PICH9PCIBUS pBus = &pGlobals->aPciBus;
627 const bool fIsAcpiDevice = PCIDevGetDeviceId(pPciDev) == 0x7113;
628
629 /* Check if the state changed. */
630 if (pPciDev->Int.s.uIrqPinState != iLevel)
631 {
632 pPciDev->Int.s.uIrqPinState = (iLevel & PDM_IRQ_LEVEL_HIGH);
633
634 /* Send interrupt to I/O APIC only now. */
635 if (fIsAcpiDevice)
636 /*
637 * ACPI needs special treatment since SCI is hardwired and
638 * should not be affected by PCI IRQ routing tables at the
639 * same time SCI IRQ is shared in PCI sense hence this
640 * kludge (i.e. we fetch the hardwired value from ACPIs
641 * PCI device configuration space).
642 */
643 ich9pciApicSetIrq(pBus, uDevFn, pPciDev, -1, iLevel, uTagSrc, PCIDevGetInterruptLine(pPciDev));
644 else
645 ich9pciApicSetIrq(pBus, uDevFn, pPciDev, iIrq, iLevel, uTagSrc, -1);
646 }
647}
648
649
650/**
651 * Memory mapped I/O Handler for write operations.
652 *
653 * Emulates writes to configuration space.
654 *
655 * @returns VBox status code.
656 *
657 * @param pDevIns The device instance.
658 * @param pvUser User argument.
659 * @param GCPhysAddr Physical address (in GC) where the read starts.
660 * @param pv Where to fetch the result.
661 * @param cb Number of bytes to write.
662 * @remarks Caller enters the device critical section.
663 */
664PDMBOTHCBDECL(int) ich9pciMcfgMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
665{
666 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
667 uint32_t u32 = 0;
668 NOREF(pvUser);
669
670 Log2(("ich9pciMcfgMMIOWrite: %RGp(%d) \n", GCPhysAddr, cb));
671
672 PCI_LOCK(pDevIns, VINF_IOM_R3_MMIO_WRITE);
673
674 /* Decode target device and configuration space register */
675 PciAddress aDest;
676 ich9pciPhysToPciAddr(pGlobals, GCPhysAddr, &aDest);
677
678 switch (cb)
679 {
680 case 1:
681 u32 = *(uint8_t*)pv;
682 break;
683 case 2:
684 u32 = *(uint16_t*)pv;
685 break;
686 case 4:
687 u32 = *(uint32_t*)pv;
688 break;
689 default:
690 Assert(false);
691 break;
692 }
693
694 /* Perform configuration space write */
695 int rc = ich9pciDataWriteAddr(pGlobals, &aDest, u32, cb, VINF_IOM_R3_MMIO_WRITE);
696 PCI_UNLOCK(pDevIns);
697
698 return rc;
699}
700
701
702/**
703 * Memory mapped I/O Handler for read operations.
704 *
705 * Emulates reads from configuration space.
706 *
707 * @returns VBox status code.
708 *
709 * @param pDevIns The device instance.
710 * @param pvUser User argument.
711 * @param GCPhysAddr Physical address (in GC) where the read starts.
712 * @param pv Where to store the result.
713 * @param cb Number of bytes read.
714 * @remarks Caller enters the device critical section.
715 */
716PDMBOTHCBDECL(int) ich9pciMcfgMMIORead (PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
717{
718 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
719 uint32_t rv;
720 NOREF(pvUser);
721
722 LogFlow(("ich9pciMcfgMMIORead: %RGp(%d) \n", GCPhysAddr, cb));
723
724 PCI_LOCK(pDevIns, VINF_IOM_R3_MMIO_READ);
725
726 /* Decode target device and configuration space register */
727 PciAddress aDest;
728 ich9pciPhysToPciAddr(pGlobals, GCPhysAddr, &aDest);
729
730 /* Perform configuration space read */
731 int rc = ich9pciDataReadAddr(pGlobals, &aDest, cb, &rv, VINF_IOM_R3_MMIO_READ);
732
733 if (RT_SUCCESS(rc))
734 {
735 switch (cb)
736 {
737 case 1:
738 *(uint8_t*)pv = (uint8_t)rv;
739 break;
740 case 2:
741 *(uint16_t*)pv = (uint16_t)rv;
742 break;
743 case 4:
744 *(uint32_t*)pv = (uint32_t)rv;
745 break;
746 default:
747 Assert(false);
748 break;
749 }
750 }
751 PCI_UNLOCK(pDevIns);
752
753 return rc;
754}
755
756#ifdef IN_RING3
757
758DECLINLINE(PPCIDEVICE) ich9pciFindBridge(PICH9PCIBUS pBus, uint8_t iBus)
759{
760 /* Search for a fitting bridge. */
761 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
762 {
763 /*
764 * Examine secondary and subordinate bus number.
765 * If the target bus is in the range we pass the request on to the bridge.
766 */
767 PPCIDEVICE pBridge = pBus->papBridgesR3[iBridge];
768 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
769 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
770 uint32_t uSecondary = PCIDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS);
771 uint32_t uSubordinate = PCIDevGetByte(pBridge, VBOX_PCI_SUBORDINATE_BUS);
772 Log3(("ich9pciFindBridge on bus %p, bridge %d: %d in %d..%d\n", pBus, iBridge, iBus, uSecondary, uSubordinate));
773 if (iBus >= uSecondary && iBus <= uSubordinate)
774 return pBridge;
775 }
776
777 /* Nothing found. */
778 return NULL;
779}
780
781static uint32_t ich9pciGetCfg(PCIDevice* aDev, int32_t iRegister, int cb)
782{
783 return aDev->Int.s.pfnConfigRead(aDev, iRegister, cb);
784}
785
786static uint8_t ich9pciGetByte(PCIDevice* aDev, int32_t iRegister)
787{
788 return (uint8_t)ich9pciGetCfg(aDev, iRegister, 1);
789}
790
791static uint16_t ich9pciGetWord(PCIDevice* aDev, int32_t iRegister)
792{
793 return (uint16_t)ich9pciGetCfg(aDev, iRegister, 2);
794}
795
796static uint32_t ich9pciGetDWord(PCIDevice* aDev, int32_t iRegister)
797{
798 return (uint32_t)ich9pciGetCfg(aDev, iRegister, 4);
799}
800
801DECLINLINE(uint32_t) ich9pciGetRegionReg(int iRegion)
802{
803 return (iRegion == VBOX_PCI_ROM_SLOT) ?
804 VBOX_PCI_ROM_ADDRESS : (VBOX_PCI_BASE_ADDRESS_0 + iRegion * 4);
805}
806
807#define INVALID_PCI_ADDRESS ~0U
808
809static int ich9pciUnmapRegion(PPCIDEVICE pDev, int iRegion)
810{
811 PCIIORegion* pRegion = &pDev->Int.s.aIORegions[iRegion];
812 int rc = VINF_SUCCESS;
813 PICH9PCIBUS pBus = pDev->Int.s.CTX_SUFF(pBus);
814
815 Assert (pRegion->size != 0);
816
817 if (pRegion->addr != INVALID_PCI_ADDRESS)
818 {
819 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
820 {
821 /* Port IO */
822 rc = PDMDevHlpIOPortDeregister(pDev->pDevIns, pRegion->addr, pRegion->size);
823 AssertRC(rc);
824 }
825 else
826 {
827 RTGCPHYS GCPhysBase = pRegion->addr;
828 if (pBus->pPciHlpR3->pfnIsMMIO2Base(pBus->pDevInsR3, pDev->pDevIns, GCPhysBase))
829 {
830 /* unmap it. */
831 rc = pRegion->map_func(pDev, iRegion, NIL_RTGCPHYS, pRegion->size, (PCIADDRESSSPACE)(pRegion->type));
832 AssertRC(rc);
833 rc = PDMDevHlpMMIO2Unmap(pDev->pDevIns, iRegion, GCPhysBase);
834 }
835 else
836 rc = PDMDevHlpMMIODeregister(pDev->pDevIns, GCPhysBase, pRegion->size);
837 }
838
839 pRegion->addr = INVALID_PCI_ADDRESS;
840 }
841
842 return rc;
843}
844
845static void ich9pciUpdateMappings(PCIDevice* pDev)
846{
847 uint64_t uLast, uNew;
848
849 int iCmd = ich9pciGetWord(pDev, VBOX_PCI_COMMAND);
850 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
851 {
852 PCIIORegion* pRegion = &pDev->Int.s.aIORegions[iRegion];
853 uint32_t uConfigReg = ich9pciGetRegionReg(iRegion);
854 int64_t iRegionSize = pRegion->size;
855 int rc;
856
857 if (iRegionSize == 0)
858 continue;
859
860 bool f64Bit = (pRegion->type & PCI_ADDRESS_SPACE_BAR64) != 0;
861
862 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
863 {
864 /* port IO region */
865 if (iCmd & PCI_COMMAND_IOACCESS)
866 {
867 /* IO access allowed */
868 uNew = ich9pciGetDWord(pDev, uConfigReg);
869 uNew &= ~(iRegionSize - 1);
870 uLast = uNew + iRegionSize - 1;
871 /* only 64K ioports on PC */
872 if (uLast <= uNew || uNew == 0 || uLast >= 0x10000)
873 uNew = INVALID_PCI_ADDRESS;
874 } else
875 uNew = INVALID_PCI_ADDRESS;
876 }
877 else
878 {
879 /* MMIO region */
880 if (iCmd & PCI_COMMAND_MEMACCESS)
881 {
882 uNew = ich9pciGetDWord(pDev, uConfigReg);
883
884 if (f64Bit)
885 {
886 uNew |= ((uint64_t)ich9pciGetDWord(pDev, uConfigReg+4)) << 32;
887 if (uNew > UINT64_C(0x0000010000000000))
888 {
889 /* Workaround for REM being unhapping with mapping very lange 64-bit addresses */
890 Log(("Ignoring too 64-bit BAR: %llx\n", uNew));
891 uNew = INVALID_PCI_ADDRESS;
892 }
893 }
894
895 /* the ROM slot has a specific enable bit */
896 if (iRegion == PCI_ROM_SLOT && !(uNew & 1))
897 uNew = INVALID_PCI_ADDRESS;
898 else
899 {
900 uNew &= ~(iRegionSize - 1);
901 uLast = uNew + iRegionSize - 1;
902 /* NOTE: we do not support wrapping */
903 /* XXX: as we cannot support really dynamic
904 mappings, we handle specific values as invalid
905 mappings. */
906 if (uLast <= uNew || uNew == 0 || uLast == INVALID_PCI_ADDRESS)
907 uNew = INVALID_PCI_ADDRESS;
908 }
909 } else
910 uNew = INVALID_PCI_ADDRESS;
911 }
912 /* now do the real mapping */
913 if (uNew != pRegion->addr)
914 {
915 if (pRegion->addr != INVALID_PCI_ADDRESS)
916 ich9pciUnmapRegion(pDev, iRegion);
917
918 pRegion->addr = uNew;
919 if (pRegion->addr != INVALID_PCI_ADDRESS)
920 {
921
922 /* finally, map the region */
923 rc = pRegion->map_func(pDev, iRegion,
924 pRegion->addr, pRegion->size,
925 (PCIADDRESSSPACE)(pRegion->type));
926 AssertRC(rc);
927 }
928 }
929 }
930}
931
932static DECLCALLBACK(int) ich9pciRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
933{
934 PICH9PCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
935
936 /*
937 * Check input.
938 */
939 if ( !pszName
940 || !pPciDev
941 || iDev >= (int)RT_ELEMENTS(pBus->apDevices)
942 )
943 {
944 AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
945 return VERR_INVALID_PARAMETER;
946 }
947
948 /*
949 * Register the device.
950 */
951 return ich9pciRegisterInternal(pBus, iDev, pPciDev, pszName);
952}
953
954
955static DECLCALLBACK(int) ich9pciRegisterMsi(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PPDMMSIREG pMsiReg)
956{
957 NOREF(pDevIns);
958 int rc;
959
960 rc = MsiInit(pPciDev, pMsiReg);
961 if (RT_FAILURE(rc))
962 return rc;
963
964 rc = MsixInit(pPciDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp), pPciDev, pMsiReg);
965 if (RT_FAILURE(rc))
966 return rc;
967
968 return VINF_SUCCESS;
969}
970
971
972static DECLCALLBACK(int) ich9pcibridgeRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
973{
974
975 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
976
977 /*
978 * Check input.
979 */
980 if ( !pszName
981 || !pPciDev
982 || iDev >= (int)RT_ELEMENTS(pBus->apDevices))
983 {
984 AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
985 return VERR_INVALID_PARAMETER;
986 }
987
988 /*
989 * Register the device.
990 */
991 return ich9pciRegisterInternal(pBus, iDev, pPciDev, pszName);
992}
993
994static DECLCALLBACK(int) ich9pciIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, uint32_t cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
995{
996 NOREF(pDevIns);
997
998 /*
999 * Validate.
1000 */
1001 AssertMsgReturn( enmType == (PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR32)
1002 || enmType == (PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_BAR32)
1003 || enmType == (PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64)
1004 || enmType == (PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_BAR64)
1005 || enmType == PCI_ADDRESS_SPACE_IO
1006 ,
1007 ("Invalid enmType=%#x? Or was this a bitmask after all...\n", enmType),
1008 VERR_INVALID_PARAMETER);
1009 AssertMsgReturn((unsigned)iRegion < PCI_NUM_REGIONS,
1010 ("Invalid iRegion=%d PCI_NUM_REGIONS=%d\n", iRegion, PCI_NUM_REGIONS),
1011 VERR_INVALID_PARAMETER);
1012 int iLastSet = ASMBitLastSetU32(cbRegion);
1013 AssertMsgReturn( iLastSet != 0
1014 && RT_BIT_32(iLastSet - 1) == cbRegion,
1015 ("Invalid cbRegion=%#x iLastSet=%#x (not a power of 2 or 0)\n", cbRegion, iLastSet),
1016 VERR_INVALID_PARAMETER);
1017
1018 Log(("ich9pciIORegionRegister: %s region %d size %d type %x\n",
1019 pPciDev->name, iRegion, cbRegion, enmType));
1020
1021 /* Make sure that we haven't marked this region as continuation of 64-bit region. */
1022 Assert(pPciDev->Int.s.aIORegions[iRegion].type != 0xff);
1023
1024 /*
1025 * Register the I/O region.
1026 */
1027 PPCIIOREGION pRegion = &pPciDev->Int.s.aIORegions[iRegion];
1028 pRegion->addr = INVALID_PCI_ADDRESS;
1029 pRegion->size = cbRegion;
1030 pRegion->type = enmType;
1031 pRegion->map_func = pfnCallback;
1032
1033 if ((enmType & PCI_ADDRESS_SPACE_BAR64) != 0)
1034 {
1035 AssertMsgReturn(iRegion < 4,
1036 ("Region %d cannot be 64-bit\n", iRegion),
1037 VERR_INVALID_PARAMETER);
1038 /* Mark next region as continuation of this one. */
1039 pPciDev->Int.s.aIORegions[iRegion+1].type = 0xff;
1040 }
1041
1042 /* Set type in the PCI config space. */
1043 uint32_t u32Value = ((uint32_t)enmType) & (PCI_ADDRESS_SPACE_IO | PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_MEM_PREFETCH);
1044 PCIDevSetDWord(pPciDev, ich9pciGetRegionReg(iRegion), u32Value);
1045
1046 return VINF_SUCCESS;
1047}
1048
1049static DECLCALLBACK(void) ich9pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
1050 PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
1051{
1052 NOREF(pDevIns);
1053
1054 if (ppfnReadOld)
1055 *ppfnReadOld = pPciDev->Int.s.pfnConfigRead;
1056 pPciDev->Int.s.pfnConfigRead = pfnRead;
1057
1058 if (ppfnWriteOld)
1059 *ppfnWriteOld = pPciDev->Int.s.pfnConfigWrite;
1060 pPciDev->Int.s.pfnConfigWrite = pfnWrite;
1061}
1062
1063static int ich9pciR3CommonSaveExec(PICH9PCIBUS pBus, PSSMHANDLE pSSM)
1064{
1065 /*
1066 * Iterate thru all the devices.
1067 */
1068 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
1069 {
1070 PPCIDEVICE pDev = pBus->apDevices[i];
1071 if (pDev)
1072 {
1073 /* Device position */
1074 SSMR3PutU32(pSSM, i);
1075 /* PCI config registers */
1076 SSMR3PutMem(pSSM, pDev->config, sizeof(pDev->config));
1077
1078 /* Device flags */
1079 int rc = SSMR3PutU32(pSSM, pDev->Int.s.fFlags);
1080 if (RT_FAILURE(rc))
1081 return rc;
1082
1083 /* IRQ pin state */
1084 rc = SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
1085 if (RT_FAILURE(rc))
1086 return rc;
1087
1088 /* MSI info */
1089 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapOffset);
1090 if (RT_FAILURE(rc))
1091 return rc;
1092 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapSize);
1093 if (RT_FAILURE(rc))
1094 return rc;
1095
1096 /* MSI-X info */
1097 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapOffset);
1098 if (RT_FAILURE(rc))
1099 return rc;
1100 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapSize);
1101 if (RT_FAILURE(rc))
1102 return rc;
1103 /* Save MSI-X page state */
1104 if (pDev->Int.s.u8MsixCapOffset != 0)
1105 {
1106 Assert(pDev->Int.s.pMsixPageR3 != NULL);
1107 SSMR3PutMem(pSSM, pDev->Int.s.pMsixPageR3, 0x1000);
1108 if (RT_FAILURE(rc))
1109 return rc;
1110 }
1111 }
1112 }
1113 return SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
1114}
1115
1116static DECLCALLBACK(int) ich9pciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1117{
1118 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
1119
1120 /*
1121 * Bus state data.
1122 */
1123 SSMR3PutU32(pSSM, pThis->uConfigReg);
1124
1125 /*
1126 * Save IRQ states.
1127 */
1128 for (int i = 0; i < PCI_APIC_IRQ_PINS; i++)
1129 SSMR3PutU32(pSSM, pThis->uaPciApicIrqLevels[i]);
1130
1131 SSMR3PutU32(pSSM, ~0); /* separator */
1132
1133 return ich9pciR3CommonSaveExec(&pThis->aPciBus, pSSM);
1134}
1135
1136
1137static DECLCALLBACK(int) ich9pcibridgeR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1138{
1139 PICH9PCIBUS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1140 return ich9pciR3CommonSaveExec(pThis, pSSM);
1141}
1142
1143
1144static void ich9pcibridgeConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, uint32_t u32Value, unsigned cb)
1145{
1146 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1147
1148 LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u u32Value=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, u32Value, cb));
1149
1150 /* If the current bus is not the target bus search for the bus which contains the device. */
1151 if (iBus != PCIDevGetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS))
1152 {
1153 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1154 if (pBridgeDevice)
1155 {
1156 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
1157 pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, u32Value, cb);
1158 }
1159 }
1160 else
1161 {
1162 /* This is the target bus, pass the write to the device. */
1163 PPCIDEVICE pPciDev = pBus->apDevices[iDevice];
1164 if (pPciDev)
1165 {
1166 Log(("%s: %s: addr=%02x val=%08x len=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
1167 pPciDev->Int.s.pfnConfigWrite(pPciDev, u32Address, u32Value, cb);
1168 }
1169 }
1170}
1171
1172static uint32_t ich9pcibridgeConfigRead(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, unsigned cb)
1173{
1174 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1175 uint32_t u32Value;
1176
1177 LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, cb));
1178
1179 /* If the current bus is not the target bus search for the bus which contains the device. */
1180 if (iBus != PCIDevGetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS))
1181 {
1182 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1183 if (pBridgeDevice)
1184 {
1185 AssertPtr( pBridgeDevice->Int.s.pfnBridgeConfigRead);
1186 u32Value = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, cb);
1187 }
1188 else
1189 ich9pciNoMem(&u32Value, 4);
1190 }
1191 else
1192 {
1193 /* This is the target bus, pass the read to the device. */
1194 PPCIDEVICE pPciDev = pBus->apDevices[iDevice];
1195 if (pPciDev)
1196 {
1197 u32Value = pPciDev->Int.s.pfnConfigRead(pPciDev, u32Address, cb);
1198 Log(("%s: %s: u32Address=%02x u32Value=%08x cb=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
1199 }
1200 else
1201 ich9pciNoMem(&u32Value, 4);
1202 }
1203
1204 return u32Value;
1205}
1206
1207
1208/**
1209 * Common routine for restoring the config registers of a PCI device.
1210 *
1211 * @param pDev The PCI device.
1212 * @param pbSrcConfig The configuration register values to be loaded.
1213 * @param fIsBridge Whether this is a bridge device or not.
1214 */
1215static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig, bool fIsBridge)
1216{
1217 /*
1218 * This table defines the fields for normal devices and bridge devices, and
1219 * the order in which they need to be restored.
1220 */
1221 static const struct PciField
1222 {
1223 uint8_t off;
1224 uint8_t cb;
1225 uint8_t fWritable;
1226 uint8_t fBridge;
1227 const char *pszName;
1228 } s_aFields[] =
1229 {
1230 /* off,cb,fW,fB, pszName */
1231 { 0x00, 2, 0, 3, "VENDOR_ID" },
1232 { 0x02, 2, 0, 3, "DEVICE_ID" },
1233 { 0x06, 2, 1, 3, "STATUS" },
1234 { 0x08, 1, 0, 3, "REVISION_ID" },
1235 { 0x09, 1, 0, 3, "CLASS_PROG" },
1236 { 0x0a, 1, 0, 3, "CLASS_SUB" },
1237 { 0x0b, 1, 0, 3, "CLASS_BASE" },
1238 { 0x0c, 1, 1, 3, "CACHE_LINE_SIZE" },
1239 { 0x0d, 1, 1, 3, "LATENCY_TIMER" },
1240 { 0x0e, 1, 0, 3, "HEADER_TYPE" },
1241 { 0x0f, 1, 1, 3, "BIST" },
1242 { 0x10, 4, 1, 3, "BASE_ADDRESS_0" },
1243 { 0x14, 4, 1, 3, "BASE_ADDRESS_1" },
1244 { 0x18, 4, 1, 1, "BASE_ADDRESS_2" },
1245 { 0x18, 1, 1, 2, "PRIMARY_BUS" }, // fWritable = ??
1246 { 0x19, 1, 1, 2, "SECONDARY_BUS" }, // fWritable = ??
1247 { 0x1a, 1, 1, 2, "SUBORDINATE_BUS" }, // fWritable = ??
1248 { 0x1b, 1, 1, 2, "SEC_LATENCY_TIMER" }, // fWritable = ??
1249 { 0x1c, 4, 1, 1, "BASE_ADDRESS_3" },
1250 { 0x1c, 1, 1, 2, "IO_BASE" }, // fWritable = ??
1251 { 0x1d, 1, 1, 2, "IO_LIMIT" }, // fWritable = ??
1252 { 0x1e, 2, 1, 2, "SEC_STATUS" }, // fWritable = ??
1253 { 0x20, 4, 1, 1, "BASE_ADDRESS_4" },
1254 { 0x20, 2, 1, 2, "MEMORY_BASE" }, // fWritable = ??
1255 { 0x22, 2, 1, 2, "MEMORY_LIMIT" }, // fWritable = ??
1256 { 0x24, 4, 1, 1, "BASE_ADDRESS_5" },
1257 { 0x24, 2, 1, 2, "PREF_MEMORY_BASE" }, // fWritable = ??
1258 { 0x26, 2, 1, 2, "PREF_MEMORY_LIMIT" }, // fWritable = ??
1259 { 0x28, 4, 1, 1, "CARDBUS_CIS" }, // fWritable = ??
1260 { 0x28, 4, 1, 2, "PREF_BASE_UPPER32" }, // fWritable = ??
1261 { 0x2c, 2, 0, 1, "SUBSYSTEM_VENDOR_ID" },// fWritable = !?
1262 { 0x2c, 4, 1, 2, "PREF_LIMIT_UPPER32" },// fWritable = ??
1263 { 0x2e, 2, 0, 1, "SUBSYSTEM_ID" }, // fWritable = !?
1264 { 0x30, 4, 1, 1, "ROM_ADDRESS" }, // fWritable = ?!
1265 { 0x30, 2, 1, 2, "IO_BASE_UPPER16" }, // fWritable = ?!
1266 { 0x32, 2, 1, 2, "IO_LIMIT_UPPER16" }, // fWritable = ?!
1267 { 0x34, 4, 0, 3, "CAPABILITY_LIST" }, // fWritable = !? cb=!?
1268 { 0x38, 4, 1, 1, "RESERVED_38" }, // ???
1269 { 0x38, 4, 1, 2, "ROM_ADDRESS_BR" }, // fWritable = !? cb=!? fBridge=!?
1270 { 0x3c, 1, 1, 3, "INTERRUPT_LINE" }, // fBridge=??
1271 { 0x3d, 1, 0, 3, "INTERRUPT_PIN" }, // fBridge=??
1272 { 0x3e, 1, 0, 1, "MIN_GNT" },
1273 { 0x3e, 2, 1, 2, "BRIDGE_CONTROL" }, // fWritable = !?
1274 { 0x3f, 1, 0, 1, "MAX_LAT" },
1275 /* The COMMAND register must come last as it requires the *ADDRESS*
1276 registers to be restored before we pretent to change it from 0 to
1277 whatever value the guest assigned it. */
1278 { 0x04, 2, 1, 3, "COMMAND" },
1279 };
1280
1281#ifdef RT_STRICT
1282 /* Check that we've got full register coverage. */
1283 uint32_t bmDevice[0x40 / 32];
1284 uint32_t bmBridge[0x40 / 32];
1285 RT_ZERO(bmDevice);
1286 RT_ZERO(bmBridge);
1287 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1288 {
1289 uint8_t off = s_aFields[i].off;
1290 uint8_t cb = s_aFields[i].cb;
1291 uint8_t f = s_aFields[i].fBridge;
1292 while (cb-- > 0)
1293 {
1294 if (f & 1) AssertMsg(!ASMBitTest(bmDevice, off), ("%#x\n", off));
1295 if (f & 2) AssertMsg(!ASMBitTest(bmBridge, off), ("%#x\n", off));
1296 if (f & 1) ASMBitSet(bmDevice, off);
1297 if (f & 2) ASMBitSet(bmBridge, off);
1298 off++;
1299 }
1300 }
1301 for (uint32_t off = 0; off < 0x40; off++)
1302 {
1303 AssertMsg(ASMBitTest(bmDevice, off), ("%#x\n", off));
1304 AssertMsg(ASMBitTest(bmBridge, off), ("%#x\n", off));
1305 }
1306#endif
1307
1308 /*
1309 * Loop thru the fields covering the 64 bytes of standard registers.
1310 */
1311 uint8_t const fBridge = fIsBridge ? 2 : 1;
1312 Assert(!pciDevIsPassthrough(pDev));
1313 uint8_t *pbDstConfig = &pDev->config[0];
1314
1315 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1316 if (s_aFields[i].fBridge & fBridge)
1317 {
1318 uint8_t const off = s_aFields[i].off;
1319 uint8_t const cb = s_aFields[i].cb;
1320 uint32_t u32Src;
1321 uint32_t u32Dst;
1322 switch (cb)
1323 {
1324 case 1:
1325 u32Src = pbSrcConfig[off];
1326 u32Dst = pbDstConfig[off];
1327 break;
1328 case 2:
1329 u32Src = *(uint16_t const *)&pbSrcConfig[off];
1330 u32Dst = *(uint16_t const *)&pbDstConfig[off];
1331 break;
1332 case 4:
1333 u32Src = *(uint32_t const *)&pbSrcConfig[off];
1334 u32Dst = *(uint32_t const *)&pbDstConfig[off];
1335 break;
1336 default:
1337 AssertFailed();
1338 continue;
1339 }
1340
1341 if ( u32Src != u32Dst
1342 || off == VBOX_PCI_COMMAND)
1343 {
1344 if (u32Src != u32Dst)
1345 {
1346 if (!s_aFields[i].fWritable)
1347 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x - !READ ONLY!\n",
1348 pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1349 else
1350 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x\n",
1351 pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1352 }
1353 if (off == VBOX_PCI_COMMAND)
1354 PCIDevSetCommand(pDev, 0); /* For remapping, see ich9pciR3CommonLoadExec. */
1355 pDev->Int.s.pfnConfigWrite(pDev, off, u32Src, cb);
1356 }
1357 }
1358
1359 /*
1360 * The device dependent registers.
1361 *
1362 * We will not use ConfigWrite here as we have no clue about the size
1363 * of the registers, so the device is responsible for correctly
1364 * restoring functionality governed by these registers.
1365 */
1366 for (uint32_t off = 0x40; off < sizeof(pDev->config); off++)
1367 if (pbDstConfig[off] != pbSrcConfig[off])
1368 {
1369 LogRel(("PCI: %8s/%u: register %02x: %02x -> %02x\n",
1370 pDev->name, pDev->pDevIns->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
1371 pbDstConfig[off] = pbSrcConfig[off];
1372 }
1373}
1374
1375/**
1376 * Common worker for ich9pciR3LoadExec and ich9pcibridgeR3LoadExec.
1377 *
1378 * @returns VBox status code.
1379 * @param pBus The bus which data is being loaded.
1380 * @param pSSM The saved state handle.
1381 * @param uVersion The data version.
1382 * @param uPass The pass.
1383 */
1384static DECLCALLBACK(int) ich9pciR3CommonLoadExec(PICH9PCIBUS pBus, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1385{
1386 uint32_t u32;
1387 uint32_t i;
1388 int rc;
1389
1390 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1391 if (uVersion != VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT)
1392 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1393
1394 /*
1395 * Iterate thru all the devices and write 0 to the COMMAND register so
1396 * that all the memory is unmapped before we start restoring the saved
1397 * mapping locations.
1398 *
1399 * The register value is restored afterwards so we can do proper
1400 * LogRels in pciR3CommonRestoreConfig.
1401 */
1402 for (i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
1403 {
1404 PPCIDEVICE pDev = pBus->apDevices[i];
1405 if (pDev)
1406 {
1407 uint16_t u16 = PCIDevGetCommand(pDev);
1408 pDev->Int.s.pfnConfigWrite(pDev, VBOX_PCI_COMMAND, 0, 2);
1409 PCIDevSetCommand(pDev, u16);
1410 Assert(PCIDevGetCommand(pDev) == u16);
1411 }
1412 }
1413
1414 void *pvMsixPage = RTMemTmpAllocZ(0x1000);
1415 AssertReturn(pvMsixPage, VERR_NO_TMP_MEMORY);
1416
1417 /*
1418 * Iterate all the devices.
1419 */
1420 for (i = 0;; i++)
1421 {
1422 PPCIDEVICE pDev;
1423 PCIDEVICE DevTmp;
1424
1425 /* index / terminator */
1426 rc = SSMR3GetU32(pSSM, &u32);
1427 if (RT_FAILURE(rc))
1428 break;
1429 if (u32 == (uint32_t)~0)
1430 break;
1431 AssertMsgBreak(u32 < RT_ELEMENTS(pBus->apDevices) && u32 >= i, ("u32=%#x i=%#x\n", u32, i));
1432
1433 /* skip forward to the device checking that no new devices are present. */
1434 for (; i < u32; i++)
1435 {
1436 pDev = pBus->apDevices[i];
1437 if (pDev)
1438 {
1439 LogRel(("PCI: New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pDev->name,
1440 PCIDevGetVendorId(pDev), PCIDevGetDeviceId(pDev)));
1441 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1442 {
1443 rc = SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("New device in slot %#x, %s (vendor=%#06x device=%#06x)"),
1444 i, pDev->name, PCIDevGetVendorId(pDev), PCIDevGetDeviceId(pDev));
1445 break;
1446 }
1447 }
1448 }
1449 if (RT_FAILURE(rc))
1450 break;
1451
1452 /* get the data */
1453 DevTmp.Int.s.fFlags = 0;
1454 DevTmp.Int.s.u8MsiCapOffset = 0;
1455 DevTmp.Int.s.u8MsiCapSize = 0;
1456 DevTmp.Int.s.u8MsixCapOffset = 0;
1457 DevTmp.Int.s.u8MsixCapSize = 0;
1458 DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
1459 SSMR3GetMem(pSSM, DevTmp.config, sizeof(DevTmp.config));
1460
1461 SSMR3GetU32(pSSM, &DevTmp.Int.s.fFlags);
1462 SSMR3GetS32(pSSM, &DevTmp.Int.s.uIrqPinState);
1463 SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsiCapOffset);
1464 SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsiCapSize);
1465 SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsixCapOffset);
1466 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsixCapSize);
1467 if (RT_FAILURE(rc))
1468 break;
1469
1470 /* Load MSI-X page state */
1471 if (DevTmp.Int.s.u8MsixCapOffset != 0)
1472 {
1473 Assert(pvMsixPage != NULL);
1474 rc = SSMR3GetMem(pSSM, pvMsixPage, 0x1000);
1475 if (RT_FAILURE(rc))
1476 break;
1477 }
1478
1479 /* check that it's still around. */
1480 pDev = pBus->apDevices[i];
1481 if (!pDev)
1482 {
1483 LogRel(("PCI: Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", i,
1484 PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp)));
1485 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1486 {
1487 rc = SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x has been removed! vendor=%#06x device=%#06x"),
1488 i, PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp));
1489 break;
1490 }
1491 continue;
1492 }
1493
1494 /* match the vendor id assuming that this will never be changed. */
1495 if (PCIDevGetVendorId(&DevTmp) != PCIDevGetVendorId(pDev))
1496 {
1497 rc = SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
1498 i, pDev->name, PCIDevGetVendorId(&DevTmp), PCIDevGetVendorId(pDev));
1499 break;
1500 }
1501
1502 /* commit the loaded device config. */
1503 Assert(!pciDevIsPassthrough(pDev));
1504 pciR3CommonRestoreConfig(pDev, &DevTmp.config[0], false ); /** @todo fix bridge fun! */
1505
1506 pDev->Int.s.uIrqPinState = DevTmp.Int.s.uIrqPinState;
1507 pDev->Int.s.u8MsiCapOffset = DevTmp.Int.s.u8MsiCapOffset;
1508 pDev->Int.s.u8MsiCapSize = DevTmp.Int.s.u8MsiCapSize;
1509 pDev->Int.s.u8MsixCapOffset = DevTmp.Int.s.u8MsixCapOffset;
1510 pDev->Int.s.u8MsixCapSize = DevTmp.Int.s.u8MsixCapSize;
1511 if (DevTmp.Int.s.u8MsixCapSize != 0)
1512 {
1513 Assert(pDev->Int.s.pMsixPageR3 != NULL);
1514 memcpy(pDev->Int.s.pMsixPageR3, pvMsixPage, 0x1000);
1515 }
1516 }
1517
1518 RTMemTmpFree(pvMsixPage);
1519
1520 return rc;
1521}
1522
1523static DECLCALLBACK(int) ich9pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1524{
1525 PICH9PCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
1526 PICH9PCIBUS pBus = &pThis->aPciBus;
1527 uint32_t u32;
1528 int rc;
1529
1530 /* We ignore this version as there's no saved state with it anyway */
1531 if (uVersion == VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI)
1532 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1533 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI)
1534 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1535
1536 /*
1537 * Bus state data.
1538 */
1539 SSMR3GetU32(pSSM, &pThis->uConfigReg);
1540
1541 /*
1542 * Load IRQ states.
1543 */
1544 for (int i = 0; i < PCI_APIC_IRQ_PINS; i++)
1545 SSMR3GetU32(pSSM, (uint32_t*)&pThis->uaPciApicIrqLevels[i]);
1546
1547 /* separator */
1548 rc = SSMR3GetU32(pSSM, &u32);
1549 if (RT_FAILURE(rc))
1550 return rc;
1551 if (u32 != (uint32_t)~0)
1552 AssertMsgFailedReturn(("u32=%#x\n", u32), rc);
1553
1554 return ich9pciR3CommonLoadExec(pBus, pSSM, uVersion, uPass);
1555}
1556
1557static DECLCALLBACK(int) ich9pcibridgeR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1558{
1559 PICH9PCIBUS pThis = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
1560 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI)
1561 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1562 return ich9pciR3CommonLoadExec(pThis, pSSM, uVersion, uPass);
1563}
1564
1565
1566/*
1567 * Perform imeediate read of configuration space register.
1568 * Cannot be rescheduled, as already in R3.
1569 */
1570static uint32_t ich9pciConfigRead(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t len)
1571{
1572 PciAddress aPciAddr;
1573 aPciAddr.iBus = uBus;
1574 aPciAddr.iDeviceFunc = uDevFn;
1575 aPciAddr.iRegister = addr;
1576
1577 uint32_t u32Val;
1578 int rc = ich9pciDataReadAddr(pGlobals, &aPciAddr, len, &u32Val, VERR_INTERNAL_ERROR);
1579 AssertRC(rc);
1580
1581 return u32Val;
1582}
1583
1584
1585/*
1586 * Perform imeediate write to configuration space register.
1587 * Cannot be rescheduled, as already in R3.
1588 */
1589static void ich9pciConfigWrite(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t val, uint32_t len)
1590{
1591 PciAddress aPciAddr;
1592 aPciAddr.iBus = uBus;
1593 aPciAddr.iDeviceFunc = uDevFn;
1594 aPciAddr.iRegister = addr;
1595
1596 int rc = ich9pciDataWriteAddr(pGlobals, &aPciAddr, val, len, VERR_INTERNAL_ERROR);
1597 AssertRC(rc);
1598}
1599
1600
1601static void ich9pciSetRegionAddress(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, int iRegion, uint64_t addr)
1602{
1603 uint32_t uReg = ich9pciGetRegionReg(iRegion);
1604
1605 /* Read memory type first. */
1606 uint8_t uResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, uReg, 1);
1607 /* Read command register. */
1608 uint16_t uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 2);
1609
1610 Log(("Set region address: %02x:%02x.%d region %d address=%lld\n",
1611 uBus, uDevFn>>3, uDevFn&7, addr));
1612
1613 if ( iRegion == PCI_ROM_SLOT )
1614 uCmd |= PCI_COMMAND_MEMACCESS;
1615 else if ((uResourceType & PCI_ADDRESS_SPACE_IO) == PCI_ADDRESS_SPACE_IO)
1616 uCmd |= PCI_COMMAND_IOACCESS; /* Enable I/O space access. */
1617 else /* The region is MMIO. */
1618 uCmd |= PCI_COMMAND_MEMACCESS; /* Enable MMIO access. */
1619
1620 bool f64Bit = (uResourceType & PCI_ADDRESS_SPACE_BAR64) != 0;
1621
1622 /* Write address of the device. */
1623 ich9pciConfigWrite(pGlobals, uBus, uDevFn, uReg, (uint32_t)addr, 4);
1624 if (f64Bit)
1625 ich9pciConfigWrite(pGlobals, uBus, uDevFn, uReg + 4, (uint32_t)(addr >> 32), 4);
1626
1627 /* enable memory mappings */
1628 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, uCmd, 2);
1629}
1630
1631
1632static void ich9pciBiosInitBridge(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn)
1633{
1634 Log(("BIOS init bridge: %02x::%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
1635
1636 /*
1637 * The I/O range for the bridge must be aligned to a 4KB boundary.
1638 * This does not change anything really as the access to the device is not going
1639 * through the bridge but we want to be compliant to the spec.
1640 */
1641 if ((pGlobals->uPciBiosIo % 4096) != 0)
1642 {
1643 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
1644 Log(("%s: Aligned I/O start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosIo));
1645 }
1646 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_BASE, (pGlobals->uPciBiosIo >> 8) & 0xf0, 1);
1647
1648 /* The MMIO range for the bridge must be aligned to a 1MB boundary. */
1649 if ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0)
1650 {
1651 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
1652 Log(("%s: Aligned MMIO start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosMmio));
1653 }
1654 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_BASE, (pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xffff0), 2);
1655
1656 /* Save values to compare later to. */
1657 uint32_t u32IoAddressBase = pGlobals->uPciBiosIo;
1658 uint32_t u32MMIOAddressBase = pGlobals->uPciBiosMmio;
1659 uint8_t uBridgeBus = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_SECONDARY_BUS, 1);
1660
1661 /* Init devices behind the bridge and possibly other bridges as well. */
1662 for (int iDev = 0; iDev <= 255; iDev++)
1663 ich9pciBiosInitDevice(pGlobals, uBridgeBus, iDev);
1664
1665 /*
1666 * Set I/O limit register. If there is no device with I/O space behind the bridge
1667 * we set a lower value than in the base register.
1668 * The result with a real bridge is that no I/O transactions are passed to the secondary
1669 * interface. Again this doesn't really matter here but we want to be compliant to the spec.
1670 */
1671 if ((u32IoAddressBase != pGlobals->uPciBiosIo) && ((pGlobals->uPciBiosIo % 4096) != 0))
1672 {
1673 /* The upper boundary must be one byte less than a 4KB boundary. */
1674 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
1675 }
1676
1677 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_LIMIT, ((pGlobals->uPciBiosIo >> 8) & 0xf0) - 1, 1);
1678
1679 /* Same with the MMIO limit register but with 1MB boundary here. */
1680 if ((u32MMIOAddressBase != pGlobals->uPciBiosMmio) && ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0))
1681 {
1682 /* The upper boundary must be one byte less than a 1MB boundary. */
1683 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
1684 }
1685 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_LIMIT, ((pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xfff0)) - 1, 2);
1686
1687 /*
1688 * Set the prefetch base and limit registers. We currently have no device with a prefetchable region
1689 * which may be behind a bridge. That's why it is unconditionally disabled here atm by writing a higher value into
1690 * the base register than in the limit register.
1691 */
1692 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_BASE, 0xfff0, 2);
1693 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_LIMIT, 0x0, 2);
1694 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_BASE_UPPER32, 0x00, 4);
1695 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_LIMIT_UPPER32, 0x00, 4);
1696}
1697
1698static void ich9pciBiosInitDevice(PICH9PCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn)
1699{
1700 uint16_t uDevClass, uVendor, uDevice;
1701 uint8_t uCmd;
1702
1703 uDevClass = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_CLASS_DEVICE, 2);
1704 uVendor = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_VENDOR_ID, 2);
1705 uDevice = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_DEVICE_ID, 2);
1706
1707 /* If device is present */
1708 if (uVendor == 0xffff)
1709 return;
1710
1711 Log(("BIOS init device: %02x:%02x.%d\n", uBus, uDevFn >> 3, uDevFn & 7));
1712
1713 switch (uDevClass)
1714 {
1715 case 0x0101:
1716 /* IDE controller */
1717 ich9pciConfigWrite(pGlobals, uBus, uDevFn, 0x40, 0x8000, 2); /* enable IDE0 */
1718 ich9pciConfigWrite(pGlobals, uBus, uDevFn, 0x42, 0x8000, 2); /* enable IDE1 */
1719 goto default_map;
1720 break;
1721 case 0x0300:
1722 /* VGA controller */
1723 if (uVendor != 0x80ee)
1724 goto default_map;
1725 /* VGA: map frame buffer to default Bochs VBE address */
1726 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, 0, 0xE0000000);
1727 /*
1728 * Legacy VGA I/O ports are implicitly decoded by a VGA class device. But
1729 * only the framebuffer (i.e., a memory region) is explicitly registered via
1730 * ich9pciSetRegionAddress, so I/O decoding must be enabled manually.
1731 */
1732 uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 1);
1733 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND,
1734 /* Enable I/O space access. */
1735 uCmd | PCI_COMMAND_IOACCESS,
1736 1);
1737 break;
1738 case 0x0604:
1739 /* PCI-to-PCI bridge. */
1740 AssertMsg(pGlobals->uBus < 255, ("Too many bridges on the bus\n"));
1741 ich9pciBiosInitBridge(pGlobals, uBus, uDevFn);
1742 break;
1743 default:
1744 default_map:
1745 {
1746 /* default memory mappings */
1747 /*
1748 * We ignore ROM region here.
1749 */
1750 for (int iRegion = 0; iRegion < (PCI_NUM_REGIONS-1); iRegion++)
1751 {
1752 uint32_t u32Address = ich9pciGetRegionReg(iRegion);
1753
1754 /* Calculate size - we write all 1s into the BAR, and then evaluate which bits
1755 are cleared. . */
1756 uint8_t u8ResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 1);
1757
1758 bool f64bit = (u8ResourceType & PCI_ADDRESS_SPACE_BAR64) != 0;
1759 bool fIsPio = ((u8ResourceType & PCI_COMMAND_IOACCESS) == PCI_COMMAND_IOACCESS);
1760 uint64_t cbRegSize64 = 0;
1761
1762 if (f64bit)
1763 {
1764 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
1765 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address+4, UINT32_C(0xffffffff), 4);
1766 cbRegSize64 = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4);
1767 cbRegSize64 |= ((uint64_t)ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address+4, 4) << 32);
1768 cbRegSize64 &= ~UINT64_C(0x0f);
1769 cbRegSize64 = (~cbRegSize64) + 1;
1770
1771 /* No 64-bit PIO regions possible. */
1772#ifndef DEBUG_bird /* EFI triggers this for DevAHCI. */
1773 AssertMsg((u8ResourceType & PCI_COMMAND_IOACCESS) == 0, ("type=%#x rgn=%d\n", u8ResourceType, iRegion));
1774#endif
1775 }
1776 else
1777 {
1778 uint32_t cbRegSize32;
1779 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
1780 cbRegSize32 = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4);
1781
1782 /* Clear resource information depending on resource type. */
1783 if (fIsPio) /* PIO */
1784 cbRegSize32 &= ~UINT32_C(0x01);
1785 else /* MMIO */
1786 cbRegSize32 &= ~UINT32_C(0x0f);
1787
1788 /*
1789 * Invert all bits and add 1 to get size of the region.
1790 * (From PCI implementation note)
1791 */
1792 if (fIsPio && (cbRegSize32 & UINT32_C(0xffff0000)) == 0)
1793 cbRegSize32 = (~(cbRegSize32 | UINT32_C(0xffff0000))) + 1;
1794 else
1795 cbRegSize32 = (~cbRegSize32) + 1;
1796
1797 cbRegSize64 = cbRegSize32;
1798 }
1799#ifndef DEBUG_bird /* EFI triggers this for DevAHCI. */
1800 Assert(cbRegSize64 == (uint32_t)cbRegSize64);
1801#endif
1802 Log2(("%s: Size of region %u for device %d on bus %d is %lld\n", __FUNCTION__, iRegion, uDevFn, uBus, cbRegSize64));
1803
1804 if (cbRegSize64)
1805 {
1806 uint32_t cbRegSize32 = (uint32_t)cbRegSize64;
1807 uint32_t* paddr = fIsPio ? &pGlobals->uPciBiosIo : &pGlobals->uPciBiosMmio;
1808 *paddr = (*paddr + cbRegSize32 - 1) & ~(cbRegSize32 - 1);
1809 Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, (fIsPio ? "I/O" : "MMIO"), iRegion, *paddr));
1810 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, iRegion, *paddr);
1811 *paddr += cbRegSize32;
1812 Log2(("%s: New address is %#x\n", __FUNCTION__, *paddr));
1813
1814 if (f64bit)
1815 iRegion++; /* skip next region */
1816 }
1817 }
1818 break;
1819 }
1820 }
1821
1822 /* map the interrupt */
1823 uint32_t iPin = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_INTERRUPT_PIN, 1);
1824 if (iPin != 0)
1825 {
1826 iPin--;
1827
1828 if (uBus != 0)
1829 {
1830 /* Find bus this device attached to. */
1831 PICH9PCIBUS pBus = &pGlobals->aPciBus;
1832 while (1)
1833 {
1834 PPCIDEVICE pBridge = ich9pciFindBridge(pBus, uBus);
1835 if (!pBridge)
1836 {
1837 Assert(false);
1838 break;
1839 }
1840 if (uBus == PCIDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS))
1841 {
1842 /* OK, found bus this device attached to. */
1843 break;
1844 }
1845 pBus = PDMINS_2_DATA(pBridge->pDevIns, PICH9PCIBUS);
1846 }
1847
1848 /* We need to go up to the host bus to see which irq pin this
1849 * device will use there. See logic in ich9pcibridgeSetIrq().
1850 */
1851 while (pBus->iBus != 0)
1852 {
1853 /* Get the pin the device would assert on the bridge. */
1854 iPin = ((pBus->aPciDev.devfn >> 3) + iPin) & 3;
1855 pBus = pBus->aPciDev.Int.s.pBusR3;
1856 };
1857 }
1858
1859 int iIrq = aPciIrqs[ich9pciSlotGetPirq(uBus, uDevFn, iPin)];
1860 Log(("Using pin %d and IRQ %d for device %02x:%02x.%d\n",
1861 iPin, iIrq, uBus, uDevFn>>3, uDevFn&7));
1862 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_INTERRUPT_LINE, iIrq, 1);
1863 }
1864}
1865
1866/**
1867 * Initializes bridges registers used for routing.
1868 *
1869 * @returns nothing.
1870 * @param pGlobals Global device instance data used to generate unique bus numbers.
1871 * @param pBus The PCI bus to initialize.
1872 * @param uBusPrimary The primary bus number the bus is connected to.
1873 * @param uBusSecondary The secondary bus number, i.e. the bus number behind the bridge.
1874 */
1875static void ich9pciInitBridgeTopology(PICH9PCIGLOBALS pGlobals, PICH9PCIBUS pBus, unsigned uBusPrimary,
1876 unsigned uBusSecondary)
1877{
1878 PPCIDEVICE pBridgeDev = &pBus->aPciDev;
1879
1880 /* Set only if we are not on the root bus, it has no primary bus attached. */
1881 if (uBusSecondary != 0)
1882 {
1883 PCIDevSetByte(pBridgeDev, VBOX_PCI_PRIMARY_BUS, uBusPrimary);
1884 PCIDevSetByte(pBridgeDev, VBOX_PCI_SECONDARY_BUS, uBusSecondary);
1885 }
1886
1887 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
1888 {
1889 PPCIDEVICE pBridge = pBus->papBridgesR3[iBridge];
1890 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
1891 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
1892 PICH9PCIBUS pChildBus = PDMINS_2_DATA(pBridge->pDevIns, PICH9PCIBUS);
1893 pGlobals->uBus++;
1894 ich9pciInitBridgeTopology(pGlobals, pChildBus, uBusSecondary, pGlobals->uBus);
1895 }
1896 PCIDevSetByte(pBridgeDev, VBOX_PCI_SUBORDINATE_BUS, pGlobals->uBus);
1897 Log2(("ich9pciInitBridgeTopology: for bus %p: primary=%d secondary=%d subordinate=%d\n",
1898 pBus,
1899 PCIDevGetByte(pBridgeDev, VBOX_PCI_PRIMARY_BUS),
1900 PCIDevGetByte(pBridgeDev, VBOX_PCI_SECONDARY_BUS),
1901 PCIDevGetByte(pBridgeDev, VBOX_PCI_SUBORDINATE_BUS)
1902 ));
1903}
1904
1905
1906static DECLCALLBACK(int) ich9pciFakePCIBIOS(PPDMDEVINS pDevIns)
1907{
1908 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
1909 PVM pVM = PDMDevHlpGetVM(pDevIns);
1910 Assert(pVM);
1911
1912 /*
1913 * Set the start addresses.
1914 */
1915 pGlobals->uPciBiosIo = 0xd000;
1916 pGlobals->uPciBiosMmio = UINT32_C(0xf0000000);
1917 pGlobals->uBus = 0;
1918
1919 /*
1920 * Assign bridge topology, for further routing to work.
1921 */
1922 PICH9PCIBUS pBus = &pGlobals->aPciBus;
1923 ich9pciInitBridgeTopology(pGlobals, pBus, 0, 0);
1924
1925 /*
1926 * Init the devices.
1927 */
1928 for (int i = 0; i < 256; i++)
1929 {
1930 ich9pciBiosInitDevice(pGlobals, 0, i);
1931 }
1932
1933 return VINF_SUCCESS;
1934}
1935
1936
1937/*
1938 * Configuration space read callback (PCIDEVICEINT::pfnConfigRead) for
1939 * connected devices.
1940 */
1941static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PCIDevice *aDev, uint32_t u32Address, unsigned len)
1942{
1943 if ((u32Address + len) > 256 && (u32Address + len) < 4096)
1944 {
1945 LogRel(("PCI: Read from extended register %d fallen back to generic code\n",
1946 u32Address));
1947 return 0;
1948 }
1949
1950 AssertMsgReturn(u32Address + len <= 256, ("Read after the end of PCI config space\n"),
1951 0);
1952 if ( pciDevIsMsiCapable(aDev)
1953 && (u32Address >= aDev->Int.s.u8MsiCapOffset)
1954 && (u32Address < (unsigned)(aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize))
1955 )
1956 {
1957 return MsiPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
1958 }
1959
1960 if ( pciDevIsMsixCapable(aDev)
1961 && (u32Address >= aDev->Int.s.u8MsixCapOffset)
1962 && (u32Address < (unsigned)(aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize))
1963 )
1964 {
1965 return MsixPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
1966 }
1967
1968 AssertMsgReturn(u32Address + len <= 256, ("Read after end of PCI config space\n"),
1969 0);
1970 switch (len)
1971 {
1972 case 1:
1973 return PCIDevGetByte(aDev, u32Address);
1974 case 2:
1975 return PCIDevGetWord(aDev, u32Address);
1976 case 4:
1977 return PCIDevGetDWord(aDev, u32Address);
1978 default:
1979 Assert(false);
1980 return 0;
1981 }
1982}
1983
1984
1985DECLINLINE(void) ich9pciWriteBarByte(PCIDevice *aDev, int iRegion, int iOffset, uint8_t u8Val)
1986{
1987 PCIIORegion * pRegion = &aDev->Int.s.aIORegions[iRegion];
1988 int64_t iRegionSize = pRegion->size;
1989
1990 Log3(("ich9pciWriteBarByte: region=%d off=%d val=%x size=%d\n",
1991 iRegion, iOffset, u8Val, iRegionSize));
1992
1993 if (iOffset > 3)
1994 Assert((pRegion->type & PCI_ADDRESS_SPACE_BAR64) != 0);
1995
1996 /* Check if we're writing to upper part of 64-bit BAR. */
1997 if (pRegion->type == 0xff)
1998 {
1999 ich9pciWriteBarByte(aDev, iRegion-1, iOffset+4, u8Val);
2000 return;
2001 }
2002
2003 /* Region doesn't exist */
2004 if (iRegionSize == 0)
2005 return;
2006
2007 uint32_t uAddr = ich9pciGetRegionReg(iRegion) + iOffset;
2008 /* Region size must be power of two */
2009 Assert((iRegionSize & (iRegionSize - 1)) == 0);
2010 uint8_t uMask = ((iRegionSize - 1) >> (iOffset*8) ) & 0xff;
2011
2012 if (iOffset == 0)
2013 {
2014 uMask |= (pRegion->type & PCI_ADDRESS_SPACE_IO) ?
2015 (1 << 2) - 1 /* 2 lowest bits for IO region */ :
2016 (1 << 4) - 1 /* 4 lowest bits for memory region, also ROM enable bit for ROM region */;
2017
2018 }
2019
2020 uint8_t u8Old = PCIDevGetByte(aDev, uAddr) & uMask;
2021 u8Val = (u8Old & uMask) | (u8Val & ~uMask);
2022
2023 Log3(("ich9pciWriteBarByte: was %x writing %x\n", u8Old, u8Val));
2024
2025 PCIDevSetByte(aDev, uAddr, u8Val);
2026}
2027
2028
2029/**
2030 * Configuration space write callback (PCIDEVICEINT::pfnConfigWrite)
2031 * for connected devices.
2032 *
2033 * See paragraph 7.5 of PCI Express specification (p. 349) for
2034 * definition of registers and their writability policy.
2035 */
2036static DECLCALLBACK(void) ich9pciConfigWriteDev(PCIDevice *aDev, uint32_t u32Address,
2037 uint32_t val, unsigned len)
2038{
2039 Assert(len <= 4);
2040
2041 if ((u32Address + len) > 256 && (u32Address + len) < 4096)
2042 {
2043 LogRel(("PCI: Write to extended register %d fallen back to generic code\n",
2044 u32Address));
2045 return;
2046 }
2047
2048 AssertMsgReturnVoid(u32Address + len <= 256, ("Write after end of PCI config space\n"));
2049
2050 if ( pciDevIsMsiCapable(aDev)
2051 && (u32Address >= aDev->Int.s.u8MsiCapOffset)
2052 && (u32Address < (unsigned)(aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize))
2053 )
2054 {
2055 MsiPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
2056 aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
2057 aDev, u32Address, val, len);
2058 return;
2059 }
2060
2061 if ( pciDevIsMsixCapable(aDev)
2062 && (u32Address >= aDev->Int.s.u8MsixCapOffset)
2063 && (u32Address < (unsigned)(aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize))
2064 )
2065 {
2066 MsixPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
2067 aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
2068 aDev, u32Address, val, len);
2069 return;
2070 }
2071
2072 uint32_t addr = u32Address;
2073 bool fUpdateMappings = false;
2074 bool fP2PBridge = false;
2075 /*bool fPassthrough = pciDevIsPassthrough(aDev);*/
2076 uint8_t u8HeaderType = ich9pciGetByte(aDev, VBOX_PCI_HEADER_TYPE);
2077
2078 for (uint32_t i = 0; i < len; i++)
2079 {
2080 bool fWritable = false;
2081 bool fRom = false;
2082 switch (u8HeaderType)
2083 {
2084 case 0x00: /* normal device */
2085 case 0x80: /* multi-function device */
2086 switch (addr)
2087 {
2088 /* Read-only registers */
2089 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
2090 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
2091 case VBOX_PCI_REVISION_ID:
2092 case VBOX_PCI_CLASS_PROG:
2093 case VBOX_PCI_CLASS_SUB:
2094 case VBOX_PCI_CLASS_BASE:
2095 case VBOX_PCI_HEADER_TYPE:
2096 case VBOX_PCI_SUBSYSTEM_VENDOR_ID: case VBOX_PCI_SUBSYSTEM_VENDOR_ID+1:
2097 case VBOX_PCI_SUBSYSTEM_ID: case VBOX_PCI_SUBSYSTEM_ID+1:
2098 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS+1: case VBOX_PCI_ROM_ADDRESS+2: case VBOX_PCI_ROM_ADDRESS+3:
2099 case VBOX_PCI_CAPABILITY_LIST:
2100 case VBOX_PCI_INTERRUPT_PIN:
2101 fWritable = false;
2102 break;
2103 /* Others can be written */
2104 default:
2105 fWritable = true;
2106 break;
2107 }
2108 break;
2109 case 0x01: /* PCI-PCI bridge */
2110 fP2PBridge = true;
2111 switch (addr)
2112 {
2113 /* Read-only registers */
2114 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
2115 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
2116 case VBOX_PCI_REVISION_ID:
2117 case VBOX_PCI_CLASS_PROG:
2118 case VBOX_PCI_CLASS_SUB:
2119 case VBOX_PCI_CLASS_BASE:
2120 case VBOX_PCI_HEADER_TYPE:
2121 case VBOX_PCI_ROM_ADDRESS_BR: case VBOX_PCI_ROM_ADDRESS_BR+1: case VBOX_PCI_ROM_ADDRESS_BR+2: case VBOX_PCI_ROM_ADDRESS_BR+3:
2122 case VBOX_PCI_INTERRUPT_PIN:
2123 fWritable = false;
2124 break;
2125 default:
2126 fWritable = true;
2127 break;
2128 }
2129 break;
2130 default:
2131 AssertMsgFailed(("Unknown header type %x\n", PCIDevGetHeaderType(aDev)));
2132 fWritable = false;
2133 break;
2134 }
2135
2136 uint8_t u8Val = (uint8_t)val;
2137 switch (addr)
2138 {
2139 case VBOX_PCI_COMMAND: /* Command register, bits 0-7. */
2140 fUpdateMappings = true;
2141 goto default_case;
2142 case VBOX_PCI_COMMAND+1: /* Command register, bits 8-15. */
2143 /* don't change reserved bits (11-15) */
2144 u8Val &= UINT32_C(~0xf8);
2145 fUpdateMappings = true;
2146 goto default_case;
2147 case VBOX_PCI_STATUS: /* Status register, bits 0-7. */
2148 /* don't change read-only bits => actually all lower bits are read-only */
2149 u8Val &= UINT32_C(~0xff);
2150 /* status register, low part: clear bits by writing a '1' to the corresponding bit */
2151 aDev->config[addr] &= ~u8Val;
2152 break;
2153 case VBOX_PCI_STATUS+1: /* Status register, bits 8-15. */
2154 /* don't change read-only bits */
2155 u8Val &= UINT32_C(~0x06);
2156 /* status register, high part: clear bits by writing a '1' to the corresponding bit */
2157 aDev->config[addr] &= ~u8Val;
2158 break;
2159 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS +1: case VBOX_PCI_ROM_ADDRESS +2: case VBOX_PCI_ROM_ADDRESS +3:
2160 fRom = true;
2161 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:
2162 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:
2163 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:
2164 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:
2165 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:
2166 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:
2167 {
2168 /* We check that, as same PCI register numbers as BARs may mean different registers for bridges */
2169 if (fP2PBridge)
2170 goto default_case;
2171 else
2172 {
2173 int iRegion = fRom ? VBOX_PCI_ROM_SLOT : (addr - VBOX_PCI_BASE_ADDRESS_0) >> 2;
2174 int iOffset = addr & 0x3;
2175 ich9pciWriteBarByte(aDev, iRegion, iOffset, u8Val);
2176 fUpdateMappings = true;
2177 }
2178 break;
2179 }
2180 default:
2181 default_case:
2182 if (fWritable)
2183 PCIDevSetByte(aDev, addr, u8Val);
2184 }
2185 addr++;
2186 val >>= 8;
2187 }
2188
2189 if (fUpdateMappings)
2190 /* if the command/base address register is modified, we must modify the mappings */
2191 ich9pciUpdateMappings(aDev);
2192}
2193
2194static bool assignPosition(PICH9PCIBUS pBus, PPCIDEVICE pPciDev, const char *pszName, int iDevFn, PciAddress* aPosition)
2195{
2196 NOREF(pszName);
2197 aPosition->iBus = 0;
2198 aPosition->iDeviceFunc = iDevFn;
2199 aPosition->iRegister = 0; /* N/A */
2200
2201 /* Explicit slot request */
2202 if (iDevFn >= 0 && iDevFn < (int)RT_ELEMENTS(pBus->apDevices))
2203 return true;
2204
2205 int iStartPos = 0;
2206
2207 /* Otherwise when assigning a slot, we need to make sure all its functions are available */
2208 for (int iPos = iStartPos; iPos < (int)RT_ELEMENTS(pBus->apDevices); iPos += 8)
2209 {
2210 if ( !pBus->apDevices[iPos]
2211 && !pBus->apDevices[iPos + 1]
2212 && !pBus->apDevices[iPos + 2]
2213 && !pBus->apDevices[iPos + 3]
2214 && !pBus->apDevices[iPos + 4]
2215 && !pBus->apDevices[iPos + 5]
2216 && !pBus->apDevices[iPos + 6]
2217 && !pBus->apDevices[iPos + 7])
2218 {
2219 pciDevClearRequestedDevfunc(pPciDev);
2220 aPosition->iDeviceFunc = iPos;
2221 return true;
2222 }
2223 }
2224
2225 return false;
2226}
2227
2228#ifdef SOME_UNUSED_FUNCTION
2229static bool hasHardAssignedDevsInSlot(PICH9PCIBUS pBus, int iSlot)
2230{
2231 PCIDevice** aSlot = &pBus->apDevices[iSlot << 3];
2232
2233 return (aSlot[0] && pciDevIsRequestedDevfunc(aSlot[0]))
2234 || (aSlot[1] && pciDevIsRequestedDevfunc(aSlot[1]))
2235 || (aSlot[2] && pciDevIsRequestedDevfunc(aSlot[2]))
2236 || (aSlot[3] && pciDevIsRequestedDevfunc(aSlot[3]))
2237 || (aSlot[4] && pciDevIsRequestedDevfunc(aSlot[4]))
2238 || (aSlot[5] && pciDevIsRequestedDevfunc(aSlot[5]))
2239 || (aSlot[6] && pciDevIsRequestedDevfunc(aSlot[6]))
2240 || (aSlot[7] && pciDevIsRequestedDevfunc(aSlot[7]))
2241 ;
2242}
2243#endif
2244
2245static int ich9pciRegisterInternal(PICH9PCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName)
2246{
2247 PciAddress aPosition;
2248 aPosition.iBus = 0;
2249 aPosition.iDeviceFunc = 0;
2250 aPosition.iRegister = 0;
2251
2252 /*
2253 * Find device position
2254 */
2255 if (!assignPosition(pBus, pPciDev, pszName, iDev, &aPosition))
2256 {
2257 AssertMsgFailed(("Couldn't asssign position!\n"));
2258 return VERR_PDM_TOO_PCI_MANY_DEVICES;
2259 }
2260
2261 AssertMsgReturn(aPosition.iBus == 0,
2262 ("Assigning behind the bridge not implemented yet\n"),
2263 VERR_PDM_TOO_PCI_MANY_DEVICES);
2264
2265
2266 iDev = aPosition.iDeviceFunc;
2267 /*
2268 * Check if we can really take this slot, possibly by relocating
2269 * its current habitant, if it wasn't hard assigned too.
2270 */
2271 if (pciDevIsRequestedDevfunc(pPciDev) &&
2272 pBus->apDevices[iDev] &&
2273 pciDevIsRequestedDevfunc(pBus->apDevices[iDev]))
2274 {
2275 AssertReleaseMsgFailed(("Configuration error:'%s' and '%s' are both configured as device %d\n",
2276 pszName, pBus->apDevices[iDev]->name, iDev));
2277 return VERR_INTERNAL_ERROR;
2278 }
2279
2280 if (pBus->apDevices[iDev])
2281 {
2282 /* if we got here, we shall (and usually can) relocate the device */
2283 bool assigned = assignPosition(pBus, pBus->apDevices[iDev], pBus->apDevices[iDev]->name, -1, &aPosition);
2284 AssertMsgReturn(aPosition.iBus == 0,
2285 ("Assigning behind the bridge not implemented yet\n"),
2286 VERR_PDM_TOO_PCI_MANY_DEVICES);
2287 int iRelDev = aPosition.iDeviceFunc;
2288 if (!assigned || iRelDev == iDev)
2289 {
2290 AssertMsgFailed(("Couldn't find free spot!\n"));
2291 return VERR_PDM_TOO_PCI_MANY_DEVICES;
2292 }
2293 /* Copy device function by function to its new position */
2294 for (int i = 0; i < 8; i++)
2295 {
2296 if (!pBus->apDevices[iDev + i])
2297 continue;
2298 Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->apDevices[iDev + i]->name, iDev + i, iRelDev + i));
2299 pBus->apDevices[iRelDev + i] = pBus->apDevices[iDev + i];
2300 pBus->apDevices[iRelDev + i]->devfn = iRelDev + i;
2301 pBus->apDevices[iDev + i] = NULL;
2302 }
2303 }
2304
2305 /*
2306 * Fill in device information.
2307 */
2308 pPciDev->devfn = iDev;
2309 pPciDev->name = pszName;
2310 pPciDev->Int.s.pBusR3 = pBus;
2311 pPciDev->Int.s.pBusR0 = MMHyperR3ToR0(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
2312 pPciDev->Int.s.pBusRC = MMHyperR3ToRC(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
2313 pPciDev->Int.s.pfnConfigRead = ich9pciConfigReadDev;
2314 pPciDev->Int.s.pfnConfigWrite = ich9pciConfigWriteDev;
2315 pBus->apDevices[iDev] = pPciDev;
2316 if (pciDevIsPci2PciBridge(pPciDev))
2317 {
2318 AssertMsg(pBus->cBridges < RT_ELEMENTS(pBus->apDevices), ("Number of bridges exceeds the number of possible devices on the bus\n"));
2319 AssertMsg(pPciDev->Int.s.pfnBridgeConfigRead && pPciDev->Int.s.pfnBridgeConfigWrite,
2320 ("device is a bridge but does not implement read/write functions\n"));
2321 Log2(("Setting bridge %d on bus %p\n", pBus->cBridges, pBus));
2322 pBus->papBridgesR3[pBus->cBridges] = pPciDev;
2323 pBus->cBridges++;
2324 }
2325
2326 Log(("PCI: Registered device %d function %d on bus %d (%#x) '%s'.\n",
2327 iDev >> 3, iDev & 7, pBus->iBus, 0x80000000 | (iDev << 8), pszName));
2328
2329 return VINF_SUCCESS;
2330}
2331
2332static void printIndent(PCDBGFINFOHLP pHlp, int iIndent)
2333{
2334 for (int i = 0; i < iIndent; i++)
2335 {
2336 pHlp->pfnPrintf(pHlp, " ");
2337 }
2338}
2339
2340static void ich9pciBusInfo(PICH9PCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bool fRegisters)
2341{
2342 for (uint32_t iDev = 0; iDev < RT_ELEMENTS(pBus->apDevices); iDev++)
2343 {
2344 PPCIDEVICE pPciDev = pBus->apDevices[iDev];
2345 if (pPciDev != NULL)
2346 {
2347 printIndent(pHlp, iIndent);
2348
2349 /*
2350 * For passthrough devices MSI/MSI-X mostly reflects the way interrupts delivered to the guest,
2351 * as host driver handles real devices interrupts.
2352 */
2353 pHlp->pfnPrintf(pHlp, "%02x:%02x:%02x %s%s: %04x-%04x%s%s",
2354 pBus->iBus, (iDev >> 3) & 0xff, iDev & 0x7,
2355 pPciDev->name,
2356 pciDevIsPassthrough(pPciDev) ? " (PASSTHROUGH)" : "",
2357 ich9pciGetWord(pPciDev, VBOX_PCI_VENDOR_ID), ich9pciGetWord(pPciDev, VBOX_PCI_DEVICE_ID),
2358 pciDevIsMsiCapable(pPciDev) ? " MSI" : "",
2359 pciDevIsMsixCapable(pPciDev) ? " MSI-X" : ""
2360 );
2361 if (ich9pciGetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN) != 0)
2362 pHlp->pfnPrintf(pHlp, " IRQ%d", ich9pciGetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE));
2363
2364 pHlp->pfnPrintf(pHlp, "\n");
2365
2366 uint16_t iCmd = ich9pciGetWord(pPciDev, VBOX_PCI_COMMAND);
2367 if ((iCmd & (VBOX_PCI_COMMAND_IO | VBOX_PCI_COMMAND_MEMORY)) != 0)
2368 {
2369 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
2370 {
2371 PCIIORegion* pRegion = &pPciDev->Int.s.aIORegions[iRegion];
2372 uint64_t iRegionSize = pRegion->size;
2373
2374 if (iRegionSize == 0)
2375 continue;
2376
2377 uint32_t u32Addr = ich9pciGetDWord(pPciDev, ich9pciGetRegionReg(iRegion));
2378 const char * pszDesc;
2379 char szDescBuf[128];
2380
2381 bool f64Bit = !!(pRegion->type & PCI_ADDRESS_SPACE_BAR64);
2382 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
2383 {
2384 pszDesc = "IO";
2385 u32Addr &= ~0x3;
2386 }
2387 else
2388 {
2389 RTStrPrintf(szDescBuf, sizeof(szDescBuf), "MMIO%s%s",
2390 f64Bit ? "64" : "32",
2391 (pRegion->type & PCI_ADDRESS_SPACE_MEM_PREFETCH) ? " PREFETCH" : "");
2392 pszDesc = szDescBuf;
2393 u32Addr &= ~0xf;
2394 }
2395
2396 printIndent(pHlp, iIndent + 2);
2397 pHlp->pfnPrintf(pHlp, "%s region #%d: %x..%x\n",
2398 pszDesc, iRegion, u32Addr, u32Addr+iRegionSize);
2399 if (f64Bit)
2400 iRegion++;
2401 }
2402 }
2403
2404 printIndent(pHlp, iIndent + 2);
2405 uint16_t iStatus = ich9pciGetWord(pPciDev, VBOX_PCI_STATUS);
2406 pHlp->pfnPrintf(pHlp, "Command: %.*Rhxs, Status: %.*Rhxs\n",
2407 sizeof(uint16_t), &iCmd, sizeof(uint16_t), &iStatus);
2408 printIndent(pHlp, iIndent + 2);
2409 pHlp->pfnPrintf(pHlp, "Bus master: %s\n",
2410 iCmd & VBOX_PCI_COMMAND_MASTER ? "Yes" : "No");
2411
2412 if (fRegisters)
2413 {
2414 printIndent(pHlp, iIndent + 2);
2415 pHlp->pfnPrintf(pHlp, "PCI registers:\n");
2416 for (int iReg = 0; iReg < 0x100; )
2417 {
2418 int iPerLine = 0x10;
2419 Assert (0x100 % iPerLine == 0);
2420 printIndent(pHlp, iIndent + 3);
2421
2422 while (iPerLine-- > 0)
2423 {
2424 pHlp->pfnPrintf(pHlp, "%02x ", ich9pciGetByte(pPciDev, iReg++));
2425 }
2426 pHlp->pfnPrintf(pHlp, "\n");
2427 }
2428 }
2429 }
2430 }
2431
2432 if (pBus->cBridges > 0)
2433 {
2434 printIndent(pHlp, iIndent);
2435 pHlp->pfnPrintf(pHlp, "Registered %d bridges, subordinate buses info follows\n", pBus->cBridges);
2436 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2437 {
2438 PICH9PCIBUS pBusSub = PDMINS_2_DATA(pBus->papBridgesR3[iBridge]->pDevIns, PICH9PCIBUS);
2439 ich9pciBusInfo(pBusSub, pHlp, iIndent + 1, fRegisters);
2440 }
2441 }
2442}
2443
2444/**
2445 * Info handler, device version.
2446 *
2447 * @param pDevIns Device instance which registered the info.
2448 * @param pHlp Callback functions for doing output.
2449 * @param pszArgs Argument string. Optional and specific to the handler.
2450 */
2451static DECLCALLBACK(void) ich9pciInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2452{
2453 PICH9PCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
2454
2455 if (pszArgs == NULL || !strcmp(pszArgs, "basic"))
2456 {
2457 ich9pciBusInfo(pBus, pHlp, 0, false);
2458 }
2459 else if (!strcmp(pszArgs, "verbose"))
2460 {
2461 ich9pciBusInfo(pBus, pHlp, 0, true);
2462 }
2463 else
2464 {
2465 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'verbose'.\n");
2466 }
2467}
2468
2469
2470static DECLCALLBACK(int) ich9pciConstruct(PPDMDEVINS pDevIns,
2471 int iInstance,
2472 PCFGMNODE pCfg)
2473{
2474 Assert(iInstance == 0);
2475 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2476
2477 /*
2478 * Validate and read configuration.
2479 */
2480 if (!CFGMR3AreValuesValid(pCfg,
2481 "IOAPIC\0"
2482 "GCEnabled\0"
2483 "R0Enabled\0"
2484 "McfgBase\0"
2485 "McfgLength\0"
2486 ))
2487 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2488
2489 /* query whether we got an IOAPIC */
2490 bool fUseIoApic;
2491 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fUseIoApic, false);
2492 if (RT_FAILURE(rc))
2493 return PDMDEV_SET_ERROR(pDevIns, rc,
2494 N_("Configuration error: Failed to query boolean value \"IOAPIC\""));
2495
2496 /* check if RC code is enabled. */
2497 bool fGCEnabled;
2498 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2499 if (RT_FAILURE(rc))
2500 return PDMDEV_SET_ERROR(pDevIns, rc,
2501 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2502 /* check if R0 code is enabled. */
2503 bool fR0Enabled;
2504 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2505 if (RT_FAILURE(rc))
2506 return PDMDEV_SET_ERROR(pDevIns, rc,
2507 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2508
2509 Log(("PCI: fUseIoApic=%RTbool fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fUseIoApic, fGCEnabled, fR0Enabled));
2510
2511 /*
2512 * Init data.
2513 */
2514 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2515 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2516 /* Zero out everything */
2517 memset(pGlobals, 0, sizeof(*pGlobals));
2518 /* And fill values */
2519 if (!fUseIoApic)
2520 return PDMDEV_SET_ERROR(pDevIns, rc,
2521 N_("Must use IO-APIC with ICH9 chipset"));
2522 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pGlobals->u64PciConfigMMioAddress, 0);
2523 if (RT_FAILURE(rc))
2524 return PDMDEV_SET_ERROR(pDevIns, rc,
2525 N_("Configuration error: Failed to read \"McfgBase\""));
2526 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pGlobals->u64PciConfigMMioLength, 0);
2527 if (RT_FAILURE(rc))
2528 return PDMDEV_SET_ERROR(pDevIns, rc,
2529 N_("Configuration error: Failed to read \"McfgLength\""));
2530
2531 pGlobals->pDevInsR3 = pDevIns;
2532 pGlobals->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2533 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2534
2535 pGlobals->aPciBus.pDevInsR3 = pDevIns;
2536 pGlobals->aPciBus.pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2537 pGlobals->aPciBus.pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2538 pGlobals->aPciBus.papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pGlobals->aPciBus.apDevices));
2539
2540 /*
2541 * Register bus
2542 */
2543 PDMPCIBUSREG PciBusReg;
2544 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2545 PciBusReg.pfnRegisterR3 = ich9pciRegister;
2546 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
2547 PciBusReg.pfnIORegionRegisterR3 = ich9pciIORegionRegister;
2548 PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
2549 PciBusReg.pfnSetIrqR3 = ich9pciSetIrq;
2550 PciBusReg.pfnFakePCIBIOSR3 = ich9pciFakePCIBIOS;
2551 PciBusReg.pszSetIrqRC = fGCEnabled ? "ich9pciSetIrq" : NULL;
2552 PciBusReg.pszSetIrqR0 = fR0Enabled ? "ich9pciSetIrq" : NULL;
2553 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2554 if (RT_FAILURE(rc))
2555 return PDMDEV_SET_ERROR(pDevIns, rc,
2556 N_("Failed to register ourselves as a PCI Bus"));
2557 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2558 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2559 N_("PCI helper version mismatch; got %#x expected %#x"),
2560 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
2561
2562 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2563 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2564
2565 /*
2566 * Fill in PCI configs and add them to the bus.
2567 */
2568 /** @todo: Disabled for now because this causes error messages with Linux guests.
2569 * The guest loads the x38_edac device which tries to map a memory region
2570 * using an address given at place 0x48 - 0x4f in the PCi config space.
2571 * This fails. because we don't register such a region.
2572 */
2573#if 0
2574 /* Host bridge device */
2575 PCIDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
2576 PCIDevSetDeviceId( &pBus->aPciDev, 0x29e0); /* Desktop */
2577 PCIDevSetRevisionId(&pBus->aPciDev, 0x01); /* rev. 01 */
2578 PCIDevSetClassBase( &pBus->aPciDev, 0x06); /* bridge */
2579 PCIDevSetClassSub( &pBus->aPciDev, 0x00); /* Host/PCI bridge */
2580 PCIDevSetClassProg( &pBus->aPciDev, 0x00); /* Host/PCI bridge */
2581 PCIDevSetHeaderType(&pBus->aPciDev, 0x00); /* bridge */
2582 PCIDevSetWord(&pBus->aPciDev, VBOX_PCI_SEC_STATUS, 0x0280); /* secondary status */
2583
2584 pBus->aPciDev.pDevIns = pDevIns;
2585 /* We register Host<->PCI controller on the bus */
2586 ich9pciRegisterInternal(pBus, 0, &pBus->aPciDev, "dram");
2587#endif
2588
2589 /*
2590 * Register I/O ports and save state.
2591 */
2592 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cf8, 1, NULL, ich9pciIOPortAddressWrite, ich9pciIOPortAddressRead, NULL, NULL, "ICH9 (PCI)");
2593 if (RT_FAILURE(rc))
2594 return rc;
2595 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cfc, 4, NULL, ich9pciIOPortDataWrite, ich9pciIOPortDataRead, NULL, NULL, "ICH9 (PCI)");
2596 if (RT_FAILURE(rc))
2597 return rc;
2598 if (fGCEnabled)
2599 {
2600 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cf8, 1, NIL_RTGCPTR, "ich9pciIOPortAddressWrite", "ich9pciIOPortAddressRead", NULL, NULL, "ICH9 (PCI)");
2601 if (RT_FAILURE(rc))
2602 return rc;
2603 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cfc, 4, NIL_RTGCPTR, "ich9pciIOPortDataWrite", "ich9pciIOPortDataRead", NULL, NULL, "ICH9 (PCI)");
2604 if (RT_FAILURE(rc))
2605 return rc;
2606 }
2607 if (fR0Enabled)
2608 {
2609 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cf8, 1, NIL_RTR0PTR, "ich9pciIOPortAddressWrite", "ich9pciIOPortAddressRead", NULL, NULL, "ICH9 (PCI)");
2610 if (RT_FAILURE(rc))
2611 return rc;
2612 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cfc, 4, NIL_RTR0PTR, "ich9pciIOPortDataWrite", "ich9pciIOPortDataRead", NULL, NULL, "ICH9 (PCI)");
2613 if (RT_FAILURE(rc))
2614 return rc;
2615 }
2616
2617 if (pGlobals->u64PciConfigMMioAddress != 0)
2618 {
2619 rc = PDMDevHlpMMIORegister(pDevIns, pGlobals->u64PciConfigMMioAddress, pGlobals->u64PciConfigMMioLength, NULL /*pvUser*/,
2620 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
2621 ich9pciMcfgMMIOWrite, ich9pciMcfgMMIORead, "MCFG ranges");
2622 AssertMsgRCReturn(rc, ("rc=%Rrc %#llx/%#llx\n", rc, pGlobals->u64PciConfigMMioAddress, pGlobals->u64PciConfigMMioLength), rc);
2623
2624 if (fGCEnabled)
2625 {
2626 rc = PDMDevHlpMMIORegisterRC(pDevIns, pGlobals->u64PciConfigMMioAddress, pGlobals->u64PciConfigMMioLength,
2627 NIL_RTRCPTR /*pvUser*/, "ich9pciMcfgMMIOWrite", "ich9pciMcfgMMIORead");
2628 AssertRCReturn(rc, rc);
2629 }
2630
2631
2632 if (fR0Enabled)
2633 {
2634 rc = PDMDevHlpMMIORegisterR0(pDevIns, pGlobals->u64PciConfigMMioAddress, pGlobals->u64PciConfigMMioLength,
2635 NIL_RTR0PTR /*pvUser*/, "ich9pciMcfgMMIOWrite", "ich9pciMcfgMMIORead");
2636 AssertRCReturn(rc, rc);
2637 }
2638 }
2639
2640 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
2641 sizeof(*pBus) + 16*128, "pgm",
2642 NULL, NULL, NULL,
2643 NULL, ich9pciR3SaveExec, NULL,
2644 NULL, ich9pciR3LoadExec, NULL);
2645 if (RT_FAILURE(rc))
2646 return rc;
2647
2648
2649 /** @todo: other chipset devices shall be registered too */
2650
2651 PDMDevHlpDBGFInfoRegister(pDevIns, "pci", "Display PCI bus status. Recognizes 'basic' or 'verbose' "
2652 "as arguments, defaults to 'basic'.", ich9pciInfo);
2653
2654 return VINF_SUCCESS;
2655}
2656
2657static void ich9pciResetDevice(PPCIDEVICE pDev)
2658{
2659 /* Clear regions */
2660 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
2661 {
2662 PCIIORegion* pRegion = &pDev->Int.s.aIORegions[iRegion];
2663 if (pRegion->size == 0)
2664 continue;
2665
2666 ich9pciUnmapRegion(pDev, iRegion);
2667 }
2668
2669 if (pciDevIsPassthrough(pDev))
2670 {
2671 // no reset handler - we can do what we need in PDM reset handler
2672 // @todo: is it correct?
2673 }
2674 else
2675 {
2676 PCIDevSetCommand(pDev,
2677 PCIDevGetCommand(pDev)
2678 &
2679 ~(VBOX_PCI_COMMAND_IO |
2680 VBOX_PCI_COMMAND_MEMORY |
2681 VBOX_PCI_COMMAND_MASTER));
2682
2683 /* Bridge device reset handlers processed later */
2684 if (!pciDevIsPci2PciBridge(pDev))
2685 {
2686 PCIDevSetByte(pDev, VBOX_PCI_CACHE_LINE_SIZE, 0x0);
2687 PCIDevSetInterruptLine(pDev, 0x0);
2688 }
2689 }
2690}
2691
2692
2693/**
2694 * @copydoc FNPDMDEVRESET
2695 */
2696static DECLCALLBACK(void) ich9pciReset(PPDMDEVINS pDevIns)
2697{
2698 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2699 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2700
2701 /* PCI-specific reset for each device. */
2702 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2703 {
2704 if (pBus->apDevices[i])
2705 ich9pciResetDevice(pBus->apDevices[i]);
2706 }
2707
2708 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2709 {
2710 if (pBus->papBridgesR3[iBridge])
2711 ich9pcibridgeReset(pBus->papBridgesR3[iBridge]->pDevIns);
2712 }
2713
2714 ich9pciFakePCIBIOS(pDevIns);
2715}
2716
2717static void ich9pciRelocateDevice(PPCIDEVICE pDev, RTGCINTPTR offDelta)
2718{
2719 if (pDev)
2720 {
2721 pDev->Int.s.pBusRC += offDelta;
2722 if (pDev->Int.s.pMsixPageRC)
2723 pDev->Int.s.pMsixPageRC += offDelta;
2724 }
2725}
2726
2727/**
2728 * @copydoc FNPDMDEVRELOCATE
2729 */
2730static DECLCALLBACK(void) ich9pciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2731{
2732 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2733 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2734 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2735
2736 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2737 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2738
2739 /* Relocate RC pointers for the attached pci devices. */
2740 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2741 ich9pciRelocateDevice(pBus->apDevices[i], offDelta);
2742
2743}
2744
2745/**
2746 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2747 */
2748static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
2749 int iInstance,
2750 PCFGMNODE pCfg)
2751{
2752 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2753
2754 /*
2755 * Validate and read configuration.
2756 */
2757 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
2758 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2759
2760 /* check if RC code is enabled. */
2761 bool fGCEnabled;
2762 int rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2763 if (RT_FAILURE(rc))
2764 return PDMDEV_SET_ERROR(pDevIns, rc,
2765 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2766
2767 /* check if R0 code is enabled. */
2768 bool fR0Enabled;
2769 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2770 if (RT_FAILURE(rc))
2771 return PDMDEV_SET_ERROR(pDevIns, rc,
2772 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2773 Log(("PCI: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
2774
2775 /*
2776 * Init data and register the PCI bus.
2777 */
2778 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2779 pBus->pDevInsR3 = pDevIns;
2780 pBus->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2781 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2782 pBus->papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pBus->apDevices));
2783
2784 PDMPCIBUSREG PciBusReg;
2785 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2786 PciBusReg.pfnRegisterR3 = ich9pcibridgeRegister;
2787 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
2788 PciBusReg.pfnIORegionRegisterR3 = ich9pciIORegionRegister;
2789 PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
2790 PciBusReg.pfnSetIrqR3 = ich9pcibridgeSetIrq;
2791 PciBusReg.pfnFakePCIBIOSR3 = NULL; /* Only needed for the first bus. */
2792 PciBusReg.pszSetIrqRC = fGCEnabled ? "ich9pcibridgeSetIrq" : NULL;
2793 PciBusReg.pszSetIrqR0 = fR0Enabled ? "ich9pcibridgeSetIrq" : NULL;
2794 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2795 if (RT_FAILURE(rc))
2796 return PDMDEV_SET_ERROR(pDevIns, rc,
2797 N_("Failed to register ourselves as a PCI Bus"));
2798 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2799 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2800 N_("PCI helper version mismatch; got %#x expected %#x"),
2801 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
2802
2803 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2804 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2805
2806 /* Disable default device locking. */
2807 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
2808 AssertRCReturn(rc, rc);
2809
2810 /*
2811 * Fill in PCI configs and add them to the bus.
2812 */
2813 PCIDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
2814 PCIDevSetDeviceId( &pBus->aPciDev, 0x2448); /* 82801 Mobile PCI bridge. */
2815 PCIDevSetRevisionId(&pBus->aPciDev, 0xf2);
2816 PCIDevSetClassSub( &pBus->aPciDev, 0x04); /* pci2pci */
2817 PCIDevSetClassBase( &pBus->aPciDev, 0x06); /* PCI_bridge */
2818 PCIDevSetClassProg( &pBus->aPciDev, 0x01); /* Supports subtractive decoding. */
2819 PCIDevSetHeaderType(&pBus->aPciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
2820 PCIDevSetCommand( &pBus->aPciDev, 0x00);
2821 PCIDevSetStatus( &pBus->aPciDev, 0x20); /* 66MHz Capable. */
2822 PCIDevSetInterruptLine(&pBus->aPciDev, 0x00); /* This device does not assert interrupts. */
2823
2824 /*
2825 * This device does not generate interrupts. Interrupt delivery from
2826 * devices attached to the bus is unaffected.
2827 */
2828 PCIDevSetInterruptPin (&pBus->aPciDev, 0x00);
2829
2830 pBus->aPciDev.pDevIns = pDevIns;
2831
2832 /* Bridge-specific data */
2833 pciDevSetPci2PciBridge(&pBus->aPciDev);
2834 pBus->aPciDev.Int.s.pfnBridgeConfigRead = ich9pcibridgeConfigRead;
2835 pBus->aPciDev.Int.s.pfnBridgeConfigWrite = ich9pcibridgeConfigWrite;
2836
2837 /*
2838 * Register this PCI bridge. The called function will take care on which bus we will get registered.
2839 */
2840 rc = PDMDevHlpPCIRegister (pDevIns, &pBus->aPciDev);
2841 if (RT_FAILURE(rc))
2842 return rc;
2843
2844 /*
2845 * The iBus property doesn't really represent the bus number
2846 * because the guest and the BIOS can choose different bus numbers
2847 * for them.
2848 * The bus number is mainly for the setIrq function to indicate
2849 * when the host bus is reached which will have iBus = 0.
2850 * That's why the + 1.
2851 */
2852 pBus->iBus = iInstance + 1;
2853
2854 /*
2855 * Register SSM handlers. We use the same saved state version as for the host bridge
2856 * to make changes easier.
2857 */
2858 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
2859 sizeof(*pBus) + 16*128,
2860 "pgm" /* before */,
2861 NULL, NULL, NULL,
2862 NULL, ich9pcibridgeR3SaveExec, NULL,
2863 NULL, ich9pcibridgeR3LoadExec, NULL);
2864 if (RT_FAILURE(rc))
2865 return rc;
2866
2867
2868 return VINF_SUCCESS;
2869}
2870
2871/**
2872 * @copydoc FNPDMDEVRESET
2873 */
2874static void ich9pcibridgeReset(PPDMDEVINS pDevIns)
2875{
2876 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2877
2878 /* Reset config space to default values. */
2879 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_PRIMARY_BUS, 0);
2880 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS, 0);
2881 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_SUBORDINATE_BUS, 0);
2882
2883 /* PCI-specific reset for each device. */
2884 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2885 {
2886 if (pBus->apDevices[i])
2887 ich9pciResetDevice(pBus->apDevices[i]);
2888 }
2889}
2890
2891
2892/**
2893 * @copydoc FNPDMDEVRELOCATE
2894 */
2895static DECLCALLBACK(void) ich9pcibridgeRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2896{
2897 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2898 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2899
2900 /* Relocate RC pointers for the attached pci devices. */
2901 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2902 ich9pciRelocateDevice(pBus->apDevices[i], offDelta);
2903}
2904
2905/**
2906 * The PCI bus device registration structure.
2907 */
2908const PDMDEVREG g_DevicePciIch9 =
2909{
2910 /* u32Version */
2911 PDM_DEVREG_VERSION,
2912 /* szName */
2913 "ich9pci",
2914 /* szRCMod */
2915 "VBoxDDGC.gc",
2916 /* szR0Mod */
2917 "VBoxDDR0.r0",
2918 /* pszDescription */
2919 "ICH9 PCI bridge",
2920 /* fFlags */
2921 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2922 /* fClass */
2923 PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
2924 /* cMaxInstances */
2925 1,
2926 /* cbInstance */
2927 sizeof(ICH9PCIGLOBALS),
2928 /* pfnConstruct */
2929 ich9pciConstruct,
2930 /* pfnDestruct */
2931 NULL,
2932 /* pfnRelocate */
2933 ich9pciRelocate,
2934 /* pfnMemSetup */
2935 NULL,
2936 /* pfnPowerOn */
2937 NULL,
2938 /* pfnReset */
2939 ich9pciReset,
2940 /* pfnSuspend */
2941 NULL,
2942 /* pfnResume */
2943 NULL,
2944 /* pfnAttach */
2945 NULL,
2946 /* pfnDetach */
2947 NULL,
2948 /* pfnQueryInterface */
2949 NULL,
2950 /* pfnInitComplete */
2951 NULL,
2952 /* pfnPowerOff */
2953 NULL,
2954 /* pfnSoftReset */
2955 NULL,
2956 /* u32VersionEnd */
2957 PDM_DEVREG_VERSION
2958};
2959
2960/**
2961 * The device registration structure
2962 * for the PCI-to-PCI bridge.
2963 */
2964const PDMDEVREG g_DevicePciIch9Bridge =
2965{
2966 /* u32Version */
2967 PDM_DEVREG_VERSION,
2968 /* szName */
2969 "ich9pcibridge",
2970 /* szRCMod */
2971 "VBoxDDGC.gc",
2972 /* szR0Mod */
2973 "VBoxDDR0.r0",
2974 /* pszDescription */
2975 "ICH9 PCI to PCI bridge",
2976 /* fFlags */
2977 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2978 /* fClass */
2979 PDM_DEVREG_CLASS_BUS_PCI,
2980 /* cMaxInstances */
2981 ~0U,
2982 /* cbInstance */
2983 sizeof(ICH9PCIBUS),
2984 /* pfnConstruct */
2985 ich9pcibridgeConstruct,
2986 /* pfnDestruct */
2987 NULL,
2988 /* pfnRelocate */
2989 ich9pcibridgeRelocate,
2990 /* pfnMemSetup */
2991 NULL,
2992 /* pfnPowerOn */
2993 NULL,
2994 /* pfnReset */
2995 NULL, /* Must be NULL, to make sure only bus driver handles reset */
2996 /* pfnSuspend */
2997 NULL,
2998 /* pfnResume */
2999 NULL,
3000 /* pfnAttach */
3001 NULL,
3002 /* pfnDetach */
3003 NULL,
3004 /* pfnQueryInterface */
3005 NULL,
3006 /* pfnInitComplete */
3007 NULL,
3008 /* pfnPowerOff */
3009 NULL,
3010 /* pfnSoftReset */
3011 NULL,
3012 /* u32VersionEnd */
3013 PDM_DEVREG_VERSION
3014};
3015
3016#endif /* IN_RING3 */
3017#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
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