VirtualBox

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

Last change on this file since 44600 was 44600, checked in by vboxsync, 12 years ago

Annoying assertions.

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