VirtualBox

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

Last change on this file since 34231 was 34231, checked in by vboxsync, 14 years ago

PCI: allow arbitrary width BAR accesses

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 96.5 KB
Line 
1/* $Id: DevPciIch9.cpp 34231 2010-11-22 10:23:59Z 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 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
724 {
725 /* port IO region */
726 if (iCmd & PCI_COMMAND_IOACCESS)
727 {
728 /* IO access allowed */
729 uNew = ich9pciConfigReadDev(pDev, uConfigReg, 4);
730 uNew &= ~(iRegionSize - 1);
731 uLast = uNew + iRegionSize - 1;
732 /* only 64K ioports on PC */
733 if (uLast <= uNew || uNew == 0 || uLast >= 0x10000)
734 uNew = INVALID_PCI_ADDRESS;
735 } else
736 uNew = INVALID_PCI_ADDRESS;
737 }
738 else
739 {
740 /* MMIO region */
741 if (iCmd & PCI_COMMAND_MEMACCESS)
742 {
743 uNew = ich9pciConfigReadDev(pDev, uConfigReg, 4);
744 /* the ROM slot has a specific enable bit */
745 if (iRegion == PCI_ROM_SLOT && !(uNew & 1))
746 uNew = INVALID_PCI_ADDRESS;
747 else
748 {
749 uNew &= ~(iRegionSize - 1);
750 uLast = uNew + iRegionSize - 1;
751 /* NOTE: we do not support wrapping */
752 /* XXX: as we cannot support really dynamic
753 mappings, we handle specific values as invalid
754 mappings. */
755 if (uLast <= uNew || uNew == 0 || uLast == INVALID_PCI_ADDRESS)
756 uNew = INVALID_PCI_ADDRESS;
757 }
758 } else
759 uNew = INVALID_PCI_ADDRESS;
760 }
761 /* now do the real mapping */
762 if (uNew != pRegion->addr)
763 {
764 if (pRegion->addr != INVALID_PCI_ADDRESS)
765 {
766 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
767 {
768 /* Port IO */
769 rc = PDMDevHlpIOPortDeregister(pDev->pDevIns, pRegion->addr, pRegion->size);
770 AssertRC(rc);
771 }
772 else
773 {
774 RTGCPHYS GCPhysBase = pRegion->addr;
775 if (pBus->pPciHlpR3->pfnIsMMIO2Base(pBus->pDevInsR3, pDev->pDevIns, GCPhysBase))
776 {
777 /* unmap it. */
778 rc = pRegion->map_func(pDev, iRegion, NIL_RTGCPHYS, pRegion->size, (PCIADDRESSSPACE)(pRegion->type));
779 AssertRC(rc);
780 rc = PDMDevHlpMMIO2Unmap(pDev->pDevIns, iRegion, GCPhysBase);
781 }
782 else
783 rc = PDMDevHlpMMIODeregister(pDev->pDevIns, GCPhysBase, pRegion->size);
784 AssertMsgRC(rc, ("rc=%Rrc d=%s i=%d GCPhysBase=%RGp size=%#x\n", rc, pDev->name, iRegion, GCPhysBase, pRegion->size));
785 }
786 }
787 pRegion->addr = uNew;
788 if (pRegion->addr != INVALID_PCI_ADDRESS)
789 {
790 /* finally, map the region */
791 rc = pRegion->map_func(pDev, iRegion,
792 pRegion->addr, pRegion->size,
793 (PCIADDRESSSPACE)(pRegion->type));
794 AssertRC(rc);
795 }
796 }
797 }
798}
799
800static DECLCALLBACK(int) ich9pciRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
801{
802 PPCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
803
804 /*
805 * Check input.
806 */
807 if ( !pszName
808 || !pPciDev
809 || iDev >= (int)RT_ELEMENTS(pBus->apDevices)
810 )
811 {
812 AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
813 return VERR_INVALID_PARAMETER;
814 }
815
816 /*
817 * Register the device.
818 */
819 return ich9pciRegisterInternal(pBus, iDev, pPciDev, pszName);
820}
821
822
823static DECLCALLBACK(int) ich9pciRegisterMsi(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PPDMMSIREG pMsiReg)
824{
825 int rc;
826
827 rc = MsiInit(pPciDev, pMsiReg);
828 if (rc != VINF_SUCCESS)
829 return rc;
830
831 rc = MsixInit(pPciDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp), pPciDev, pMsiReg);
832 if (rc != VINF_SUCCESS)
833 return rc;
834
835 return rc;
836}
837
838
839static DECLCALLBACK(int) ich9pcibridgeRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
840{
841
842 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
843
844 /*
845 * Check input.
846 */
847 if ( !pszName
848 || !pPciDev
849 || iDev >= (int)RT_ELEMENTS(pBus->apDevices))
850 {
851 AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
852 return VERR_INVALID_PARAMETER;
853 }
854
855 /*
856 * Register the device.
857 */
858 return ich9pciRegisterInternal(pBus, iDev, pPciDev, pszName);
859}
860
861static DECLCALLBACK(int) ich9pciIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, uint32_t cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
862{
863 /*
864 * Validate.
865 */
866 AssertMsgReturn( enmType == PCI_ADDRESS_SPACE_MEM
867 || enmType == PCI_ADDRESS_SPACE_IO
868 || enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH,
869 ("Invalid enmType=%#x? Or was this a bitmask after all...\n", enmType),
870 VERR_INVALID_PARAMETER);
871 AssertMsgReturn((unsigned)iRegion < PCI_NUM_REGIONS,
872 ("Invalid iRegion=%d PCI_NUM_REGIONS=%d\n", iRegion, PCI_NUM_REGIONS),
873 VERR_INVALID_PARAMETER);
874 int iLastSet = ASMBitLastSetU32(cbRegion);
875 AssertMsgReturn( iLastSet != 0
876 && RT_BIT_32(iLastSet - 1) == cbRegion,
877 ("Invalid cbRegion=%#x iLastSet=%#x (not a power of 2 or 0)\n", cbRegion, iLastSet),
878 VERR_INVALID_PARAMETER);
879
880 /*
881 * Register the I/O region.
882 */
883 PPCIIOREGION pRegion = &pPciDev->Int.s.aIORegions[iRegion];
884 pRegion->addr = INVALID_PCI_ADDRESS;
885 pRegion->size = cbRegion;
886 pRegion->type = enmType;
887 pRegion->map_func = pfnCallback;
888
889 /* Set type in the config space. */
890 uint32_t u32Address = ich9pciGetRegionReg(iRegion);
891 uint32_t u32Value = (enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH ? (1 << 3) : 0)
892 | (enmType == PCI_ADDRESS_SPACE_IO ? 1 : 0);
893 PCIDevSetDWord(pPciDev, u32Address, u32Value);
894
895 return VINF_SUCCESS;
896}
897
898static DECLCALLBACK(void) ich9pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
899 PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
900{
901 if (ppfnReadOld)
902 *ppfnReadOld = pPciDev->Int.s.pfnConfigRead;
903 pPciDev->Int.s.pfnConfigRead = pfnRead;
904
905 if (ppfnWriteOld)
906 *ppfnWriteOld = pPciDev->Int.s.pfnConfigWrite;
907 pPciDev->Int.s.pfnConfigWrite = pfnWrite;
908}
909
910/**
911 * Saves a state of the PCI device.
912 *
913 * @returns VBox status code.
914 * @param pDevIns Device instance of the PCI Bus.
915 * @param pPciDev Pointer to PCI device.
916 * @param pSSM The handle to save the state to.
917 */
918static DECLCALLBACK(int) ich9pciGenericSaveExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSM)
919{
920 return SSMR3PutMem(pSSM, &pPciDev->config[0], sizeof(pPciDev->config));
921}
922
923static int ich9pciR3CommonSaveExec(PPCIBUS pBus, PSSMHANDLE pSSM)
924{
925 /*
926 * Iterate thru all the devices.
927 */
928 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
929 {
930 PPCIDEVICE pDev = pBus->apDevices[i];
931 if (pDev)
932 {
933 /* Device position */
934 SSMR3PutU32(pSSM, i);
935 /* PCI config registers */
936 SSMR3PutMem(pSSM, pDev->config, sizeof(pDev->config));
937
938 /* Device flags */
939 int rc = SSMR3PutU32(pSSM, pDev->Int.s.uFlags);
940 if (RT_FAILURE(rc))
941 return rc;
942
943 /* IRQ pin state */
944 rc = SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
945 if (RT_FAILURE(rc))
946 return rc;
947
948 /* MSI info */
949 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapOffset);
950 if (RT_FAILURE(rc))
951 return rc;
952 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapSize);
953 if (RT_FAILURE(rc))
954 return rc;
955
956 /* MSI-X info */
957 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapOffset);
958 if (RT_FAILURE(rc))
959 return rc;
960 rc = SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapSize);
961 if (RT_FAILURE(rc))
962 return rc;
963 /* Save MSI-X page state */
964 if (pDev->Int.s.u8MsixCapOffset != 0)
965 {
966 Assert(pDev->Int.s.pMsixPageR3 != NULL);
967 SSMR3PutMem(pSSM, pDev->Int.s.pMsixPageR3, 0x1000);
968 if (RT_FAILURE(rc))
969 return rc;
970 }
971 }
972 }
973 return SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
974}
975
976static DECLCALLBACK(int) ich9pciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
977{
978 PPCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
979
980 /*
981 * Bus state data.
982 */
983 SSMR3PutU32(pSSM, pThis->uConfigReg);
984
985 /*
986 * Save IRQ states.
987 */
988 for (int i = 0; i < PCI_APIC_IRQ_PINS; i++)
989 SSMR3PutU32(pSSM, pThis->uaPciApicIrqLevels[i]);
990
991 SSMR3PutU32(pSSM, ~0); /* separator */
992
993 return ich9pciR3CommonSaveExec(&pThis->aPciBus, pSSM);
994}
995
996
997static DECLCALLBACK(int) ich9pcibridgeR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
998{
999 PPCIBUS pThis = PDMINS_2_DATA(pDevIns, PPCIBUS);
1000 return ich9pciR3CommonSaveExec(pThis, pSSM);
1001}
1002
1003
1004static void ich9pcibridgeConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, uint32_t u32Value, unsigned cb)
1005{
1006 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
1007
1008 LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u u32Value=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, u32Value, cb));
1009
1010 /* If the current bus is not the target bus search for the bus which contains the device. */
1011 if (iBus != PCIDevGetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS))
1012 {
1013 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1014 if (pBridgeDevice)
1015 {
1016 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
1017 pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, u32Value, cb);
1018 }
1019 }
1020 else
1021 {
1022 /* This is the target bus, pass the write to the device. */
1023 PPCIDEVICE pPciDev = pBus->apDevices[iDevice];
1024 if (pPciDev)
1025 {
1026 Log(("%s: %s: addr=%02x val=%08x len=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
1027 pPciDev->Int.s.pfnConfigWrite(pPciDev, u32Address, u32Value, cb);
1028 }
1029 }
1030}
1031
1032static uint32_t ich9pcibridgeConfigRead(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, unsigned cb)
1033{
1034 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
1035 uint32_t u32Value;
1036
1037 LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, cb));
1038
1039 /* If the current bus is not the target bus search for the bus which contains the device. */
1040 if (iBus != PCIDevGetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS))
1041 {
1042 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1043 if (pBridgeDevice)
1044 {
1045 AssertPtr( pBridgeDevice->Int.s.pfnBridgeConfigRead);
1046 u32Value = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, cb);
1047 }
1048 else
1049 ich9pciNoMem(&u32Value, 4);
1050 }
1051 else
1052 {
1053 /* This is the target bus, pass the read to the device. */
1054 PPCIDEVICE pPciDev = pBus->apDevices[iDevice];
1055 if (pPciDev)
1056 {
1057 u32Value = pPciDev->Int.s.pfnConfigRead(pPciDev, u32Address, cb);
1058 Log(("%s: %s: u32Address=%02x u32Value=%08x cb=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
1059 }
1060 else
1061 ich9pciNoMem(&u32Value, 4);
1062 }
1063
1064 return u32Value;
1065}
1066
1067
1068/**
1069 * Common routine for restoring the config registers of a PCI device.
1070 *
1071 * @param pDev The PCI device.
1072 * @param pbSrcConfig The configuration register values to be loaded.
1073 * @param fIsBridge Whether this is a bridge device or not.
1074 */
1075static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig, bool fIsBridge)
1076{
1077 /*
1078 * This table defines the fields for normal devices and bridge devices, and
1079 * the order in which they need to be restored.
1080 */
1081 static const struct PciField
1082 {
1083 uint8_t off;
1084 uint8_t cb;
1085 uint8_t fWritable;
1086 uint8_t fBridge;
1087 const char *pszName;
1088 } s_aFields[] =
1089 {
1090 /* off,cb,fW,fB, pszName */
1091 { VBOX_PCI_VENDOR_ID, 2, 0, 3, "VENDOR_ID" },
1092 { VBOX_PCI_DEVICE_ID, 2, 0, 3, "DEVICE_ID" },
1093 { VBOX_PCI_STATUS, 2, 1, 3, "STATUS" },
1094 { VBOX_PCI_REVISION_ID, 1, 0, 3, "REVISION_ID" },
1095 { VBOX_PCI_CLASS_PROG, 1, 0, 3, "CLASS_PROG" },
1096 { VBOX_PCI_CLASS_SUB, 1, 0, 3, "CLASS_SUB" },
1097 { VBOX_PCI_CLASS_BASE, 1, 0, 3, "CLASS_BASE" },
1098 { VBOX_PCI_CACHE_LINE_SIZE, 1, 1, 3, "CACHE_LINE_SIZE" },
1099 { VBOX_PCI_LATENCY_TIMER, 1, 1, 3, "LATENCY_TIMER" },
1100 { VBOX_PCI_HEADER_TYPE, 1, 0, 3, "HEADER_TYPE" },
1101 { VBOX_PCI_BIST, 1, 1, 3, "BIST" },
1102 { VBOX_PCI_BASE_ADDRESS_0, 4, 1, 3, "BASE_ADDRESS_0" },
1103 { VBOX_PCI_BASE_ADDRESS_1, 4, 1, 3, "BASE_ADDRESS_1" },
1104 { VBOX_PCI_BASE_ADDRESS_2, 4, 1, 1, "BASE_ADDRESS_2" },
1105 { VBOX_PCI_PRIMARY_BUS, 1, 1, 2, "PRIMARY_BUS" }, // fWritable = ??
1106 { VBOX_PCI_SECONDARY_BUS, 1, 1, 2, "SECONDARY_BUS" }, // fWritable = ??
1107 { VBOX_PCI_SUBORDINATE_BUS, 1, 1, 2, "SUBORDINATE_BUS" }, // fWritable = ??
1108 { VBOX_PCI_SEC_LATENCY_TIMER, 1, 1, 2, "SEC_LATENCY_TIMER" }, // fWritable = ??
1109 { VBOX_PCI_BASE_ADDRESS_3, 4, 1, 1, "BASE_ADDRESS_3" },
1110 { VBOX_PCI_IO_BASE, 1, 1, 2, "IO_BASE" }, // fWritable = ??
1111 { VBOX_PCI_IO_LIMIT, 1, 1, 2, "IO_LIMIT" }, // fWritable = ??
1112 { VBOX_PCI_SEC_STATUS, 2, 1, 2, "SEC_STATUS" }, // fWritable = ??
1113 { VBOX_PCI_BASE_ADDRESS_4, 4, 1, 1, "BASE_ADDRESS_4" },
1114 { VBOX_PCI_MEMORY_BASE, 2, 1, 2, "MEMORY_BASE" }, // fWritable = ??
1115 { VBOX_PCI_MEMORY_LIMIT, 2, 1, 2, "MEMORY_LIMIT" }, // fWritable = ??
1116 { VBOX_PCI_BASE_ADDRESS_5, 4, 1, 1, "BASE_ADDRESS_5" },
1117 { VBOX_PCI_PREF_MEMORY_BASE, 2, 1, 2, "PREF_MEMORY_BASE" }, // fWritable = ??
1118 { VBOX_PCI_PREF_MEMORY_LIMIT, 2, 1, 2, "PREF_MEMORY_LIMIT" }, // fWritable = ??
1119 { VBOX_PCI_CARDBUS_CIS, 4, 1, 1, "CARDBUS_CIS" }, // fWritable = ??
1120 { VBOX_PCI_PREF_BASE_UPPER32, 4, 1, 2, "PREF_BASE_UPPER32" }, // fWritable = ??
1121 { VBOX_PCI_SUBSYSTEM_VENDOR_ID, 2, 0, 1, "SUBSYSTEM_VENDOR_ID" },// fWritable = !?
1122 { VBOX_PCI_PREF_LIMIT_UPPER32, 4, 1, 2, "PREF_LIMIT_UPPER32" },// fWritable = ??
1123 { VBOX_PCI_SUBSYSTEM_ID, 2, 0, 1, "SUBSYSTEM_ID" }, // fWritable = !?
1124 { VBOX_PCI_ROM_ADDRESS, 4, 1, 1, "ROM_ADDRESS" }, // fWritable = ?!
1125 { VBOX_PCI_IO_BASE_UPPER16, 2, 1, 2, "IO_BASE_UPPER16" }, // fWritable = ?!
1126 { VBOX_PCI_IO_LIMIT_UPPER16, 2, 1, 2, "IO_LIMIT_UPPER16" }, // fWritable = ?!
1127 { VBOX_PCI_CAPABILITY_LIST, 4, 0, 3, "CAPABILITY_LIST" }, // fWritable = !? cb=!?
1128 { VBOX_PCI_RESERVED_38, 4, 1, 1, "RESERVED_38" }, // ???
1129 { VBOX_PCI_ROM_ADDRESS_BR, 4, 1, 2, "ROM_ADDRESS_BR" }, // fWritable = !? cb=!? fBridge=!?
1130 { VBOX_PCI_INTERRUPT_LINE, 1, 1, 3, "INTERRUPT_LINE" }, // fBridge=??
1131 { VBOX_PCI_INTERRUPT_PIN, 1, 0, 3, "INTERRUPT_PIN" }, // fBridge=??
1132 { VBOX_PCI_MIN_GNT, 1, 0, 1, "MIN_GNT" },
1133 { VBOX_PCI_BRIDGE_CONTROL, 2, 1, 2, "BRIDGE_CONTROL" }, // fWritable = !?
1134 { VBOX_PCI_MAX_LAT, 1, 0, 1, "MAX_LAT" },
1135 /* The COMMAND register must come last as it requires the *ADDRESS*
1136 registers to be restored before we pretent to change it from 0 to
1137 whatever value the guest assigned it. */
1138 { VBOX_PCI_COMMAND, 2, 1, 3, "COMMAND" },
1139 };
1140
1141#ifdef RT_STRICT
1142 /* Check that we've got full register coverage. */
1143 uint32_t bmDevice[0x40 / 32];
1144 uint32_t bmBridge[0x40 / 32];
1145 RT_ZERO(bmDevice);
1146 RT_ZERO(bmBridge);
1147 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1148 {
1149 uint8_t off = s_aFields[i].off;
1150 uint8_t cb = s_aFields[i].cb;
1151 uint8_t f = s_aFields[i].fBridge;
1152 while (cb-- > 0)
1153 {
1154 if (f & 1) AssertMsg(!ASMBitTest(bmDevice, off), ("%#x\n", off));
1155 if (f & 2) AssertMsg(!ASMBitTest(bmBridge, off), ("%#x\n", off));
1156 if (f & 1) ASMBitSet(bmDevice, off);
1157 if (f & 2) ASMBitSet(bmBridge, off);
1158 off++;
1159 }
1160 }
1161 for (uint32_t off = 0; off < 0x40; off++)
1162 {
1163 AssertMsg(ASMBitTest(bmDevice, off), ("%#x\n", off));
1164 AssertMsg(ASMBitTest(bmBridge, off), ("%#x\n", off));
1165 }
1166#endif
1167
1168 /*
1169 * Loop thru the fields covering the 64 bytes of standard registers.
1170 */
1171 uint8_t const fBridge = fIsBridge ? 2 : 1;
1172 uint8_t *pbDstConfig = &pDev->config[0];
1173 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1174 if (s_aFields[i].fBridge & fBridge)
1175 {
1176 uint8_t const off = s_aFields[i].off;
1177 uint8_t const cb = s_aFields[i].cb;
1178 uint32_t u32Src;
1179 uint32_t u32Dst;
1180 switch (cb)
1181 {
1182 case 1:
1183 u32Src = pbSrcConfig[off];
1184 u32Dst = pbDstConfig[off];
1185 break;
1186 case 2:
1187 u32Src = *(uint16_t const *)&pbSrcConfig[off];
1188 u32Dst = *(uint16_t const *)&pbDstConfig[off];
1189 break;
1190 case 4:
1191 u32Src = *(uint32_t const *)&pbSrcConfig[off];
1192 u32Dst = *(uint32_t const *)&pbDstConfig[off];
1193 break;
1194 default:
1195 AssertFailed();
1196 continue;
1197 }
1198
1199 if ( u32Src != u32Dst
1200 || off == VBOX_PCI_COMMAND)
1201 {
1202 if (u32Src != u32Dst)
1203 {
1204 if (!s_aFields[i].fWritable)
1205 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x - !READ ONLY!\n",
1206 pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1207 else
1208 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x\n",
1209 pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1210 }
1211 if (off == VBOX_PCI_COMMAND)
1212 PCIDevSetCommand(pDev, 0); /* For remapping, see ich9pciR3CommonLoadExec. */
1213 pDev->Int.s.pfnConfigWrite(pDev, off, u32Src, cb);
1214 }
1215 }
1216
1217 /*
1218 * The device dependent registers.
1219 *
1220 * We will not use ConfigWrite here as we have no clue about the size
1221 * of the registers, so the device is responsible for correctly
1222 * restoring functionality governed by these registers.
1223 */
1224 for (uint32_t off = 0x40; off < sizeof(pDev->config); off++)
1225 if (pbDstConfig[off] != pbSrcConfig[off])
1226 {
1227 LogRel(("PCI: %8s/%u: register %02x: %02x -> %02x\n",
1228 pDev->name, pDev->pDevIns->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
1229 pbDstConfig[off] = pbSrcConfig[off];
1230 }
1231}
1232
1233/**
1234 * Common worker for ich9pciR3LoadExec and ich9pcibridgeR3LoadExec.
1235 *
1236 * @returns VBox status code.
1237 * @param pBus The bus which data is being loaded.
1238 * @param pSSM The saved state handle.
1239 * @param uVersion The data version.
1240 * @param uPass The pass.
1241 */
1242static DECLCALLBACK(int) ich9pciR3CommonLoadExec(PPCIBUS pBus, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1243{
1244 uint32_t u32;
1245 uint32_t i;
1246 int rc;
1247
1248 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1249
1250 /*
1251 * Iterate thru all the devices and write 0 to the COMMAND register so
1252 * that all the memory is unmapped before we start restoring the saved
1253 * mapping locations.
1254 *
1255 * The register value is restored afterwards so we can do proper
1256 * LogRels in pciR3CommonRestoreConfig.
1257 */
1258 for (i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
1259 {
1260 PPCIDEVICE pDev = pBus->apDevices[i];
1261 if (pDev)
1262 {
1263 uint16_t u16 = PCIDevGetCommand(pDev);
1264 pDev->Int.s.pfnConfigWrite(pDev, VBOX_PCI_COMMAND, 0, 2);
1265 PCIDevSetCommand(pDev, u16);
1266 Assert(PCIDevGetCommand(pDev) == u16);
1267 }
1268 }
1269
1270 void* pvMsixPage = RTMemTmpAllocZ(0x1000);
1271 /*
1272 * Iterate all the devices.
1273 */
1274 for (i = 0;; i++)
1275 {
1276 PPCIDEVICE pDev;
1277 PCIDEVICE DevTmp;
1278
1279 /* index / terminator */
1280 rc = SSMR3GetU32(pSSM, &u32);
1281 if (RT_FAILURE(rc))
1282 return rc;
1283 if (u32 == (uint32_t)~0)
1284 break;
1285 if ( u32 >= RT_ELEMENTS(pBus->apDevices)
1286 || u32 < i)
1287 {
1288 AssertMsgFailed(("u32=%#x i=%#x\n", u32, i));
1289 goto out;
1290 }
1291
1292 /* skip forward to the device checking that no new devices are present. */
1293 for (; i < u32; i++)
1294 {
1295 pDev = pBus->apDevices[i];
1296 if (pDev)
1297 {
1298 LogRel(("New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pDev->name,
1299 PCIDevGetVendorId(pDev), PCIDevGetDeviceId(pDev)));
1300 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1301 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("New device in slot %#x, %s (vendor=%#06x device=%#06x)"),
1302 i, pDev->name, PCIDevGetVendorId(pDev), PCIDevGetDeviceId(pDev));
1303 }
1304 }
1305
1306 /* get the data */
1307 DevTmp.Int.s.uFlags = 0;
1308 DevTmp.Int.s.u8MsiCapOffset = 0;
1309 DevTmp.Int.s.u8MsiCapSize = 0;
1310 DevTmp.Int.s.u8MsixCapOffset = 0;
1311 DevTmp.Int.s.u8MsixCapSize = 0;
1312 DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
1313 SSMR3GetMem(pSSM, DevTmp.config, sizeof(DevTmp.config));
1314
1315 rc = SSMR3GetU32(pSSM, &DevTmp.Int.s.uFlags);
1316 if (RT_FAILURE(rc))
1317 goto out;
1318
1319 rc = SSMR3GetS32(pSSM, &DevTmp.Int.s.uIrqPinState);
1320 if (RT_FAILURE(rc))
1321 goto out;
1322
1323 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsiCapOffset);
1324 if (RT_FAILURE(rc))
1325 goto out;
1326
1327 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsiCapSize);
1328 if (RT_FAILURE(rc))
1329 goto out;
1330
1331 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsixCapOffset);
1332 if (RT_FAILURE(rc))
1333 goto out;
1334
1335 rc = SSMR3GetU8(pSSM, &DevTmp.Int.s.u8MsixCapSize);
1336 if (RT_FAILURE(rc))
1337 goto out;
1338
1339 /* Load MSI-X page state */
1340 if (DevTmp.Int.s.u8MsixCapOffset != 0)
1341 {
1342 Assert(pvMsixPage != NULL);
1343 SSMR3GetMem(pSSM, pvMsixPage, 0x1000);
1344 if (RT_FAILURE(rc))
1345 goto out;
1346 }
1347
1348 /* check that it's still around. */
1349 pDev = pBus->apDevices[i];
1350 if (!pDev)
1351 {
1352 LogRel(("Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", i,
1353 PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp)));
1354 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1355 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x has been removed! vendor=%#06x device=%#06x"),
1356 i, PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp));
1357 continue;
1358 }
1359
1360 /* match the vendor id assuming that this will never be changed. */
1361 if ( PCIDevGetVendorId(&DevTmp) != PCIDevGetVendorId(pDev))
1362 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
1363 i, pDev->name, PCIDevGetVendorId(&DevTmp), PCIDevGetVendorId(pDev));
1364
1365 /* commit the loaded device config. */
1366 pciR3CommonRestoreConfig(pDev, &DevTmp.config[0], false ); /** @todo fix bridge fun! */
1367
1368 pDev->Int.s.uIrqPinState = DevTmp.Int.s.uIrqPinState;
1369 pDev->Int.s.u8MsiCapOffset = DevTmp.Int.s.u8MsiCapOffset;
1370 pDev->Int.s.u8MsiCapSize = DevTmp.Int.s.u8MsiCapSize;
1371 pDev->Int.s.u8MsixCapOffset = DevTmp.Int.s.u8MsixCapOffset;
1372 pDev->Int.s.u8MsixCapSize = DevTmp.Int.s.u8MsixCapSize;
1373 if (DevTmp.Int.s.u8MsixCapSize != 0)
1374 {
1375 Assert(pDev->Int.s.pMsixPageR3 != NULL);
1376 memcpy(pDev->Int.s.pMsixPageR3, pvMsixPage, 0x1000);
1377 }
1378 }
1379
1380 out:
1381 if (pvMsixPage)
1382 RTMemTmpFree(pvMsixPage);
1383
1384 return rc;
1385}
1386
1387/**
1388 * Loads a saved PCI device state.
1389 *
1390 * @returns VBox status code.
1391 * @param pDevIns Device instance of the PCI Bus.
1392 * @param pPciDev Pointer to PCI device.
1393 * @param pSSM The handle to the saved state.
1394 */
1395static DECLCALLBACK(int) ich9pciGenericLoadExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSM)
1396{
1397 return SSMR3GetMem(pSSM, &pPciDev->config[0], sizeof(pPciDev->config));
1398}
1399
1400static DECLCALLBACK(int) ich9pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1401{
1402 PPCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
1403 PPCIBUS pBus = &pThis->aPciBus;
1404 uint32_t u32;
1405 int rc;
1406
1407 /* We ignore this version as there's no saved state with it anyway */
1408 if (uVersion == VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI)
1409 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1410 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI)
1411 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1412
1413 /*
1414 * Bus state data.
1415 */
1416 SSMR3GetU32(pSSM, &pThis->uConfigReg);
1417
1418 /*
1419 * Load IRQ states.
1420 */
1421 for (int i = 0; i < PCI_APIC_IRQ_PINS; i++)
1422 SSMR3GetU32(pSSM, (uint32_t*)&pThis->uaPciApicIrqLevels[i]);
1423
1424 /* separator */
1425 rc = SSMR3GetU32(pSSM, &u32);
1426 if (RT_FAILURE(rc))
1427 return rc;
1428 if (u32 != (uint32_t)~0)
1429 AssertMsgFailedReturn(("u32=%#x\n", u32), rc);
1430
1431 return ich9pciR3CommonLoadExec(pBus, pSSM, uVersion, uPass);
1432}
1433
1434static DECLCALLBACK(int) ich9pcibridgeR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1435{
1436 PPCIBUS pThis = PDMINS_2_DATA(pDevIns, PPCIBUS);
1437 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI)
1438 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1439 return ich9pciR3CommonLoadExec(pThis, pSSM, uVersion, uPass);
1440}
1441
1442static uint32_t ich9pciConfigRead(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t len)
1443{
1444 /* Will only work in LSB case */
1445 uint32_t u32Val;
1446 PciAddress aPciAddr;
1447
1448 aPciAddr.iBus = uBus;
1449 aPciAddr.iDeviceFunc = uDevFn;
1450 aPciAddr.iRegister = addr;
1451
1452 /* cannot be rescheduled, as already in R3 */
1453 int rc = ich9pciDataReadAddr(pGlobals, &aPciAddr, len, &u32Val, VERR_INTERNAL_ERROR);
1454 AssertRC(rc);
1455 return u32Val;
1456}
1457
1458static void ich9pciConfigWrite(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t val, uint32_t len)
1459{
1460 PciAddress aPciAddr;
1461
1462 aPciAddr.iBus = uBus;
1463 aPciAddr.iDeviceFunc = uDevFn;
1464 aPciAddr.iRegister = addr;
1465
1466 /* cannot be rescheduled, as already in R3 */
1467 int rc = ich9pciDataWriteAddr(pGlobals, &aPciAddr, val, len, VERR_INTERNAL_ERROR);
1468 AssertRC(rc);
1469}
1470
1471static void ich9pciSetRegionAddress(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, int iRegion, uint32_t addr)
1472{
1473 uint32_t uReg = ich9pciGetRegionReg(iRegion);
1474
1475 /* Read memory type first. */
1476 uint8_t uResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, uReg, 1);
1477 /* Read command register. */
1478 uint16_t uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 2);
1479
1480 if ( iRegion == PCI_ROM_SLOT )
1481 uCmd |= PCI_COMMAND_MEMACCESS;
1482 else if ((uResourceType & PCI_ADDRESS_SPACE_IO) == PCI_ADDRESS_SPACE_IO)
1483 uCmd |= PCI_COMMAND_IOACCESS; /* Enable I/O space access. */
1484 else /* The region is MMIO. */
1485 uCmd |= PCI_COMMAND_MEMACCESS; /* Enable MMIO access. */
1486
1487 /* Write address of the device. */
1488 ich9pciConfigWrite(pGlobals, uBus, uDevFn, uReg, addr, 4);
1489
1490 /* enable memory mappings */
1491 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, uCmd, 2);
1492}
1493
1494
1495static void ich9pciBiosInitBridge(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint8_t cBridgeDepth, uint8_t *paBridgePositions)
1496{
1497 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_SECONDARY_BUS, pGlobals->uBus, 1);
1498 /* Temporary until we know how many other bridges are behind this one. */
1499 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_SUBORDINATE_BUS, 0xff, 1);
1500
1501 /* Add position of this bridge into the array. */
1502 paBridgePositions[cBridgeDepth+1] = (uDevFn >> 3);
1503
1504 /*
1505 * The I/O range for the bridge must be aligned to a 4KB boundary.
1506 * This does not change anything really as the access to the device is not going
1507 * through the bridge but we want to be compliant to the spec.
1508 */
1509 if ((pGlobals->uPciBiosIo % 4096) != 0)
1510 {
1511 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
1512 Log(("%s: Aligned I/O start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosIo));
1513 }
1514 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_BASE, (pGlobals->uPciBiosIo >> 8) & 0xf0, 1);
1515
1516 /* The MMIO range for the bridge must be aligned to a 1MB boundary. */
1517 if ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0)
1518 {
1519 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
1520 Log(("%s: Aligned MMIO start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosMmio));
1521 }
1522 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_BASE, (pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xffff0), 2);
1523
1524 /* Save values to compare later to. */
1525 uint32_t u32IoAddressBase = pGlobals->uPciBiosIo;
1526 uint32_t u32MMIOAddressBase = pGlobals->uPciBiosMmio;
1527
1528 /* Init devices behind the bridge and possibly other bridges as well. */
1529 for (int iDev = 0; iDev <= 255; iDev++)
1530 ich9pciBiosInitDevice(pGlobals, uBus + 1, iDev, cBridgeDepth + 1, paBridgePositions);
1531
1532 /* The number of bridges behind the this one is now available. */
1533 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_SUBORDINATE_BUS, pGlobals->uBus, 1);
1534
1535 /*
1536 * Set I/O limit register. If there is no device with I/O space behind the bridge
1537 * we set a lower value than in the base register.
1538 * The result with a real bridge is that no I/O transactions are passed to the secondary
1539 * interface. Again this doesn't really matter here but we want to be compliant to the spec.
1540 */
1541 if ((u32IoAddressBase != pGlobals->uPciBiosIo) && ((pGlobals->uPciBiosIo % 4096) != 0))
1542 {
1543 /* The upper boundary must be one byte less than a 4KB boundary. */
1544 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
1545 }
1546
1547 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_LIMIT, ((pGlobals->uPciBiosIo >> 8) & 0xf0) - 1, 1);
1548
1549 /* Same with the MMIO limit register but with 1MB boundary here. */
1550 if ((u32MMIOAddressBase != pGlobals->uPciBiosMmio) && ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0))
1551 {
1552 /* The upper boundary must be one byte less than a 1MB boundary. */
1553 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
1554 }
1555 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_LIMIT, ((pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xfff0)) - 1, 2);
1556
1557 /*
1558 * Set the prefetch base and limit registers. We currently have no device with a prefetchable region
1559 * which may be behind a bridge. That's why it is unconditionally disabled here atm by writing a higher value into
1560 * the base register than in the limit register.
1561 */
1562 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_BASE, 0xfff0, 2);
1563 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_LIMIT, 0x0, 2);
1564 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_BASE_UPPER32, 0x00, 4);
1565 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_LIMIT_UPPER32, 0x00, 4);
1566}
1567
1568static void ich9pciBiosInitDevice(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint8_t cBridgeDepth, uint8_t *paBridgePositions)
1569{
1570 uint32_t *paddr;
1571 uint16_t uDevClass, uVendor, uDevice;
1572 uint8_t uCmd;
1573
1574 uDevClass = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_CLASS_DEVICE, 2);
1575 uVendor = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_VENDOR_ID, 2);
1576 uDevice = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_DEVICE_ID, 2);
1577
1578 /* If device is present */
1579 if (uVendor == 0xffff)
1580 return;
1581
1582 switch (uDevClass)
1583 {
1584 case 0x0101:
1585 /* IDE controller */
1586 ich9pciConfigWrite(pGlobals, uBus, uDevFn, 0x40, 0x8000, 2); /* enable IDE0 */
1587 ich9pciConfigWrite(pGlobals, uBus, uDevFn, 0x42, 0x8000, 2); /* enable IDE1 */
1588 goto default_map;
1589 break;
1590 case 0x0300:
1591 /* VGA controller */
1592 if (uVendor != 0x80ee)
1593 goto default_map;
1594 /* VGA: map frame buffer to default Bochs VBE address */
1595 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, 0, 0xE0000000);
1596 /*
1597 * Legacy VGA I/O ports are implicitly decoded by a VGA class device. But
1598 * only the framebuffer (i.e., a memory region) is explicitly registered via
1599 * ich9pciSetRegionAddress, so I/O decoding must be enabled manually.
1600 */
1601 uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 1);
1602 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND,
1603 /* Enable I/O space access. */
1604 uCmd | PCI_COMMAND_IOACCESS,
1605 1);
1606 break;
1607 case 0x0604:
1608 /* PCI-to-PCI bridge. */
1609 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PRIMARY_BUS, uBus, 1);
1610
1611 AssertMsg(pGlobals->uBus < 255, ("Too many bridges on the bus\n"));
1612 pGlobals->uBus++;
1613 ich9pciBiosInitBridge(pGlobals, uBus, uDevFn, cBridgeDepth, paBridgePositions);
1614 break;
1615 default:
1616 default_map:
1617 {
1618 /* default memory mappings */
1619 /*
1620 * We ignore ROM region here.
1621 */
1622 for (int iRegion = 0; iRegion < (PCI_NUM_REGIONS-1); iRegion++)
1623 {
1624 uint32_t u32Address = ich9pciGetRegionReg(iRegion);
1625
1626 /* Calculate size. */
1627 uint8_t u8ResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 1);
1628 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
1629 uint32_t u32Size = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4);
1630 /* Clear resource information depending on resource type. */
1631 if ((u8ResourceType & PCI_COMMAND_IOACCESS) == PCI_COMMAND_IOACCESS) /* I/O */
1632 u32Size &= ~(0x01);
1633 else /* MMIO */
1634 u32Size &= ~(0x0f);
1635
1636 bool fIsPio = ((u8ResourceType & PCI_COMMAND_IOACCESS) == PCI_COMMAND_IOACCESS);
1637 /*
1638 * Invert all bits and add 1 to get size of the region.
1639 * (From PCI implementation note)
1640 */
1641 if (fIsPio && (u32Size & UINT32_C(0xffff0000)) == 0)
1642 u32Size = (~(u32Size | UINT32_C(0xffff0000))) + 1;
1643 else
1644 u32Size = (~u32Size) + 1;
1645
1646 Log(("%s: Size of region %u for device %d on bus %d is %u\n", __FUNCTION__, iRegion, uDevFn, uBus, u32Size));
1647
1648 if (u32Size)
1649 {
1650 paddr = fIsPio ? &pGlobals->uPciBiosIo : &pGlobals->uPciBiosMmio;
1651 *paddr = (*paddr + u32Size - 1) & ~(u32Size - 1);
1652 Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, (fIsPio ? "I/O" : "MMIO"), iRegion, *paddr));
1653 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, iRegion, *paddr);
1654 *paddr += u32Size;
1655 Log(("%s: New address is %#x\n", __FUNCTION__, *paddr));
1656 }
1657 }
1658 break;
1659 }
1660 }
1661}
1662
1663static DECLCALLBACK(int) ich9pciFakePCIBIOS(PPDMDEVINS pDevIns)
1664{
1665 unsigned i;
1666 uint8_t elcr[2] = {0, 0};
1667 PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
1668 PVM pVM = PDMDevHlpGetVM(pDevIns);
1669 Assert(pVM);
1670
1671 /*
1672 * Set the start addresses.
1673 */
1674 pGlobals->uPciBiosIo = 0xd000;
1675 pGlobals->uPciBiosMmio = UINT32_C(0xf0000000);
1676 pGlobals->uBus = 0;
1677
1678 /*
1679 * Init the devices.
1680 */
1681 for (i = 0; i < 256; i++)
1682 {
1683 uint8_t aBridgePositions[256];
1684
1685 memset(aBridgePositions, 0, sizeof(aBridgePositions));
1686 Log2(("PCI: Initializing device %d (%#x)\n",
1687 i, 0x80000000 | (i << 8)));
1688 ich9pciBiosInitDevice(pGlobals, 0, i, 0, aBridgePositions);
1689 }
1690
1691 return VINF_SUCCESS;
1692}
1693
1694static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PCIDevice *aDev, uint32_t u32Address, unsigned len)
1695{
1696 if ((u32Address + len) > 256 && (u32Address + len) < 4096)
1697 {
1698 AssertMsgReturn(false, ("Read from extended registers falled back to generic code\n"), 0);
1699 }
1700
1701 if ( PCIIsMsiCapable(aDev)
1702 && (u32Address >= aDev->Int.s.u8MsiCapOffset)
1703 && (u32Address < aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize)
1704 )
1705 {
1706 return MsiPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
1707 }
1708
1709 if ( PCIIsMsixCapable(aDev)
1710 && (u32Address >= aDev->Int.s.u8MsixCapOffset)
1711 && (u32Address < aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize)
1712 )
1713 {
1714 return MsixPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
1715 }
1716
1717 AssertMsgReturn(u32Address + len <= 256, ("Read after end of PCI config space\n"),
1718 0);
1719 switch (len)
1720 {
1721 case 1:
1722 return PCIDevGetByte(aDev, u32Address);
1723 case 2:
1724 return PCIDevGetWord(aDev, u32Address);
1725 case 4:
1726 return PCIDevGetDWord(aDev, u32Address);
1727 default:
1728 Assert(false);
1729 return 0;
1730 }
1731}
1732
1733DECLINLINE(void) ich9pciWriteBarByte(PCIDevice *aDev, int iRegion, int iOffset, uint8_t u8Val)
1734{
1735 PCIIORegion * pRegion = &aDev->Int.s.aIORegions[iRegion];
1736
1737 int iRegionSize = pRegion->size;
1738
1739 /* Region doesn't exist */
1740 if (iRegionSize == 0)
1741 return;
1742
1743 uint32_t uAddr = ich9pciGetRegionReg(iRegion) + iOffset;
1744 /* Region size must be power of two */
1745 Assert((iRegionSize & (iRegionSize - 1)) == 0);
1746 uint8_t uMask = ((iRegionSize - 1) >> (iOffset*8)) & 0xff;
1747
1748 if (iOffset == 0)
1749 {
1750 uMask |= (pRegion->type & PCI_ADDRESS_SPACE_IO) ?
1751 (1 << 2) - 1 /* 2 lowest bits for IO region */ :
1752 (1 << 4) - 1 /* 4 lowest bits for memory region, also ROM enable bit for ROM region */;
1753 }
1754
1755 u8Val = (PCIDevGetByte(aDev, uAddr) & uMask) | (u8Val & ~uMask);
1756 PCIDevSetByte(aDev, uAddr, u8Val);
1757}
1758/**
1759 * See paragraph 7.5 of PCI Express specification (p. 349) for definition of
1760 * registers and their writability policy.
1761 */
1762static DECLCALLBACK(void) ich9pciConfigWriteDev(PCIDevice *aDev, uint32_t u32Address,
1763 uint32_t val, unsigned len)
1764{
1765 Assert(len <= 4);
1766
1767 if ((u32Address + len) > 256 && (u32Address + len) < 4096)
1768 {
1769 AssertMsgReturnVoid(false, ("Write to extended registers falled back to generic code\n"));
1770 }
1771
1772 AssertMsgReturnVoid(u32Address + len <= 256, ("Write after end of PCI config space\n"));
1773
1774 if ( PCIIsMsiCapable(aDev)
1775 && (u32Address >= aDev->Int.s.u8MsiCapOffset)
1776 && (u32Address < aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize)
1777 )
1778 {
1779 MsiPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
1780 aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
1781 aDev, u32Address, val, len);
1782 return;
1783 }
1784
1785 if ( PCIIsMsixCapable(aDev)
1786 && (u32Address >= aDev->Int.s.u8MsixCapOffset)
1787 && (u32Address < aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize)
1788 )
1789 {
1790 MsixPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
1791 aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
1792 aDev, u32Address, val, len);
1793 return;
1794 }
1795
1796 uint32_t addr = u32Address;
1797 bool fUpdateMappings = false;
1798 for (uint32_t i = 0; i < len; i++)
1799 {
1800 bool fWritable = false;
1801 bool fRom = false;
1802 switch (PCIDevGetHeaderType(aDev))
1803 {
1804 case 0x00: /* normal device */
1805 case 0x80: /* multi-function device */
1806 switch (addr)
1807 {
1808 /* Read-only registers */
1809 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
1810 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
1811 case VBOX_PCI_REVISION_ID:
1812 case VBOX_PCI_CLASS_PROG:
1813 case VBOX_PCI_CLASS_SUB:
1814 case VBOX_PCI_CLASS_BASE:
1815 case VBOX_PCI_HEADER_TYPE:
1816 case VBOX_PCI_SUBSYSTEM_VENDOR_ID: case VBOX_PCI_SUBSYSTEM_VENDOR_ID+1:
1817 case VBOX_PCI_SUBSYSTEM_ID: case VBOX_PCI_SUBSYSTEM_ID+1:
1818 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS+1: case VBOX_PCI_ROM_ADDRESS+2: case VBOX_PCI_ROM_ADDRESS+3:
1819 case VBOX_PCI_CAPABILITY_LIST:
1820 case VBOX_PCI_INTERRUPT_PIN:
1821 fWritable = false;
1822 break;
1823 /* Others can be written */
1824 default:
1825 fWritable = true;
1826 break;
1827 }
1828 break;
1829 default:
1830 case 0x01: /* PCI-PCI bridge */
1831 switch (addr)
1832 {
1833 /* Read-only registers */
1834 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
1835 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
1836 case VBOX_PCI_REVISION_ID:
1837 case VBOX_PCI_CLASS_PROG:
1838 case VBOX_PCI_CLASS_SUB:
1839 case VBOX_PCI_CLASS_BASE:
1840 case VBOX_PCI_HEADER_TYPE:
1841 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:
1842 case VBOX_PCI_INTERRUPT_PIN:
1843 fWritable = false;
1844 break;
1845 default:
1846 fWritable = true;
1847 break;
1848 }
1849 break;
1850 }
1851
1852 uint8_t u8Val = (uint8_t)val;
1853 switch (addr)
1854 {
1855 case VBOX_PCI_COMMAND: /* Command register, bits 0-7. */
1856 fUpdateMappings = true;
1857 PCIDevSetByte(aDev, addr, u8Val);
1858 break;
1859 case VBOX_PCI_COMMAND+1: /* Command register, bits 8-15. */
1860 /* don't change reserved bits (11-15) */
1861 u8Val &= UINT32_C(~0xf8);
1862 fUpdateMappings = true;
1863 PCIDevSetByte(aDev, addr, u8Val);
1864 break;
1865 case VBOX_PCI_STATUS: /* Status register, bits 0-7. */
1866 /* don't change read-only bits => actually all lower bits are read-only */
1867 u8Val &= UINT32_C(~0xff);
1868 /* status register, low part: clear bits by writing a '1' to the corresponding bit */
1869 aDev->config[addr] &= ~u8Val;
1870 break;
1871 case VBOX_PCI_STATUS+1: /* Status register, bits 8-15. */
1872 /* don't change read-only bits */
1873 u8Val &= UINT32_C(~0x06);
1874 /* status register, high part: clear bits by writing a '1' to the corresponding bit */
1875 aDev->config[addr] &= ~u8Val;
1876 break;
1877 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS +1: case VBOX_PCI_ROM_ADDRESS +2: case VBOX_PCI_ROM_ADDRESS +3:
1878 fRom = true;
1879 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:
1880 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:
1881 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:
1882 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:
1883 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:
1884 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:
1885 {
1886 int iRegion = fRom ? VBOX_PCI_ROM_SLOT : (addr - VBOX_PCI_BASE_ADDRESS_0) >> 2;
1887 int iOffset = addr & 0x3;
1888 ich9pciWriteBarByte(aDev, iRegion, iOffset, u8Val);
1889 fUpdateMappings = true;
1890 break;
1891 }
1892 default:
1893 if (fWritable)
1894 PCIDevSetByte(aDev, addr, u8Val);
1895 }
1896 addr++;
1897 val >>= 8;
1898 }
1899
1900 if (fUpdateMappings)
1901 /* if the command/base address register is modified, we must modify the mappings */
1902 ich9pciUpdateMappings(aDev);
1903}
1904
1905/* Slot/functions assignment per table at p. 12 of ICH9 family spec update */
1906static const struct {
1907 const char* pszName;
1908 int32_t iSlot;
1909 int32_t iFunction;
1910} PciSlotAssignments[] = {
1911 /* The only override that have to be here, as host controller is added in the way invisible to bus slot assignment management,
1912 maybe to be changed in the future. */
1913 {
1914 "i82801", 30, 0 /* Host Controller */
1915 },
1916};
1917
1918static bool assignPosition(PPCIBUS pBus, PPCIDEVICE pPciDev, const char *pszName, int iDevFn, PciAddress* aPosition)
1919{
1920 aPosition->iBus = 0;
1921 aPosition->iDeviceFunc = iDevFn;
1922 aPosition->iRegister = 0; /* N/A */
1923
1924 /* Hardcoded slots/functions, per chipset spec */
1925 for (size_t i = 0; i < RT_ELEMENTS(PciSlotAssignments); i++)
1926 {
1927 if (!strcmp(pszName, PciSlotAssignments[i].pszName))
1928 {
1929 PCISetRequestedDevfunc(pPciDev);
1930 aPosition->iDeviceFunc =
1931 (PciSlotAssignments[i].iSlot << 3) + PciSlotAssignments[i].iFunction;
1932 return true;
1933 }
1934 }
1935
1936 /* Explicit slot request */
1937 if (iDevFn >=0 && iDevFn < (int)RT_ELEMENTS(pBus->apDevices))
1938 return true;
1939
1940 int iStartPos = 0;
1941
1942 /* Otherwise when assigning a slot, we need to make sure all its functions are available */
1943 for (int iPos = iStartPos; iPos < (int)RT_ELEMENTS(pBus->apDevices); iPos += 8)
1944 {
1945 if ( !pBus->apDevices[iPos]
1946 && !pBus->apDevices[iPos + 1]
1947 && !pBus->apDevices[iPos + 2]
1948 && !pBus->apDevices[iPos + 3]
1949 && !pBus->apDevices[iPos + 4]
1950 && !pBus->apDevices[iPos + 5]
1951 && !pBus->apDevices[iPos + 6]
1952 && !pBus->apDevices[iPos + 7])
1953 {
1954 PCIClearRequestedDevfunc(pPciDev);
1955 aPosition->iDeviceFunc = iPos;
1956 return true;
1957 }
1958 }
1959
1960 return false;
1961}
1962
1963static bool hasHardAssignedDevsInSlot(PPCIBUS pBus, int iSlot)
1964{
1965 PCIDevice** aSlot = &pBus->apDevices[iSlot << 3];
1966
1967 return (aSlot[0] && PCIIsRequestedDevfunc(aSlot[0]))
1968 || (aSlot[1] && PCIIsRequestedDevfunc(aSlot[1]))
1969 || (aSlot[2] && PCIIsRequestedDevfunc(aSlot[2]))
1970 || (aSlot[3] && PCIIsRequestedDevfunc(aSlot[3]))
1971 || (aSlot[4] && PCIIsRequestedDevfunc(aSlot[4]))
1972 || (aSlot[5] && PCIIsRequestedDevfunc(aSlot[5]))
1973 || (aSlot[6] && PCIIsRequestedDevfunc(aSlot[6]))
1974 || (aSlot[7] && PCIIsRequestedDevfunc(aSlot[7]))
1975 ;
1976}
1977
1978static int ich9pciRegisterInternal(PPCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName)
1979{
1980 PciAddress aPosition = {0, 0, 0};
1981
1982 /*
1983 * Find device position
1984 */
1985 if (!assignPosition(pBus, pPciDev, pszName, iDev, &aPosition))
1986 {
1987 AssertMsgFailed(("Couldn't asssign position!\n"));
1988 return VERR_PDM_TOO_PCI_MANY_DEVICES;
1989 }
1990
1991 AssertMsgReturn(aPosition.iBus == 0,
1992 ("Assigning behind the bridge not implemented yet\n"),
1993 VERR_PDM_TOO_PCI_MANY_DEVICES);
1994
1995
1996 iDev = aPosition.iDeviceFunc;
1997 /*
1998 * Check if we can really take this slot, possibly by relocating
1999 * its current habitant, if it wasn't hard assigned too.
2000 */
2001 if (PCIIsRequestedDevfunc(pPciDev) &&
2002 pBus->apDevices[iDev] &&
2003 PCIIsRequestedDevfunc(pBus->apDevices[iDev]))
2004 {
2005 AssertReleaseMsgFailed(("Configuration error:'%s' and '%s' are both configured as device %d\n",
2006 pszName, pBus->apDevices[iDev]->name, iDev));
2007 return VERR_INTERNAL_ERROR;
2008 }
2009
2010 if (pBus->apDevices[iDev])
2011 {
2012 /* if we got here, we shall (and usually can) relocate the device */
2013 bool assigned = assignPosition(pBus, pBus->apDevices[iDev], pBus->apDevices[iDev]->name, -1, &aPosition);
2014 AssertMsgReturn(aPosition.iBus == 0,
2015 ("Assigning behind the bridge not implemented yet\n"),
2016 VERR_PDM_TOO_PCI_MANY_DEVICES);
2017 int iRelDev = aPosition.iDeviceFunc;
2018 if (!assigned || iRelDev == iDev)
2019 {
2020 AssertMsgFailed(("Couldn't find free spot!\n"));
2021 return VERR_PDM_TOO_PCI_MANY_DEVICES;
2022 }
2023 /* Copy device function by function to its new position */
2024 for (int i = 0; i < 8; i++)
2025 {
2026 if (!pBus->apDevices[iDev + i])
2027 continue;
2028 Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->apDevices[iDev + i]->name, iDev + i, iRelDev + i));
2029 pBus->apDevices[iRelDev + i] = pBus->apDevices[iDev + i];
2030 pBus->apDevices[iRelDev + i]->devfn = iRelDev + i;
2031 pBus->apDevices[iDev + i] = NULL;
2032 }
2033 }
2034
2035 /*
2036 * Fill in device information.
2037 */
2038 pPciDev->devfn = iDev;
2039 pPciDev->name = pszName;
2040 pPciDev->Int.s.pBusR3 = pBus;
2041 pPciDev->Int.s.pBusR0 = MMHyperR3ToR0(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
2042 pPciDev->Int.s.pBusRC = MMHyperR3ToRC(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
2043 pPciDev->Int.s.pfnConfigRead = ich9pciConfigReadDev;
2044 pPciDev->Int.s.pfnConfigWrite = ich9pciConfigWriteDev;
2045 pBus->apDevices[iDev] = pPciDev;
2046 if (PCIIsPci2PciBridge(pPciDev))
2047 {
2048 AssertMsg(pBus->cBridges < RT_ELEMENTS(pBus->apDevices), ("Number of bridges exceeds the number of possible devices on the bus\n"));
2049 AssertMsg(pPciDev->Int.s.pfnBridgeConfigRead && pPciDev->Int.s.pfnBridgeConfigWrite,
2050 ("device is a bridge but does not implement read/write functions\n"));
2051 pBus->papBridgesR3[pBus->cBridges] = pPciDev;
2052 pBus->cBridges++;
2053 }
2054
2055 Log(("PCI: Registered device %d function %d (%#x) '%s'.\n",
2056 iDev >> 3, iDev & 7, 0x80000000 | (iDev << 8), pszName));
2057
2058 return VINF_SUCCESS;
2059}
2060
2061static void printIndent(PCDBGFINFOHLP pHlp, int iIndent)
2062{
2063 for (int i = 0; i < iIndent; i++)
2064 {
2065 pHlp->pfnPrintf(pHlp, " ");
2066 }
2067}
2068
2069static void ich9pciBusInfo(PPCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent)
2070{
2071 for (uint32_t iDev = 0; iDev < RT_ELEMENTS(pBus->apDevices); iDev++)
2072 {
2073 PPCIDEVICE pPciDev = pBus->apDevices[iDev];
2074 if (pPciDev != NULL)
2075 {
2076 printIndent(pHlp, iIndent);
2077 pHlp->pfnPrintf(pHlp, "%02x:%02x:%02x %s: %04x-%04x%s%s\n",
2078 pBus->iBus, (iDev >> 3) & 0xff, iDev & 0x7,
2079 pPciDev->name,
2080 PCIDevGetVendorId(pPciDev), PCIDevGetDeviceId(pPciDev),
2081 PCIIsMsiCapable(pPciDev) ? " MSI" : "",
2082 PCIIsMsixCapable(pPciDev) ? " MSI-X" : ""
2083 );
2084 }
2085 }
2086
2087 if (pBus->cBridges > 0)
2088 {
2089 printIndent(pHlp, iIndent);
2090 pHlp->pfnPrintf(pHlp, "Registered %d bridges, subordinate buses info follows\n", pBus->cBridges);
2091 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2092 {
2093 PPCIBUS pBusSub = PDMINS_2_DATA(pBus->papBridgesR3[iBridge]->pDevIns, PPCIBUS);
2094 ich9pciBusInfo(pBusSub, pHlp, iIndent + 1);
2095 }
2096 }
2097}
2098
2099/**
2100 * Info handler, device version.
2101 *
2102 * @param pDevIns Device instance which registered the info.
2103 * @param pHlp Callback functions for doing output.
2104 * @param pszArgs Argument string. Optional and specific to the handler.
2105 */
2106static DECLCALLBACK(void) ich9pciInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2107{
2108 PPCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
2109
2110 ich9pciBusInfo(pBus, pHlp, 0);
2111}
2112
2113
2114static DECLCALLBACK(int) ich9pciConstruct(PPDMDEVINS pDevIns,
2115 int iInstance,
2116 PCFGMNODE pCfg)
2117{
2118 int rc;
2119 Assert(iInstance == 0);
2120
2121 /*
2122 * Validate and read configuration.
2123 */
2124 if (!CFGMR3AreValuesValid(pCfg,
2125 "IOAPIC\0"
2126 "GCEnabled\0"
2127 "R0Enabled\0"
2128 "McfgBase\0"
2129 "McfgLength\0"
2130 ))
2131 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2132
2133 /* query whether we got an IOAPIC */
2134 bool fUseIoApic;
2135 rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fUseIoApic, false);
2136 if (RT_FAILURE(rc))
2137 return PDMDEV_SET_ERROR(pDevIns, rc,
2138 N_("Configuration error: Failed to query boolean value \"IOAPIC\""));
2139
2140 /* check if RC code is enabled. */
2141 bool fGCEnabled;
2142 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2143 if (RT_FAILURE(rc))
2144 return PDMDEV_SET_ERROR(pDevIns, rc,
2145 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2146
2147 /* check if R0 code is enabled. */
2148 bool fR0Enabled;
2149 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2150 if (RT_FAILURE(rc))
2151 return PDMDEV_SET_ERROR(pDevIns, rc,
2152 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2153
2154 Log(("PCI: fUseIoApic=%RTbool fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fUseIoApic, fGCEnabled, fR0Enabled));
2155
2156 /*
2157 * Init data.
2158 */
2159 PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
2160 PPCIBUS pBus = &pGlobals->aPciBus;
2161 /* Zero out everything */
2162 memset(pGlobals, 0, sizeof(*pGlobals));
2163 /* And fill values */
2164 if (!fUseIoApic)
2165 return PDMDEV_SET_ERROR(pDevIns, rc,
2166 N_("Must use IO-APIC with ICH9 chipset"));
2167 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pGlobals->u64PciConfigMMioAddress, 0);
2168 if (RT_FAILURE(rc))
2169 return PDMDEV_SET_ERROR(pDevIns, rc,
2170 N_("Configuration error: Failed to read \"McfgBase\""));
2171 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pGlobals->u64PciConfigMMioLength, 0);
2172 if (RT_FAILURE(rc))
2173 return PDMDEV_SET_ERROR(pDevIns, rc,
2174 N_("Configuration error: Failed to read \"McfgLength\""));
2175
2176 pGlobals->pDevInsR3 = pDevIns;
2177 pGlobals->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2178 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2179
2180 pGlobals->aPciBus.pDevInsR3 = pDevIns;
2181 pGlobals->aPciBus.pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2182 pGlobals->aPciBus.pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2183 pGlobals->aPciBus.papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pGlobals->aPciBus.apDevices));
2184
2185 /*
2186 * Register bus
2187 */
2188 PDMPCIBUSREG PciBusReg;
2189 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2190 PciBusReg.pfnRegisterR3 = ich9pciRegister;
2191 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
2192 PciBusReg.pfnIORegionRegisterR3 = ich9pciIORegionRegister;
2193 PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
2194 PciBusReg.pfnSetIrqR3 = ich9pciSetIrq;
2195 PciBusReg.pfnSaveExecR3 = ich9pciGenericSaveExec;
2196 PciBusReg.pfnLoadExecR3 = ich9pciGenericLoadExec;
2197 PciBusReg.pfnFakePCIBIOSR3 = ich9pciFakePCIBIOS;
2198 PciBusReg.pszSetIrqRC = fGCEnabled ? "ich9pciSetIrq" : NULL;
2199 PciBusReg.pszSetIrqR0 = fR0Enabled ? "ich9pciSetIrq" : NULL;
2200 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2201 if (RT_FAILURE(rc))
2202 return PDMDEV_SET_ERROR(pDevIns, rc,
2203 N_("Failed to register ourselves as a PCI Bus"));
2204 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2205 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2206 N_("PCI helper version mismatch; got %#x expected %#x"),
2207 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
2208
2209 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2210 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2211
2212 /*
2213 * Fill in PCI configs and add them to the bus.
2214 */
2215
2216 /**
2217 * We emulate 82801IB ICH9 IO chip used in Q35,
2218 * see http://ark.intel.com/Product.aspx?id=31892
2219 *
2220 * Stepping S-Spec Top Marking
2221 *
2222 * A2 SLA9M NH82801IB
2223 */
2224 PCIDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
2225 PCIDevSetDeviceId( &pBus->aPciDev, 0x244e); /* Desktop */
2226 PCIDevSetRevisionId(&pBus->aPciDev, 0x92); /* rev. A2 */
2227 PCIDevSetClassSub( &pBus->aPciDev, 0x00); /* Host/PCI bridge */
2228 PCIDevSetClassBase( &pBus->aPciDev, 0x06); /* bridge */
2229 PCIDevSetHeaderType(&pBus->aPciDev, 0x00); /* normal device */
2230
2231 pBus->aPciDev.pDevIns = pDevIns;
2232 /* We register Host<->PCI controller on the bus */
2233 ich9pciRegisterInternal(pBus, -1, &pBus->aPciDev, "i82801");
2234
2235 /*
2236 * Register I/O ports and save state.
2237 */
2238 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cf8, 1, NULL, ich9pciIOPortAddressWrite, ich9pciIOPortAddressRead, NULL, NULL, "ICH9 (PCI)");
2239 if (RT_FAILURE(rc))
2240 return rc;
2241 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cfc, 4, NULL, ich9pciIOPortDataWrite, ich9pciIOPortDataRead, NULL, NULL, "ICH9 (PCI)");
2242 if (RT_FAILURE(rc))
2243 return rc;
2244 if (fGCEnabled)
2245 {
2246 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cf8, 1, NIL_RTGCPTR, "ich9pciIOPortAddressWrite", "ich9pciIOPortAddressRead", NULL, NULL, "ICH9 (PCI)");
2247 if (RT_FAILURE(rc))
2248 return rc;
2249 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cfc, 4, NIL_RTGCPTR, "ich9pciIOPortDataWrite", "ich9pciIOPortDataRead", NULL, NULL, "ICH9 (PCI)");
2250 if (RT_FAILURE(rc))
2251 return rc;
2252 }
2253 if (fR0Enabled)
2254 {
2255 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cf8, 1, NIL_RTR0PTR, "ich9pciIOPortAddressWrite", "ich9pciIOPortAddressRead", NULL, NULL, "ICH9 (PCI)");
2256 if (RT_FAILURE(rc))
2257 return rc;
2258 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cfc, 4, NIL_RTR0PTR, "ich9pciIOPortDataWrite", "ich9pciIOPortDataRead", NULL, NULL, "ICH9 (PCI)");
2259 if (RT_FAILURE(rc))
2260 return rc;
2261 }
2262
2263 if (pGlobals->u64PciConfigMMioAddress != 0)
2264 {
2265 rc = PDMDevHlpMMIORegister(pDevIns,
2266 pGlobals->u64PciConfigMMioAddress,
2267 pGlobals->u64PciConfigMMioLength,
2268 0,
2269 ich9pciMcfgMMIOWrite,
2270 ich9pciMcfgMMIORead,
2271 NULL /* fill */,
2272 "MCFG ranges");
2273 if (RT_FAILURE(rc))
2274 {
2275 AssertMsgRC(rc, ("Cannot register MCFG MMIO: %Rrc\n", rc));
2276 return rc;
2277 }
2278
2279 if (fGCEnabled)
2280 {
2281
2282 rc = PDMDevHlpMMIORegisterRC(pDevIns,
2283 pGlobals->u64PciConfigMMioAddress,
2284 pGlobals->u64PciConfigMMioLength,
2285 0,
2286 "ich9pciMcfgMMIOWrite",
2287 "ich9pciMcfgMMIORead",
2288 NULL /* fill */);
2289 if (RT_FAILURE(rc))
2290 {
2291 AssertMsgRC(rc, ("Cannot register MCFG MMIO (GC): %Rrc\n", rc));
2292 return rc;
2293 }
2294 }
2295
2296
2297 if (fR0Enabled)
2298 {
2299
2300 rc = PDMDevHlpMMIORegisterR0(pDevIns,
2301 pGlobals->u64PciConfigMMioAddress,
2302 pGlobals->u64PciConfigMMioLength,
2303 0,
2304 "ich9pciMcfgMMIOWrite",
2305 "ich9pciMcfgMMIORead",
2306 NULL /* fill */);
2307 if (RT_FAILURE(rc))
2308 {
2309 AssertMsgRC(rc, ("Cannot register MCFG MMIO (R0): %Rrc\n", rc));
2310 return rc;
2311 }
2312 }
2313 }
2314
2315 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
2316 sizeof(*pBus) + 16*128, "pgm",
2317 NULL, NULL, NULL,
2318 NULL, ich9pciR3SaveExec, NULL,
2319 NULL, ich9pciR3LoadExec, NULL);
2320 if (RT_FAILURE(rc))
2321 return rc;
2322
2323
2324 /** @todo: other chipset devices shall be registered too */
2325 /** @todo: what to with bridges? */
2326
2327 PDMDevHlpDBGFInfoRegister(pDevIns, "pci", "Display PCI bus status. (no arguments)", ich9pciInfo);
2328
2329 return VINF_SUCCESS;
2330}
2331
2332static void ich9pciResetDevice(PPCIDEVICE pDev)
2333{
2334 pDev->config[VBOX_PCI_COMMAND] &= ~(VBOX_PCI_COMMAND_IO | VBOX_PCI_COMMAND_MEMORY |
2335 VBOX_PCI_COMMAND_MASTER);
2336
2337 if (!PCIIsPci2PciBridge(pDev))
2338 {
2339 PCIDevSetByte(pDev, VBOX_PCI_CACHE_LINE_SIZE, 0x0);
2340 PCIDevSetByte(pDev, VBOX_PCI_INTERRUPT_LINE, 0x0);
2341 }
2342 /* Regions ? */
2343}
2344
2345
2346/**
2347 * @copydoc FNPDMDEVRESET
2348 */
2349static DECLCALLBACK(void) ich9pciReset(PPDMDEVINS pDevIns)
2350{
2351 PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
2352 PPCIBUS pBus = &pGlobals->aPciBus;
2353
2354 /* Relocate RC pointers for the attached pci devices. */
2355 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2356 {
2357 if (pBus->apDevices[i])
2358 ich9pciResetDevice(pBus->apDevices[i]);
2359 }
2360}
2361
2362/**
2363 * @copydoc FNPDMDEVRELOCATE
2364 */
2365static DECLCALLBACK(void) ich9pciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2366{
2367 PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
2368 PPCIBUS pBus = &pGlobals->aPciBus;
2369 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2370
2371 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2372 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2373
2374 /* Relocate RC pointers for the attached pci devices. */
2375 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2376 {
2377 if (pBus->apDevices[i])
2378 {
2379 pBus->apDevices[i]->Int.s.pBusRC += offDelta;
2380 if (pBus->apDevices[i]->Int.s.pMsixPageRC)
2381 pBus->apDevices[i]->Int.s.pMsixPageRC += offDelta;
2382 }
2383 }
2384
2385}
2386
2387/**
2388 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2389 */
2390static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
2391 int iInstance,
2392 PCFGMNODE pCfg)
2393{
2394 int rc;
2395
2396 /*
2397 * Validate and read configuration.
2398 */
2399 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
2400 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2401
2402 /* check if RC code is enabled. */
2403 bool fGCEnabled;
2404 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2405 if (RT_FAILURE(rc))
2406 return PDMDEV_SET_ERROR(pDevIns, rc,
2407 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2408
2409 /* check if R0 code is enabled. */
2410 bool fR0Enabled;
2411 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2412 if (RT_FAILURE(rc))
2413 return PDMDEV_SET_ERROR(pDevIns, rc,
2414 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2415 Log(("PCI: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
2416
2417 /*
2418 * Init data and register the PCI bus.
2419 */
2420 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
2421 pBus->pDevInsR3 = pDevIns;
2422 pBus->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2423 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2424 pBus->papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pBus->apDevices));
2425
2426 PDMPCIBUSREG PciBusReg;
2427 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2428 PciBusReg.pfnRegisterR3 = ich9pcibridgeRegister;
2429 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
2430 PciBusReg.pfnIORegionRegisterR3 = ich9pciIORegionRegister;
2431 PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
2432 PciBusReg.pfnSetIrqR3 = ich9pcibridgeSetIrq;
2433 PciBusReg.pfnSaveExecR3 = ich9pciGenericSaveExec;
2434 PciBusReg.pfnLoadExecR3 = ich9pciGenericLoadExec;
2435 PciBusReg.pfnFakePCIBIOSR3 = NULL; /* Only needed for the first bus. */
2436 PciBusReg.pszSetIrqRC = fGCEnabled ? "ich9pcibridgeSetIrq" : NULL;
2437 PciBusReg.pszSetIrqR0 = fR0Enabled ? "ich9pcibridgeSetIrq" : NULL;
2438 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2439 if (RT_FAILURE(rc))
2440 return PDMDEV_SET_ERROR(pDevIns, rc,
2441 N_("Failed to register ourselves as a PCI Bus"));
2442 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2443 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2444 N_("PCI helper version mismatch; got %#x expected %#x"),
2445 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
2446
2447 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2448 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2449
2450 /*
2451 * Fill in PCI configs and add them to the bus.
2452 */
2453 PCIDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
2454 PCIDevSetDeviceId( &pBus->aPciDev, 0x2448); /* 82801 Mobile PCI bridge. */
2455 PCIDevSetRevisionId(&pBus->aPciDev, 0xf2);
2456 PCIDevSetClassSub( &pBus->aPciDev, 0x04); /* pci2pci */
2457 PCIDevSetClassBase( &pBus->aPciDev, 0x06); /* PCI_bridge */
2458 PCIDevSetClassProg( &pBus->aPciDev, 0x01); /* Supports subtractive decoding. */
2459 PCIDevSetHeaderType(&pBus->aPciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
2460 PCIDevSetCommand( &pBus->aPciDev, 0x00);
2461 PCIDevSetStatus( &pBus->aPciDev, 0x20); /* 66MHz Capable. */
2462 PCIDevSetInterruptLine(&pBus->aPciDev, 0x00); /* This device does not assert interrupts. */
2463
2464 /*
2465 * This device does not generate interrupts. Interrupt delivery from
2466 * devices attached to the bus is unaffected.
2467 */
2468 PCIDevSetInterruptPin (&pBus->aPciDev, 0x00);
2469
2470 pBus->aPciDev.pDevIns = pDevIns;
2471
2472 /* Bridge-specific data */
2473 PCISetPci2PciBridge(&pBus->aPciDev);
2474 pBus->aPciDev.Int.s.pfnBridgeConfigRead = ich9pcibridgeConfigRead;
2475 pBus->aPciDev.Int.s.pfnBridgeConfigWrite = ich9pcibridgeConfigWrite;
2476
2477 /*
2478 * Register this PCI bridge. The called function will take care on which bus we will get registered.
2479 */
2480 rc = PDMDevHlpPCIRegister (pDevIns, &pBus->aPciDev);
2481 if (RT_FAILURE(rc))
2482 return rc;
2483
2484 /*
2485 * The iBus property doesn't really represent the bus number
2486 * because the guest and the BIOS can choose different bus numbers
2487 * for them.
2488 * The bus number is mainly for the setIrq function to indicate
2489 * when the host bus is reached which will have iBus = 0.
2490 * That's why the + 1.
2491 */
2492 pBus->iBus = iInstance + 1;
2493
2494 /*
2495 * Register SSM handlers. We use the same saved state version as for the host bridge
2496 * to make changes easier.
2497 */
2498 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
2499 sizeof(*pBus) + 16*128,
2500 "pgm" /* before */,
2501 NULL, NULL, NULL,
2502 NULL, ich9pcibridgeR3SaveExec, NULL,
2503 NULL, ich9pcibridgeR3LoadExec, NULL);
2504 if (RT_FAILURE(rc))
2505 return rc;
2506
2507
2508 return VINF_SUCCESS;
2509}
2510
2511/**
2512 * @copydoc FNPDMDEVRESET
2513 */
2514static DECLCALLBACK(void) ich9pcibridgeReset(PPDMDEVINS pDevIns)
2515{
2516 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
2517
2518 /* Reset config space to default values. */
2519 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_PRIMARY_BUS, 0);
2520 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS, 0);
2521 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_SUBORDINATE_BUS, 0);
2522}
2523
2524
2525/**
2526 * @copydoc FNPDMDEVRELOCATE
2527 */
2528static DECLCALLBACK(void) ich9pcibridgeRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2529{
2530 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
2531 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2532
2533 /* Relocate RC pointers for the attached pci devices. */
2534 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2535 {
2536 if (pBus->apDevices[i])
2537 pBus->apDevices[i]->Int.s.pBusRC += offDelta;
2538 }
2539
2540}
2541
2542/**
2543 * The PCI bus device registration structure.
2544 */
2545const PDMDEVREG g_DevicePciIch9 =
2546{
2547 /* u32Version */
2548 PDM_DEVREG_VERSION,
2549 /* szName */
2550 "ich9pci",
2551 /* szRCMod */
2552 "VBoxDDGC.gc",
2553 /* szR0Mod */
2554 "VBoxDDR0.r0",
2555 /* pszDescription */
2556 "ICH9 PCI bridge",
2557 /* fFlags */
2558 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2559 /* fClass */
2560 PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
2561 /* cMaxInstances */
2562 1,
2563 /* cbInstance */
2564 sizeof(PCIGLOBALS),
2565 /* pfnConstruct */
2566 ich9pciConstruct,
2567 /* pfnDestruct */
2568 NULL,
2569 /* pfnRelocate */
2570 ich9pciRelocate,
2571 /* pfnIOCtl */
2572 NULL,
2573 /* pfnPowerOn */
2574 NULL,
2575 /* pfnReset */
2576 ich9pciReset,
2577 /* pfnSuspend */
2578 NULL,
2579 /* pfnResume */
2580 NULL,
2581 /* pfnAttach */
2582 NULL,
2583 /* pfnDetach */
2584 NULL,
2585 /* pfnQueryInterface */
2586 NULL,
2587 /* pfnInitComplete */
2588 NULL,
2589 /* pfnPowerOff */
2590 NULL,
2591 /* pfnSoftReset */
2592 NULL,
2593 /* u32VersionEnd */
2594 PDM_DEVREG_VERSION
2595};
2596
2597/**
2598 * The device registration structure
2599 * for the PCI-to-PCI bridge.
2600 */
2601const PDMDEVREG g_DevicePciIch9Bridge =
2602{
2603 /* u32Version */
2604 PDM_DEVREG_VERSION,
2605 /* szName */
2606 "ich9pcibridge",
2607 /* szRCMod */
2608 "VBoxDDGC.gc",
2609 /* szR0Mod */
2610 "VBoxDDR0.r0",
2611 /* pszDescription */
2612 "ICH9 PCI to PCI bridge",
2613 /* fFlags */
2614 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2615 /* fClass */
2616 PDM_DEVREG_CLASS_BUS_PCI,
2617 /* cMaxInstances */
2618 ~0,
2619 /* cbInstance */
2620 sizeof(PCIBUS),
2621 /* pfnConstruct */
2622 ich9pcibridgeConstruct,
2623 /* pfnDestruct */
2624 NULL,
2625 /* pfnRelocate */
2626 ich9pcibridgeRelocate,
2627 /* pfnIOCtl */
2628 NULL,
2629 /* pfnPowerOn */
2630 NULL,
2631 /* pfnReset */
2632 ich9pcibridgeReset,
2633 /* pfnSuspend */
2634 NULL,
2635 /* pfnResume */
2636 NULL,
2637 /* pfnAttach */
2638 NULL,
2639 /* pfnDetach */
2640 NULL,
2641 /* pfnQueryInterface */
2642 NULL,
2643 /* pfnInitComplete */
2644 NULL,
2645 /* pfnPowerOff */
2646 NULL,
2647 /* pfnSoftReset */
2648 NULL,
2649 /* u32VersionEnd */
2650 PDM_DEVREG_VERSION
2651};
2652
2653#endif /* IN_RING3 */
2654#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