VirtualBox

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

Last change on this file since 34286 was 34268, checked in by vboxsync, 15 years ago

PCI: some 64-bit BARs bits

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette