VirtualBox

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

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

PCI: interrupt mapping

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

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