VirtualBox

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

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

PCI: better logging, better access to non-existing devices

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