VirtualBox

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

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

Drop the pfnSaveExecR3 and pfnLoadExecR3 interfaces of the PCI buses (never used). Synced pciR3CommonRestoreConfig between the two PCI buses, dropping the constants in the table as they make double checking sizes and offsets harder. Also removing the pfnIOCtl device registration structure member, putting a pfnReserved in it's place.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 106.0 KB
Line 
1/* $Id: DevPciIch9.cpp 44508 2013-02-01 12:46:33Z 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 Assert((u8ResourceType & PCI_COMMAND_IOACCESS) == 0);
1674 }
1675 else
1676 {
1677 uint32_t cbRegSize32;
1678 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
1679 cbRegSize32 = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4);
1680
1681 /* Clear resource information depending on resource type. */
1682 if (fIsPio) /* PIO */
1683 cbRegSize32 &= ~UINT32_C(0x01);
1684 else /* MMIO */
1685 cbRegSize32 &= ~UINT32_C(0x0f);
1686
1687 /*
1688 * Invert all bits and add 1 to get size of the region.
1689 * (From PCI implementation note)
1690 */
1691 if (fIsPio && (cbRegSize32 & UINT32_C(0xffff0000)) == 0)
1692 cbRegSize32 = (~(cbRegSize32 | UINT32_C(0xffff0000))) + 1;
1693 else
1694 cbRegSize32 = (~cbRegSize32) + 1;
1695
1696 cbRegSize64 = cbRegSize32;
1697 }
1698 Assert(cbRegSize64 == (uint32_t)cbRegSize64);
1699 Log2(("%s: Size of region %u for device %d on bus %d is %lld\n", __FUNCTION__, iRegion, uDevFn, uBus, cbRegSize64));
1700
1701 if (cbRegSize64)
1702 {
1703 uint32_t cbRegSize32 = (uint32_t)cbRegSize64;
1704 uint32_t* paddr = fIsPio ? &pGlobals->uPciBiosIo : &pGlobals->uPciBiosMmio;
1705 *paddr = (*paddr + cbRegSize32 - 1) & ~(cbRegSize32 - 1);
1706 Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, (fIsPio ? "I/O" : "MMIO"), iRegion, *paddr));
1707 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, iRegion, *paddr);
1708 *paddr += cbRegSize32;
1709 Log2(("%s: New address is %#x\n", __FUNCTION__, *paddr));
1710
1711 if (f64bit)
1712 iRegion++; /* skip next region */
1713 }
1714 }
1715 break;
1716 }
1717 }
1718
1719 /* map the interrupt */
1720 uint32_t iPin = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_INTERRUPT_PIN, 1);
1721 if (iPin != 0)
1722 {
1723 iPin--;
1724
1725 if (uBus != 0)
1726 {
1727 /* Find bus this device attached to. */
1728 PICH9PCIBUS pBus = &pGlobals->aPciBus;
1729 while (1)
1730 {
1731 PPCIDEVICE pBridge = ich9pciFindBridge(pBus, uBus);
1732 if (!pBridge)
1733 {
1734 Assert(false);
1735 break;
1736 }
1737 if (uBus == PCIDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS))
1738 {
1739 /* OK, found bus this device attached to. */
1740 break;
1741 }
1742 pBus = PDMINS_2_DATA(pBridge->pDevIns, PICH9PCIBUS);
1743 }
1744
1745 /* We need to go up to the host bus to see which irq pin this
1746 * device will use there. See logic in ich9pcibridgeSetIrq().
1747 */
1748 while (pBus->iBus != 0)
1749 {
1750 /* Get the pin the device would assert on the bridge. */
1751 iPin = ((pBus->aPciDev.devfn >> 3) + iPin) & 3;
1752 pBus = pBus->aPciDev.Int.s.pBusR3;
1753 };
1754 }
1755
1756 int iIrq = aPciIrqs[ich9pciSlotGetPirq(uBus, uDevFn, iPin)];
1757 Log(("Using pin %d and IRQ %d for device %02x:%02x.%d\n",
1758 iPin, iIrq, uBus, uDevFn>>3, uDevFn&7));
1759 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_INTERRUPT_LINE, iIrq, 1);
1760 }
1761}
1762
1763/**
1764 * Initializes bridges registers used for routing.
1765 *
1766 * @returns nothing.
1767 * @param pGlobals Global device instance data used to generate unique bus numbers.
1768 * @param pBus The PCI bus to initialize.
1769 * @param uBusPrimary The primary bus number the bus is connected to.
1770 * @param uBusSecondary The secondary bus number, i.e. the bus number behind the bridge.
1771 */
1772static void ich9pciInitBridgeTopology(PICH9PCIGLOBALS pGlobals, PICH9PCIBUS pBus, unsigned uBusPrimary,
1773 unsigned uBusSecondary)
1774{
1775 PPCIDEVICE pBridgeDev = &pBus->aPciDev;
1776
1777 /* Set only if we are not on the root bus, it has no primary bus attached. */
1778 if (uBusSecondary != 0)
1779 {
1780 PCIDevSetByte(pBridgeDev, VBOX_PCI_PRIMARY_BUS, uBusPrimary);
1781 PCIDevSetByte(pBridgeDev, VBOX_PCI_SECONDARY_BUS, uBusSecondary);
1782 }
1783
1784 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
1785 {
1786 PPCIDEVICE pBridge = pBus->papBridgesR3[iBridge];
1787 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
1788 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
1789 PICH9PCIBUS pChildBus = PDMINS_2_DATA(pBridge->pDevIns, PICH9PCIBUS);
1790 pGlobals->uBus++;
1791 ich9pciInitBridgeTopology(pGlobals, pChildBus, uBusSecondary, pGlobals->uBus);
1792 }
1793 PCIDevSetByte(pBridgeDev, VBOX_PCI_SUBORDINATE_BUS, pGlobals->uBus);
1794 Log2(("ich9pciInitBridgeTopology: for bus %p: primary=%d secondary=%d subordinate=%d\n",
1795 pBus,
1796 PCIDevGetByte(pBridgeDev, VBOX_PCI_PRIMARY_BUS),
1797 PCIDevGetByte(pBridgeDev, VBOX_PCI_SECONDARY_BUS),
1798 PCIDevGetByte(pBridgeDev, VBOX_PCI_SUBORDINATE_BUS)
1799 ));
1800}
1801
1802
1803static DECLCALLBACK(int) ich9pciFakePCIBIOS(PPDMDEVINS pDevIns)
1804{
1805 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
1806 PVM pVM = PDMDevHlpGetVM(pDevIns);
1807 Assert(pVM);
1808
1809 /*
1810 * Set the start addresses.
1811 */
1812 pGlobals->uPciBiosIo = 0xd000;
1813 pGlobals->uPciBiosMmio = UINT32_C(0xf0000000);
1814 pGlobals->uBus = 0;
1815
1816 /*
1817 * Assign bridge topology, for further routing to work.
1818 */
1819 PICH9PCIBUS pBus = &pGlobals->aPciBus;
1820 ich9pciInitBridgeTopology(pGlobals, pBus, 0, 0);
1821
1822 /*
1823 * Init the devices.
1824 */
1825 for (int i = 0; i < 256; i++)
1826 {
1827 ich9pciBiosInitDevice(pGlobals, 0, i);
1828 }
1829
1830 return VINF_SUCCESS;
1831}
1832
1833static DECLCALLBACK(uint32_t) ich9pciConfigReadDev(PCIDevice *aDev, uint32_t u32Address, unsigned len)
1834{
1835 if ((u32Address + len) > 256 && (u32Address + len) < 4096)
1836 {
1837 LogRel(("Read from extended register %d fallen back to generic code\n",
1838 u32Address));
1839 return 0;
1840 }
1841
1842 AssertMsgReturn(u32Address + len <= 256, ("Read after the end of PCI config space\n"),
1843 0);
1844 if ( pciDevIsMsiCapable(aDev)
1845 && (u32Address >= aDev->Int.s.u8MsiCapOffset)
1846 && (u32Address < (unsigned)(aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize))
1847 )
1848 {
1849 return MsiPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
1850 }
1851
1852 if ( pciDevIsMsixCapable(aDev)
1853 && (u32Address >= aDev->Int.s.u8MsixCapOffset)
1854 && (u32Address < (unsigned)(aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize))
1855 )
1856 {
1857 return MsixPciConfigRead(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns), aDev, u32Address, len);
1858 }
1859
1860 AssertMsgReturn(u32Address + len <= 256, ("Read after end of PCI config space\n"),
1861 0);
1862 switch (len)
1863 {
1864 case 1:
1865 return PCIDevGetByte(aDev, u32Address);
1866 case 2:
1867 return PCIDevGetWord(aDev, u32Address);
1868 case 4:
1869 return PCIDevGetDWord(aDev, u32Address);
1870 default:
1871 Assert(false);
1872 return 0;
1873 }
1874}
1875
1876DECLINLINE(void) ich9pciWriteBarByte(PCIDevice *aDev, int iRegion, int iOffset, uint8_t u8Val)
1877{
1878 PCIIORegion * pRegion = &aDev->Int.s.aIORegions[iRegion];
1879 int64_t iRegionSize = pRegion->size;
1880
1881 Log3(("ich9pciWriteBarByte: region=%d off=%d val=%x size=%d\n",
1882 iRegion, iOffset, u8Val, iRegionSize));
1883
1884 if (iOffset > 3)
1885 Assert((aDev->Int.s.aIORegions[iRegion].type & PCI_ADDRESS_SPACE_BAR64) != 0);
1886
1887 /* Check if we're writing to upper part of 64-bit BAR. */
1888 if (aDev->Int.s.aIORegions[iRegion].type == 0xff)
1889 {
1890 ich9pciWriteBarByte(aDev, iRegion-1, iOffset+4, u8Val);
1891 return;
1892 }
1893
1894 /* Region doesn't exist */
1895 if (iRegionSize == 0)
1896 return;
1897
1898 uint32_t uAddr = ich9pciGetRegionReg(iRegion) + iOffset;
1899 /* Region size must be power of two */
1900 Assert((iRegionSize & (iRegionSize - 1)) == 0);
1901 uint8_t uMask = ((iRegionSize - 1) >> (iOffset*8) ) & 0xff;
1902
1903 if (iOffset == 0)
1904 {
1905 uMask |= (pRegion->type & PCI_ADDRESS_SPACE_IO) ?
1906 (1 << 2) - 1 /* 2 lowest bits for IO region */ :
1907 (1 << 4) - 1 /* 4 lowest bits for memory region, also ROM enable bit for ROM region */;
1908
1909 }
1910
1911 uint8_t u8Old = PCIDevGetByte(aDev, uAddr) & uMask;
1912 u8Val = (u8Old & uMask) | (u8Val & ~uMask);
1913
1914 Log3(("ich9pciWriteBarByte: was %x writing %x\n", u8Old, u8Val));
1915
1916 PCIDevSetByte(aDev, uAddr, u8Val);
1917}
1918
1919/**
1920 * See paragraph 7.5 of PCI Express specification (p. 349) for definition of
1921 * registers and their writability policy.
1922 */
1923static DECLCALLBACK(void) ich9pciConfigWriteDev(PCIDevice *aDev, uint32_t u32Address,
1924 uint32_t val, unsigned len)
1925{
1926 Assert(len <= 4);
1927
1928 if ((u32Address + len) > 256 && (u32Address + len) < 4096)
1929 {
1930 LogRel(("Write to extended register %d fallen back to generic code\n",
1931 u32Address));
1932 return;
1933 }
1934
1935 AssertMsgReturnVoid(u32Address + len <= 256, ("Write after end of PCI config space\n"));
1936
1937 if ( pciDevIsMsiCapable(aDev)
1938 && (u32Address >= aDev->Int.s.u8MsiCapOffset)
1939 && (u32Address < (unsigned)(aDev->Int.s.u8MsiCapOffset + aDev->Int.s.u8MsiCapSize))
1940 )
1941 {
1942 MsiPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
1943 aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
1944 aDev, u32Address, val, len);
1945 return;
1946 }
1947
1948 if ( pciDevIsMsixCapable(aDev)
1949 && (u32Address >= aDev->Int.s.u8MsixCapOffset)
1950 && (u32Address < (unsigned)(aDev->Int.s.u8MsixCapOffset + aDev->Int.s.u8MsixCapSize))
1951 )
1952 {
1953 MsixPciConfigWrite(aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pDevIns),
1954 aDev->Int.s.CTX_SUFF(pBus)->CTX_SUFF(pPciHlp),
1955 aDev, u32Address, val, len);
1956 return;
1957 }
1958
1959 uint32_t addr = u32Address;
1960 bool fUpdateMappings = false;
1961 bool fP2PBridge = false;
1962 /*bool fPassthrough = pciDevIsPassthrough(aDev);*/
1963 uint8_t u8HeaderType = ich9pciGetByte(aDev, VBOX_PCI_HEADER_TYPE);
1964
1965 for (uint32_t i = 0; i < len; i++)
1966 {
1967 bool fWritable = false;
1968 bool fRom = false;
1969 switch (u8HeaderType)
1970 {
1971 case 0x00: /* normal device */
1972 case 0x80: /* multi-function device */
1973 switch (addr)
1974 {
1975 /* Read-only registers */
1976 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
1977 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
1978 case VBOX_PCI_REVISION_ID:
1979 case VBOX_PCI_CLASS_PROG:
1980 case VBOX_PCI_CLASS_SUB:
1981 case VBOX_PCI_CLASS_BASE:
1982 case VBOX_PCI_HEADER_TYPE:
1983 case VBOX_PCI_SUBSYSTEM_VENDOR_ID: case VBOX_PCI_SUBSYSTEM_VENDOR_ID+1:
1984 case VBOX_PCI_SUBSYSTEM_ID: case VBOX_PCI_SUBSYSTEM_ID+1:
1985 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS+1: case VBOX_PCI_ROM_ADDRESS+2: case VBOX_PCI_ROM_ADDRESS+3:
1986 case VBOX_PCI_CAPABILITY_LIST:
1987 case VBOX_PCI_INTERRUPT_PIN:
1988 fWritable = false;
1989 break;
1990 /* Others can be written */
1991 default:
1992 fWritable = true;
1993 break;
1994 }
1995 break;
1996 case 0x01: /* PCI-PCI bridge */
1997 fP2PBridge = true;
1998 switch (addr)
1999 {
2000 /* Read-only registers */
2001 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
2002 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
2003 case VBOX_PCI_REVISION_ID:
2004 case VBOX_PCI_CLASS_PROG:
2005 case VBOX_PCI_CLASS_SUB:
2006 case VBOX_PCI_CLASS_BASE:
2007 case VBOX_PCI_HEADER_TYPE:
2008 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:
2009 case VBOX_PCI_INTERRUPT_PIN:
2010 fWritable = false;
2011 break;
2012 default:
2013 fWritable = true;
2014 break;
2015 }
2016 break;
2017 default:
2018 AssertMsgFailed(("Unknown header type %x\n", PCIDevGetHeaderType(aDev)));
2019 fWritable = false;
2020 break;
2021 }
2022
2023 uint8_t u8Val = (uint8_t)val;
2024 switch (addr)
2025 {
2026 case VBOX_PCI_COMMAND: /* Command register, bits 0-7. */
2027 fUpdateMappings = true;
2028 goto default_case;
2029 case VBOX_PCI_COMMAND+1: /* Command register, bits 8-15. */
2030 /* don't change reserved bits (11-15) */
2031 u8Val &= UINT32_C(~0xf8);
2032 fUpdateMappings = true;
2033 goto default_case;
2034 case VBOX_PCI_STATUS: /* Status register, bits 0-7. */
2035 /* don't change read-only bits => actually all lower bits are read-only */
2036 u8Val &= UINT32_C(~0xff);
2037 /* status register, low part: clear bits by writing a '1' to the corresponding bit */
2038 aDev->config[addr] &= ~u8Val;
2039 break;
2040 case VBOX_PCI_STATUS+1: /* Status register, bits 8-15. */
2041 /* don't change read-only bits */
2042 u8Val &= UINT32_C(~0x06);
2043 /* status register, high part: clear bits by writing a '1' to the corresponding bit */
2044 aDev->config[addr] &= ~u8Val;
2045 break;
2046 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS +1: case VBOX_PCI_ROM_ADDRESS +2: case VBOX_PCI_ROM_ADDRESS +3:
2047 fRom = true;
2048 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:
2049 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:
2050 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:
2051 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:
2052 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:
2053 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:
2054 {
2055 /* We check that, as same PCI register numbers as BARs may mean different registers for bridges */
2056 if (fP2PBridge)
2057 goto default_case;
2058 else
2059 {
2060 int iRegion = fRom ? VBOX_PCI_ROM_SLOT : (addr - VBOX_PCI_BASE_ADDRESS_0) >> 2;
2061 int iOffset = addr & 0x3;
2062 ich9pciWriteBarByte(aDev, iRegion, iOffset, u8Val);
2063 fUpdateMappings = true;
2064 }
2065 break;
2066 }
2067 default:
2068 default_case:
2069 if (fWritable)
2070 PCIDevSetByte(aDev, addr, u8Val);
2071 }
2072 addr++;
2073 val >>= 8;
2074 }
2075
2076 if (fUpdateMappings)
2077 /* if the command/base address register is modified, we must modify the mappings */
2078 ich9pciUpdateMappings(aDev);
2079}
2080
2081static bool assignPosition(PICH9PCIBUS pBus, PPCIDEVICE pPciDev, const char *pszName, int iDevFn, PciAddress* aPosition)
2082{
2083 NOREF(pszName);
2084 aPosition->iBus = 0;
2085 aPosition->iDeviceFunc = iDevFn;
2086 aPosition->iRegister = 0; /* N/A */
2087
2088 /* Explicit slot request */
2089 if (iDevFn >= 0 && iDevFn < (int)RT_ELEMENTS(pBus->apDevices))
2090 return true;
2091
2092 int iStartPos = 0;
2093
2094 /* Otherwise when assigning a slot, we need to make sure all its functions are available */
2095 for (int iPos = iStartPos; iPos < (int)RT_ELEMENTS(pBus->apDevices); iPos += 8)
2096 {
2097 if ( !pBus->apDevices[iPos]
2098 && !pBus->apDevices[iPos + 1]
2099 && !pBus->apDevices[iPos + 2]
2100 && !pBus->apDevices[iPos + 3]
2101 && !pBus->apDevices[iPos + 4]
2102 && !pBus->apDevices[iPos + 5]
2103 && !pBus->apDevices[iPos + 6]
2104 && !pBus->apDevices[iPos + 7])
2105 {
2106 pciDevClearRequestedDevfunc(pPciDev);
2107 aPosition->iDeviceFunc = iPos;
2108 return true;
2109 }
2110 }
2111
2112 return false;
2113}
2114
2115#ifdef SOME_UNUSED_FUNCTION
2116static bool hasHardAssignedDevsInSlot(PICH9PCIBUS pBus, int iSlot)
2117{
2118 PCIDevice** aSlot = &pBus->apDevices[iSlot << 3];
2119
2120 return (aSlot[0] && pciDevIsRequestedDevfunc(aSlot[0]))
2121 || (aSlot[1] && pciDevIsRequestedDevfunc(aSlot[1]))
2122 || (aSlot[2] && pciDevIsRequestedDevfunc(aSlot[2]))
2123 || (aSlot[3] && pciDevIsRequestedDevfunc(aSlot[3]))
2124 || (aSlot[4] && pciDevIsRequestedDevfunc(aSlot[4]))
2125 || (aSlot[5] && pciDevIsRequestedDevfunc(aSlot[5]))
2126 || (aSlot[6] && pciDevIsRequestedDevfunc(aSlot[6]))
2127 || (aSlot[7] && pciDevIsRequestedDevfunc(aSlot[7]))
2128 ;
2129}
2130#endif
2131
2132static int ich9pciRegisterInternal(PICH9PCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName)
2133{
2134 PciAddress aPosition = {0, 0, 0};
2135
2136 /*
2137 * Find device position
2138 */
2139 if (!assignPosition(pBus, pPciDev, pszName, iDev, &aPosition))
2140 {
2141 AssertMsgFailed(("Couldn't asssign position!\n"));
2142 return VERR_PDM_TOO_PCI_MANY_DEVICES;
2143 }
2144
2145 AssertMsgReturn(aPosition.iBus == 0,
2146 ("Assigning behind the bridge not implemented yet\n"),
2147 VERR_PDM_TOO_PCI_MANY_DEVICES);
2148
2149
2150 iDev = aPosition.iDeviceFunc;
2151 /*
2152 * Check if we can really take this slot, possibly by relocating
2153 * its current habitant, if it wasn't hard assigned too.
2154 */
2155 if (pciDevIsRequestedDevfunc(pPciDev) &&
2156 pBus->apDevices[iDev] &&
2157 pciDevIsRequestedDevfunc(pBus->apDevices[iDev]))
2158 {
2159 AssertReleaseMsgFailed(("Configuration error:'%s' and '%s' are both configured as device %d\n",
2160 pszName, pBus->apDevices[iDev]->name, iDev));
2161 return VERR_INTERNAL_ERROR;
2162 }
2163
2164 if (pBus->apDevices[iDev])
2165 {
2166 /* if we got here, we shall (and usually can) relocate the device */
2167 bool assigned = assignPosition(pBus, pBus->apDevices[iDev], pBus->apDevices[iDev]->name, -1, &aPosition);
2168 AssertMsgReturn(aPosition.iBus == 0,
2169 ("Assigning behind the bridge not implemented yet\n"),
2170 VERR_PDM_TOO_PCI_MANY_DEVICES);
2171 int iRelDev = aPosition.iDeviceFunc;
2172 if (!assigned || iRelDev == iDev)
2173 {
2174 AssertMsgFailed(("Couldn't find free spot!\n"));
2175 return VERR_PDM_TOO_PCI_MANY_DEVICES;
2176 }
2177 /* Copy device function by function to its new position */
2178 for (int i = 0; i < 8; i++)
2179 {
2180 if (!pBus->apDevices[iDev + i])
2181 continue;
2182 Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->apDevices[iDev + i]->name, iDev + i, iRelDev + i));
2183 pBus->apDevices[iRelDev + i] = pBus->apDevices[iDev + i];
2184 pBus->apDevices[iRelDev + i]->devfn = iRelDev + i;
2185 pBus->apDevices[iDev + i] = NULL;
2186 }
2187 }
2188
2189 /*
2190 * Fill in device information.
2191 */
2192 pPciDev->devfn = iDev;
2193 pPciDev->name = pszName;
2194 pPciDev->Int.s.pBusR3 = pBus;
2195 pPciDev->Int.s.pBusR0 = MMHyperR3ToR0(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
2196 pPciDev->Int.s.pBusRC = MMHyperR3ToRC(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
2197 pPciDev->Int.s.pfnConfigRead = ich9pciConfigReadDev;
2198 pPciDev->Int.s.pfnConfigWrite = ich9pciConfigWriteDev;
2199 pBus->apDevices[iDev] = pPciDev;
2200 if (pciDevIsPci2PciBridge(pPciDev))
2201 {
2202 AssertMsg(pBus->cBridges < RT_ELEMENTS(pBus->apDevices), ("Number of bridges exceeds the number of possible devices on the bus\n"));
2203 AssertMsg(pPciDev->Int.s.pfnBridgeConfigRead && pPciDev->Int.s.pfnBridgeConfigWrite,
2204 ("device is a bridge but does not implement read/write functions\n"));
2205 Log2(("Setting bridge %d on bus %p\n", pBus->cBridges, pBus));
2206 pBus->papBridgesR3[pBus->cBridges] = pPciDev;
2207 pBus->cBridges++;
2208 }
2209
2210 Log(("PCI: Registered device %d function %d on bus %d (%#x) '%s'.\n",
2211 iDev >> 3, iDev & 7, pBus->iBus, 0x80000000 | (iDev << 8), pszName));
2212
2213 return VINF_SUCCESS;
2214}
2215
2216static void printIndent(PCDBGFINFOHLP pHlp, int iIndent)
2217{
2218 for (int i = 0; i < iIndent; i++)
2219 {
2220 pHlp->pfnPrintf(pHlp, " ");
2221 }
2222}
2223
2224static void ich9pciBusInfo(PICH9PCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bool fRegisters)
2225{
2226 for (uint32_t iDev = 0; iDev < RT_ELEMENTS(pBus->apDevices); iDev++)
2227 {
2228 PPCIDEVICE pPciDev = pBus->apDevices[iDev];
2229 if (pPciDev != NULL)
2230 {
2231 printIndent(pHlp, iIndent);
2232
2233 /*
2234 * For passthrough devices MSI/MSI-X mostly reflects the way interrupts delivered to the guest,
2235 * as host driver handles real devices interrupts.
2236 */
2237 pHlp->pfnPrintf(pHlp, "%02x:%02x:%02x %s%s: %04x-%04x%s%s",
2238 pBus->iBus, (iDev >> 3) & 0xff, iDev & 0x7,
2239 pPciDev->name,
2240 pciDevIsPassthrough(pPciDev) ? " (PASSTHROUGH)" : "",
2241 ich9pciGetWord(pPciDev, VBOX_PCI_VENDOR_ID), ich9pciGetWord(pPciDev, VBOX_PCI_DEVICE_ID),
2242 pciDevIsMsiCapable(pPciDev) ? " MSI" : "",
2243 pciDevIsMsixCapable(pPciDev) ? " MSI-X" : ""
2244 );
2245 if (ich9pciGetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN) != 0)
2246 pHlp->pfnPrintf(pHlp, " IRQ%d", ich9pciGetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE));
2247
2248 pHlp->pfnPrintf(pHlp, "\n");
2249
2250 uint16_t iCmd = ich9pciGetWord(pPciDev, VBOX_PCI_COMMAND);
2251 if ((iCmd & (VBOX_PCI_COMMAND_IO | VBOX_PCI_COMMAND_MEMORY)) != 0)
2252 {
2253 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
2254 {
2255 PCIIORegion* pRegion = &pPciDev->Int.s.aIORegions[iRegion];
2256 uint64_t iRegionSize = pRegion->size;
2257
2258 if (iRegionSize == 0)
2259 continue;
2260
2261 uint32_t u32Addr = ich9pciGetDWord(pPciDev, ich9pciGetRegionReg(iRegion));
2262 const char * pszDesc;
2263 char szDescBuf[128];
2264
2265 bool f64Bit = !!(pRegion->type & PCI_ADDRESS_SPACE_BAR64);
2266 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
2267 {
2268 pszDesc = "IO";
2269 u32Addr &= ~0x3;
2270 }
2271 else
2272 {
2273 RTStrPrintf(szDescBuf, sizeof(szDescBuf), "MMIO%s%s",
2274 f64Bit ? "64" : "32",
2275 (pRegion->type & PCI_ADDRESS_SPACE_MEM_PREFETCH) ? " PREFETCH" : "");
2276 pszDesc = szDescBuf;
2277 u32Addr &= ~0xf;
2278 }
2279
2280 printIndent(pHlp, iIndent + 2);
2281 pHlp->pfnPrintf(pHlp, "%s region #%d: %x..%x\n",
2282 pszDesc, iRegion, u32Addr, u32Addr+iRegionSize);
2283 if (f64Bit)
2284 iRegion++;
2285 }
2286 }
2287
2288 printIndent(pHlp, iIndent + 2);
2289 uint16_t iStatus = ich9pciGetWord(pPciDev, VBOX_PCI_STATUS);
2290 pHlp->pfnPrintf(pHlp, "Command: %.*Rhxs, Status: %.*Rhxs\n",
2291 sizeof(uint16_t), &iCmd, sizeof(uint16_t), &iStatus);
2292 printIndent(pHlp, iIndent + 2);
2293 pHlp->pfnPrintf(pHlp, "Bus master: %s\n",
2294 iCmd & VBOX_PCI_COMMAND_MASTER ? "Yes" : "No");
2295
2296 if (fRegisters)
2297 {
2298 printIndent(pHlp, iIndent + 2);
2299 pHlp->pfnPrintf(pHlp, "PCI registers:\n");
2300 for (int iReg = 0; iReg < 0x100; )
2301 {
2302 int iPerLine = 0x10;
2303 Assert (0x100 % iPerLine == 0);
2304 printIndent(pHlp, iIndent + 3);
2305
2306 while (iPerLine-- > 0)
2307 {
2308 pHlp->pfnPrintf(pHlp, "%02x ", ich9pciGetByte(pPciDev, iReg++));
2309 }
2310 pHlp->pfnPrintf(pHlp, "\n");
2311 }
2312 }
2313 }
2314 }
2315
2316 if (pBus->cBridges > 0)
2317 {
2318 printIndent(pHlp, iIndent);
2319 pHlp->pfnPrintf(pHlp, "Registered %d bridges, subordinate buses info follows\n", pBus->cBridges);
2320 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2321 {
2322 PICH9PCIBUS pBusSub = PDMINS_2_DATA(pBus->papBridgesR3[iBridge]->pDevIns, PICH9PCIBUS);
2323 ich9pciBusInfo(pBusSub, pHlp, iIndent + 1, fRegisters);
2324 }
2325 }
2326}
2327
2328/**
2329 * Info handler, device version.
2330 *
2331 * @param pDevIns Device instance which registered the info.
2332 * @param pHlp Callback functions for doing output.
2333 * @param pszArgs Argument string. Optional and specific to the handler.
2334 */
2335static DECLCALLBACK(void) ich9pciInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2336{
2337 PICH9PCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
2338
2339 if (pszArgs == NULL || !strcmp(pszArgs, "basic"))
2340 {
2341 ich9pciBusInfo(pBus, pHlp, 0, false);
2342 }
2343 else if (!strcmp(pszArgs, "verbose"))
2344 {
2345 ich9pciBusInfo(pBus, pHlp, 0, true);
2346 }
2347 else
2348 {
2349 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'verbose'.\n");
2350 }
2351}
2352
2353
2354static DECLCALLBACK(int) ich9pciConstruct(PPDMDEVINS pDevIns,
2355 int iInstance,
2356 PCFGMNODE pCfg)
2357{
2358 Assert(iInstance == 0);
2359 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2360
2361 /*
2362 * Validate and read configuration.
2363 */
2364 if (!CFGMR3AreValuesValid(pCfg,
2365 "IOAPIC\0"
2366 "GCEnabled\0"
2367 "R0Enabled\0"
2368 "McfgBase\0"
2369 "McfgLength\0"
2370 ))
2371 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2372
2373 /* query whether we got an IOAPIC */
2374 bool fUseIoApic;
2375 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fUseIoApic, false);
2376 if (RT_FAILURE(rc))
2377 return PDMDEV_SET_ERROR(pDevIns, rc,
2378 N_("Configuration error: Failed to query boolean value \"IOAPIC\""));
2379
2380 /* check if RC code is enabled. */
2381 bool fGCEnabled;
2382 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2383 if (RT_FAILURE(rc))
2384 return PDMDEV_SET_ERROR(pDevIns, rc,
2385 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2386 /* check if R0 code is enabled. */
2387 bool fR0Enabled;
2388 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2389 if (RT_FAILURE(rc))
2390 return PDMDEV_SET_ERROR(pDevIns, rc,
2391 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2392
2393 Log(("PCI: fUseIoApic=%RTbool fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fUseIoApic, fGCEnabled, fR0Enabled));
2394
2395 /*
2396 * Init data.
2397 */
2398 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2399 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2400 /* Zero out everything */
2401 memset(pGlobals, 0, sizeof(*pGlobals));
2402 /* And fill values */
2403 if (!fUseIoApic)
2404 return PDMDEV_SET_ERROR(pDevIns, rc,
2405 N_("Must use IO-APIC with ICH9 chipset"));
2406 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pGlobals->u64PciConfigMMioAddress, 0);
2407 if (RT_FAILURE(rc))
2408 return PDMDEV_SET_ERROR(pDevIns, rc,
2409 N_("Configuration error: Failed to read \"McfgBase\""));
2410 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pGlobals->u64PciConfigMMioLength, 0);
2411 if (RT_FAILURE(rc))
2412 return PDMDEV_SET_ERROR(pDevIns, rc,
2413 N_("Configuration error: Failed to read \"McfgLength\""));
2414
2415 pGlobals->pDevInsR3 = pDevIns;
2416 pGlobals->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2417 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2418
2419 pGlobals->aPciBus.pDevInsR3 = pDevIns;
2420 pGlobals->aPciBus.pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2421 pGlobals->aPciBus.pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2422 pGlobals->aPciBus.papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pGlobals->aPciBus.apDevices));
2423
2424 /*
2425 * Register bus
2426 */
2427 PDMPCIBUSREG PciBusReg;
2428 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2429 PciBusReg.pfnRegisterR3 = ich9pciRegister;
2430 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
2431 PciBusReg.pfnIORegionRegisterR3 = ich9pciIORegionRegister;
2432 PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
2433 PciBusReg.pfnSetIrqR3 = ich9pciSetIrq;
2434 PciBusReg.pfnFakePCIBIOSR3 = ich9pciFakePCIBIOS;
2435 PciBusReg.pszSetIrqRC = fGCEnabled ? "ich9pciSetIrq" : NULL;
2436 PciBusReg.pszSetIrqR0 = fR0Enabled ? "ich9pciSetIrq" : NULL;
2437 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2438 if (RT_FAILURE(rc))
2439 return PDMDEV_SET_ERROR(pDevIns, rc,
2440 N_("Failed to register ourselves as a PCI Bus"));
2441 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2442 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2443 N_("PCI helper version mismatch; got %#x expected %#x"),
2444 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
2445
2446 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2447 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2448
2449 /*
2450 * Fill in PCI configs and add them to the bus.
2451 */
2452 /** @todo: Disabled for now because this causes error messages with Linux guests.
2453 * The guest loads the x38_edac device which tries to map a memory region
2454 * using an address given at place 0x48 - 0x4f in the PCi config space.
2455 * This fails. because we don't register such a region.
2456 */
2457#if 0
2458 /* Host bridge device */
2459 PCIDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
2460 PCIDevSetDeviceId( &pBus->aPciDev, 0x29e0); /* Desktop */
2461 PCIDevSetRevisionId(&pBus->aPciDev, 0x01); /* rev. 01 */
2462 PCIDevSetClassBase( &pBus->aPciDev, 0x06); /* bridge */
2463 PCIDevSetClassSub( &pBus->aPciDev, 0x00); /* Host/PCI bridge */
2464 PCIDevSetClassProg( &pBus->aPciDev, 0x00); /* Host/PCI bridge */
2465 PCIDevSetHeaderType(&pBus->aPciDev, 0x00); /* bridge */
2466 PCIDevSetWord(&pBus->aPciDev, VBOX_PCI_SEC_STATUS, 0x0280); /* secondary status */
2467
2468 pBus->aPciDev.pDevIns = pDevIns;
2469 /* We register Host<->PCI controller on the bus */
2470 ich9pciRegisterInternal(pBus, 0, &pBus->aPciDev, "dram");
2471#endif
2472
2473 /*
2474 * Register I/O ports and save state.
2475 */
2476 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cf8, 1, NULL, ich9pciIOPortAddressWrite, ich9pciIOPortAddressRead, NULL, NULL, "ICH9 (PCI)");
2477 if (RT_FAILURE(rc))
2478 return rc;
2479 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cfc, 4, NULL, ich9pciIOPortDataWrite, ich9pciIOPortDataRead, NULL, NULL, "ICH9 (PCI)");
2480 if (RT_FAILURE(rc))
2481 return rc;
2482 if (fGCEnabled)
2483 {
2484 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cf8, 1, NIL_RTGCPTR, "ich9pciIOPortAddressWrite", "ich9pciIOPortAddressRead", NULL, NULL, "ICH9 (PCI)");
2485 if (RT_FAILURE(rc))
2486 return rc;
2487 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cfc, 4, NIL_RTGCPTR, "ich9pciIOPortDataWrite", "ich9pciIOPortDataRead", NULL, NULL, "ICH9 (PCI)");
2488 if (RT_FAILURE(rc))
2489 return rc;
2490 }
2491 if (fR0Enabled)
2492 {
2493 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cf8, 1, NIL_RTR0PTR, "ich9pciIOPortAddressWrite", "ich9pciIOPortAddressRead", NULL, NULL, "ICH9 (PCI)");
2494 if (RT_FAILURE(rc))
2495 return rc;
2496 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cfc, 4, NIL_RTR0PTR, "ich9pciIOPortDataWrite", "ich9pciIOPortDataRead", NULL, NULL, "ICH9 (PCI)");
2497 if (RT_FAILURE(rc))
2498 return rc;
2499 }
2500
2501 if (pGlobals->u64PciConfigMMioAddress != 0)
2502 {
2503 rc = PDMDevHlpMMIORegister(pDevIns, pGlobals->u64PciConfigMMioAddress, pGlobals->u64PciConfigMMioLength, NULL /*pvUser*/,
2504 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
2505 ich9pciMcfgMMIOWrite, ich9pciMcfgMMIORead, "MCFG ranges");
2506 AssertMsgRCReturn(rc, ("rc=%Rrc %#llx/%#llx\n", rc, pGlobals->u64PciConfigMMioAddress, pGlobals->u64PciConfigMMioLength), rc);
2507
2508 if (fGCEnabled)
2509 {
2510 rc = PDMDevHlpMMIORegisterRC(pDevIns, pGlobals->u64PciConfigMMioAddress, pGlobals->u64PciConfigMMioLength,
2511 NIL_RTRCPTR /*pvUser*/, "ich9pciMcfgMMIOWrite", "ich9pciMcfgMMIORead");
2512 AssertRCReturn(rc, rc);
2513 }
2514
2515
2516 if (fR0Enabled)
2517 {
2518 rc = PDMDevHlpMMIORegisterR0(pDevIns, pGlobals->u64PciConfigMMioAddress, pGlobals->u64PciConfigMMioLength,
2519 NIL_RTR0PTR /*pvUser*/, "ich9pciMcfgMMIOWrite", "ich9pciMcfgMMIORead");
2520 AssertRCReturn(rc, rc);
2521 }
2522 }
2523
2524 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
2525 sizeof(*pBus) + 16*128, "pgm",
2526 NULL, NULL, NULL,
2527 NULL, ich9pciR3SaveExec, NULL,
2528 NULL, ich9pciR3LoadExec, NULL);
2529 if (RT_FAILURE(rc))
2530 return rc;
2531
2532
2533 /** @todo: other chipset devices shall be registered too */
2534
2535 PDMDevHlpDBGFInfoRegister(pDevIns, "pci", "Display PCI bus status. Recognizes 'basic' or 'verbose' "
2536 "as arguments, defaults to 'basic'.", ich9pciInfo);
2537
2538 return VINF_SUCCESS;
2539}
2540
2541static void ich9pciResetDevice(PPCIDEVICE pDev)
2542{
2543 /* Clear regions */
2544 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
2545 {
2546 PCIIORegion* pRegion = &pDev->Int.s.aIORegions[iRegion];
2547 if (pRegion->size == 0)
2548 continue;
2549
2550 ich9pciUnmapRegion(pDev, iRegion);
2551 }
2552
2553 if (pciDevIsPassthrough(pDev))
2554 {
2555 // no reset handler - we can do what we need in PDM reset handler
2556 // @todo: is it correct?
2557 }
2558 else
2559 {
2560 PCIDevSetCommand(pDev,
2561 PCIDevGetCommand(pDev)
2562 &
2563 ~(VBOX_PCI_COMMAND_IO |
2564 VBOX_PCI_COMMAND_MEMORY |
2565 VBOX_PCI_COMMAND_MASTER));
2566
2567 /* Bridge device reset handlers processed later */
2568 if (!pciDevIsPci2PciBridge(pDev))
2569 {
2570 PCIDevSetByte(pDev, VBOX_PCI_CACHE_LINE_SIZE, 0x0);
2571 PCIDevSetInterruptLine(pDev, 0x0);
2572 }
2573 }
2574}
2575
2576
2577/**
2578 * @copydoc FNPDMDEVRESET
2579 */
2580static DECLCALLBACK(void) ich9pciReset(PPDMDEVINS pDevIns)
2581{
2582 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2583 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2584
2585 /* PCI-specific reset for each device. */
2586 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2587 {
2588 if (pBus->apDevices[i])
2589 ich9pciResetDevice(pBus->apDevices[i]);
2590 }
2591
2592 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2593 {
2594 if (pBus->papBridgesR3[iBridge])
2595 ich9pcibridgeReset(pBus->papBridgesR3[iBridge]->pDevIns);
2596 }
2597
2598 ich9pciFakePCIBIOS(pDevIns);
2599}
2600
2601static void ich9pciRelocateDevice(PPCIDEVICE pDev, RTGCINTPTR offDelta)
2602{
2603 if (pDev)
2604 {
2605 pDev->Int.s.pBusRC += offDelta;
2606 if (pDev->Int.s.pMsixPageRC)
2607 pDev->Int.s.pMsixPageRC += offDelta;
2608 }
2609}
2610
2611/**
2612 * @copydoc FNPDMDEVRELOCATE
2613 */
2614static DECLCALLBACK(void) ich9pciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2615{
2616 PICH9PCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PICH9PCIGLOBALS);
2617 PICH9PCIBUS pBus = &pGlobals->aPciBus;
2618 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2619
2620 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2621 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2622
2623 /* Relocate RC pointers for the attached pci devices. */
2624 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2625 ich9pciRelocateDevice(pBus->apDevices[i], offDelta);
2626
2627}
2628
2629/**
2630 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2631 */
2632static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
2633 int iInstance,
2634 PCFGMNODE pCfg)
2635{
2636 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2637
2638 /*
2639 * Validate and read configuration.
2640 */
2641 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
2642 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2643
2644 /* check if RC code is enabled. */
2645 bool fGCEnabled;
2646 int rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2647 if (RT_FAILURE(rc))
2648 return PDMDEV_SET_ERROR(pDevIns, rc,
2649 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2650
2651 /* check if R0 code is enabled. */
2652 bool fR0Enabled;
2653 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2654 if (RT_FAILURE(rc))
2655 return PDMDEV_SET_ERROR(pDevIns, rc,
2656 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2657 Log(("PCI: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
2658
2659 /*
2660 * Init data and register the PCI bus.
2661 */
2662 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2663 pBus->pDevInsR3 = pDevIns;
2664 pBus->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2665 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2666 pBus->papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pBus->apDevices));
2667
2668 PDMPCIBUSREG PciBusReg;
2669 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2670 PciBusReg.pfnRegisterR3 = ich9pcibridgeRegister;
2671 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
2672 PciBusReg.pfnIORegionRegisterR3 = ich9pciIORegionRegister;
2673 PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
2674 PciBusReg.pfnSetIrqR3 = ich9pcibridgeSetIrq;
2675 PciBusReg.pfnFakePCIBIOSR3 = NULL; /* Only needed for the first bus. */
2676 PciBusReg.pszSetIrqRC = fGCEnabled ? "ich9pcibridgeSetIrq" : NULL;
2677 PciBusReg.pszSetIrqR0 = fR0Enabled ? "ich9pcibridgeSetIrq" : NULL;
2678 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2679 if (RT_FAILURE(rc))
2680 return PDMDEV_SET_ERROR(pDevIns, rc,
2681 N_("Failed to register ourselves as a PCI Bus"));
2682 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2683 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2684 N_("PCI helper version mismatch; got %#x expected %#x"),
2685 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
2686
2687 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2688 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2689
2690 /* Disable default device locking. */
2691 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
2692 AssertRCReturn(rc, rc);
2693
2694 /*
2695 * Fill in PCI configs and add them to the bus.
2696 */
2697 PCIDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
2698 PCIDevSetDeviceId( &pBus->aPciDev, 0x2448); /* 82801 Mobile PCI bridge. */
2699 PCIDevSetRevisionId(&pBus->aPciDev, 0xf2);
2700 PCIDevSetClassSub( &pBus->aPciDev, 0x04); /* pci2pci */
2701 PCIDevSetClassBase( &pBus->aPciDev, 0x06); /* PCI_bridge */
2702 PCIDevSetClassProg( &pBus->aPciDev, 0x01); /* Supports subtractive decoding. */
2703 PCIDevSetHeaderType(&pBus->aPciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
2704 PCIDevSetCommand( &pBus->aPciDev, 0x00);
2705 PCIDevSetStatus( &pBus->aPciDev, 0x20); /* 66MHz Capable. */
2706 PCIDevSetInterruptLine(&pBus->aPciDev, 0x00); /* This device does not assert interrupts. */
2707
2708 /*
2709 * This device does not generate interrupts. Interrupt delivery from
2710 * devices attached to the bus is unaffected.
2711 */
2712 PCIDevSetInterruptPin (&pBus->aPciDev, 0x00);
2713
2714 pBus->aPciDev.pDevIns = pDevIns;
2715
2716 /* Bridge-specific data */
2717 pciDevSetPci2PciBridge(&pBus->aPciDev);
2718 pBus->aPciDev.Int.s.pfnBridgeConfigRead = ich9pcibridgeConfigRead;
2719 pBus->aPciDev.Int.s.pfnBridgeConfigWrite = ich9pcibridgeConfigWrite;
2720
2721 /*
2722 * Register this PCI bridge. The called function will take care on which bus we will get registered.
2723 */
2724 rc = PDMDevHlpPCIRegister (pDevIns, &pBus->aPciDev);
2725 if (RT_FAILURE(rc))
2726 return rc;
2727
2728 /*
2729 * The iBus property doesn't really represent the bus number
2730 * because the guest and the BIOS can choose different bus numbers
2731 * for them.
2732 * The bus number is mainly for the setIrq function to indicate
2733 * when the host bus is reached which will have iBus = 0.
2734 * That's why the + 1.
2735 */
2736 pBus->iBus = iInstance + 1;
2737
2738 /*
2739 * Register SSM handlers. We use the same saved state version as for the host bridge
2740 * to make changes easier.
2741 */
2742 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION_CURRENT,
2743 sizeof(*pBus) + 16*128,
2744 "pgm" /* before */,
2745 NULL, NULL, NULL,
2746 NULL, ich9pcibridgeR3SaveExec, NULL,
2747 NULL, ich9pcibridgeR3LoadExec, NULL);
2748 if (RT_FAILURE(rc))
2749 return rc;
2750
2751
2752 return VINF_SUCCESS;
2753}
2754
2755/**
2756 * @copydoc FNPDMDEVRESET
2757 */
2758static void ich9pcibridgeReset(PPDMDEVINS pDevIns)
2759{
2760 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2761
2762 /* Reset config space to default values. */
2763 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_PRIMARY_BUS, 0);
2764 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_SECONDARY_BUS, 0);
2765 PCIDevSetByte(&pBus->aPciDev, VBOX_PCI_SUBORDINATE_BUS, 0);
2766
2767 /* PCI-specific reset for each device. */
2768 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2769 {
2770 if (pBus->apDevices[i])
2771 ich9pciResetDevice(pBus->apDevices[i]);
2772 }
2773}
2774
2775
2776/**
2777 * @copydoc FNPDMDEVRELOCATE
2778 */
2779static DECLCALLBACK(void) ich9pcibridgeRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2780{
2781 PICH9PCIBUS pBus = PDMINS_2_DATA(pDevIns, PICH9PCIBUS);
2782 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2783
2784 /* Relocate RC pointers for the attached pci devices. */
2785 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
2786 ich9pciRelocateDevice(pBus->apDevices[i], offDelta);
2787}
2788
2789/**
2790 * The PCI bus device registration structure.
2791 */
2792const PDMDEVREG g_DevicePciIch9 =
2793{
2794 /* u32Version */
2795 PDM_DEVREG_VERSION,
2796 /* szName */
2797 "ich9pci",
2798 /* szRCMod */
2799 "VBoxDDGC.gc",
2800 /* szR0Mod */
2801 "VBoxDDR0.r0",
2802 /* pszDescription */
2803 "ICH9 PCI bridge",
2804 /* fFlags */
2805 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2806 /* fClass */
2807 PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
2808 /* cMaxInstances */
2809 1,
2810 /* cbInstance */
2811 sizeof(ICH9PCIGLOBALS),
2812 /* pfnConstruct */
2813 ich9pciConstruct,
2814 /* pfnDestruct */
2815 NULL,
2816 /* pfnRelocate */
2817 ich9pciRelocate,
2818 /* pfnIOCtl */
2819 NULL,
2820 /* pfnPowerOn */
2821 NULL,
2822 /* pfnReset */
2823 ich9pciReset,
2824 /* pfnSuspend */
2825 NULL,
2826 /* pfnResume */
2827 NULL,
2828 /* pfnAttach */
2829 NULL,
2830 /* pfnDetach */
2831 NULL,
2832 /* pfnQueryInterface */
2833 NULL,
2834 /* pfnInitComplete */
2835 NULL,
2836 /* pfnPowerOff */
2837 NULL,
2838 /* pfnSoftReset */
2839 NULL,
2840 /* u32VersionEnd */
2841 PDM_DEVREG_VERSION
2842};
2843
2844/**
2845 * The device registration structure
2846 * for the PCI-to-PCI bridge.
2847 */
2848const PDMDEVREG g_DevicePciIch9Bridge =
2849{
2850 /* u32Version */
2851 PDM_DEVREG_VERSION,
2852 /* szName */
2853 "ich9pcibridge",
2854 /* szRCMod */
2855 "VBoxDDGC.gc",
2856 /* szR0Mod */
2857 "VBoxDDR0.r0",
2858 /* pszDescription */
2859 "ICH9 PCI to PCI bridge",
2860 /* fFlags */
2861 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2862 /* fClass */
2863 PDM_DEVREG_CLASS_BUS_PCI,
2864 /* cMaxInstances */
2865 ~0U,
2866 /* cbInstance */
2867 sizeof(ICH9PCIBUS),
2868 /* pfnConstruct */
2869 ich9pcibridgeConstruct,
2870 /* pfnDestruct */
2871 NULL,
2872 /* pfnRelocate */
2873 ich9pcibridgeRelocate,
2874 /* pfnIOCtl */
2875 NULL,
2876 /* pfnPowerOn */
2877 NULL,
2878 /* pfnReset */
2879 NULL, /* Must be NULL, to make sure only bus driver handles reset */
2880 /* pfnSuspend */
2881 NULL,
2882 /* pfnResume */
2883 NULL,
2884 /* pfnAttach */
2885 NULL,
2886 /* pfnDetach */
2887 NULL,
2888 /* pfnQueryInterface */
2889 NULL,
2890 /* pfnInitComplete */
2891 NULL,
2892 /* pfnPowerOff */
2893 NULL,
2894 /* pfnSoftReset */
2895 NULL,
2896 /* u32VersionEnd */
2897 PDM_DEVREG_VERSION
2898};
2899
2900#endif /* IN_RING3 */
2901#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