VirtualBox

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

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

PCI: BIOS init, rework

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 61.0 KB
Line 
1/* $Id: DevPciIch9.cpp 32280 2010-09-07 12:01:17Z vboxsync $ */
2/** @file
3 * DevPCI - ICH9 southbridge PCI bus emulation Device.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19 * Header Files *
20 *******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DEV_PCI
22/* Hack to get PCIDEVICEINT declare at the right point - include "PCIInternal.h". */
23#define PCI_INCLUDE_PRIVATE
24#include <VBox/pci.h>
25#include <VBox/pdmdev.h>
26#include <iprt/asm.h>
27#include <iprt/assert.h>
28#include <iprt/string.h>
29
30#include "../Builtins.h"
31
32/**
33 * PCI Bus instance.
34 */
35typedef struct PCIBus
36{
37 /** Bus number. */
38 int32_t iBus;
39 /** Number of bridges attached to the bus. */
40 uint32_t cBridges;
41
42 /** Array of PCI devices. We assume 32 slots, each with 8 functions. */
43 R3PTRTYPE(PPCIDEVICE) apDevices[256];
44 /** Array of bridges attached to the bus. */
45 R3PTRTYPE(PPCIDEVICE *) papBridgesR3;
46
47 /** R3 pointer to the device instance. */
48 PPDMDEVINSR3 pDevInsR3;
49 /** Pointer to the PCI R3 helpers. */
50 PCPDMPCIHLPR3 pPciHlpR3;
51
52 /** R0 pointer to the device instance. */
53 PPDMDEVINSR0 pDevInsR0;
54 /** Pointer to the PCI R0 helpers. */
55 PCPDMPCIHLPR0 pPciHlpR0;
56
57 /** RC pointer to the device instance. */
58 PPDMDEVINSRC pDevInsRC;
59 /** Pointer to the PCI RC helpers. */
60 PCPDMPCIHLPRC pPciHlpRC;
61
62 /** The PCI device for the PCI bridge. */
63 PCIDEVICE aPciDev;
64
65} PCIBUS, *PPCIBUS;
66
67
68/** @def PCI_IRQ_PINS
69 * Number of pins for interrupts (PIRQ#0...PIRQ#3)
70 */
71#define PCI_IRQ_PINS 4
72
73/** @def PCI_APIC_IRQ_PINS
74 * Number of pins for interrupts if the APIC is used.
75 */
76#define PCI_APIC_IRQ_PINS 8
77
78/**
79 * PCI Globals - This is the host-to-pci bridge and the root bus.
80 */
81typedef struct
82{
83 /** R3 pointer to the device instance. */
84 PPDMDEVINSR3 pDevInsR3;
85 /** R0 pointer to the device instance. */
86 PPDMDEVINSR0 pDevInsR0;
87 /** RC pointer to the device instance. */
88 PPDMDEVINSRC pDevInsRC;
89
90#if HC_ARCH_BITS == 64
91 uint32_t Alignment0;
92#endif
93
94 /** I/O APIC irq levels */
95 volatile uint32_t uaPciApicIrqLevels[PCI_APIC_IRQ_PINS];
96
97#if 1 /* Will be moved into the BIOS soon. */
98 /** The next I/O port address which the PCI BIOS will use. */
99 uint32_t uPciBiosIo;
100 /** The next MMIO address which the PCI BIOS will use. */
101 uint32_t uPciBiosMmio;
102 /** Actual bus number. */
103 uint8_t uBus;
104#endif
105
106
107 /** Config register. */
108 uint32_t uConfigReg;
109
110 /** PCI bus which is attached to the host-to-PCI bridge. */
111 PCIBUS aPciBus;
112
113} PCIGLOBALS, *PPCIGLOBALS;
114
115
116/*******************************************************************************
117 * Defined Constants And Macros *
118 *******************************************************************************/
119
120/** @def VBOX_ICH9PCI_SAVED_STATE_VERSION
121 * Saved state version of the ICH9 PCI bus device.
122 */
123#define VBOX_ICH9PCI_SAVED_STATE_VERSION 1
124
125/** Converts a bus instance pointer to a device instance pointer. */
126#define PCIBUS_2_DEVINS(pPciBus) ((pPciBus)->CTX_SUFF(pDevIns))
127/** Converts a device instance pointer to a PCIGLOBALS pointer. */
128#define DEVINS_2_PCIGLOBALS(pDevIns) ((PPCIGLOBALS)(PDMINS_2_DATA(pDevIns, PPCIGLOBALS)))
129/** Converts a device instance pointer to a PCIBUS pointer. */
130#define DEVINS_2_PCIBUS(pDevIns) ((PPCIBUS)(&PDMINS_2_DATA(pDevIns, PPCIGLOBALS)->aPciBus))
131/** Converts a pointer to a PCI root bus instance to a PCIGLOBALS pointer.
132 */
133#define PCIROOTBUS_2_PCIGLOBALS(pPciBus) ( (PPCIGLOBALS)((uintptr_t)(pPciBus) - RT_OFFSETOF(PCIGLOBALS, aPciBus)) )
134
135
136/** @def PCI_LOCK
137 * Acquires the PDM lock. This is a NOP if locking is disabled. */
138/** @def PCI_UNLOCK
139 * Releases the PDM lock. This is a NOP if locking is disabled. */
140#define PCI_LOCK(pDevIns, rc) \
141 do { \
142 int rc2 = DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnLock((pDevIns), rc); \
143 if (rc2 != VINF_SUCCESS) \
144 return rc2; \
145 } while (0)
146#define PCI_UNLOCK(pDevIns) \
147 DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnUnlock(pDevIns)
148
149#ifndef VBOX_DEVICE_STRUCT_TESTCASE
150
151RT_C_DECLS_BEGIN
152
153PDMBOTHCBDECL(void) ich9pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel);
154PDMBOTHCBDECL(void) ich9pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel);
155PDMBOTHCBDECL(int) ich9pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
156PDMBOTHCBDECL(int) ich9pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
157PDMBOTHCBDECL(int) ich9pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
158PDMBOTHCBDECL(int) ich9pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
159
160RT_C_DECLS_END
161
162/* Prototypes */
163static void ich9pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev, int iIrq, int iLevel);
164#ifdef IN_RING3
165static int ich9pciRegisterInternal(PPCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName);
166static void ich9pciUpdateMappings(PCIDevice *d);
167static DECLCALLBACK(uint32_t) ich9pciConfigRead(PCIDevice *aDev, uint32_t u32Address, unsigned len);
168DECLINLINE(PPCIDEVICE) ich9pciFindBridge(PPCIBUS pBus, uint8_t iBus);
169static void ich9pciBiosInitDevice(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint8_t cBridgeDepth, uint8_t *paBridgePositions);
170#endif
171
172PDMBOTHCBDECL(void) ich9pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel)
173{
174 ich9pciSetIrqInternal(PDMINS_2_DATA(pDevIns, PPCIGLOBALS), pPciDev->devfn, pPciDev, iIrq, iLevel);
175}
176
177PDMBOTHCBDECL(void) ich9pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel)
178{
179 /*
180 * The PCI-to-PCI bridge specification defines how the interrupt pins
181 * are routed from the secondary to the primary bus (see chapter 9).
182 * iIrq gives the interrupt pin the pci device asserted.
183 * We change iIrq here according to the spec and call the SetIrq function
184 * of our parent passing the device which asserted the interrupt instead of the device of the bridge.
185 */
186 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
187 PPCIDEVICE pPciDevBus = pPciDev;
188 int iIrqPinBridge = iIrq;
189 uint8_t uDevFnBridge = 0;
190
191 /* Walk the chain until we reach the host bus. */
192 do
193 {
194 uDevFnBridge = pBus->aPciDev.devfn;
195 iIrqPinBridge = ((pPciDevBus->devfn >> 3) + iIrqPinBridge) & 3;
196
197 /* Get the parent. */
198 pBus = pBus->aPciDev.Int.s.CTX_SUFF(pBus);
199 pPciDevBus = &pBus->aPciDev;
200 } while (pBus->iBus != 0);
201
202 AssertMsgReturnVoid(pBus->iBus == 0, ("This is not the host pci bus iBus=%d\n", pBus->iBus));
203 ich9pciSetIrqInternal(PCIROOTBUS_2_PCIGLOBALS(pBus), uDevFnBridge, pPciDev, iIrqPinBridge, iLevel);
204}
205
206/**
207 * Port I/O Handler for PCI address OUT operations.
208 *
209 * @returns VBox status code.
210 *
211 * @param pDevIns The device instance.
212 * @param pvUser User argument - ignored.
213 * @param uPort Port number used for the OUT operation.
214 * @param u32 The value to output.
215 * @param cb The value size in bytes.
216 */
217PDMBOTHCBDECL(int) ich9pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
218{
219 Log(("ich9pciIOPortAddressWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
220 NOREF(pvUser);
221 if (cb == 4)
222 {
223 PPCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
224 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_WRITE);
225 pThis->uConfigReg = u32 & ~3; /* Bits 0-1 are reserved and we silently clear them */
226 PCI_UNLOCK(pDevIns);
227 }
228 return VINF_SUCCESS;
229}
230
231/**
232 * Port I/O Handler for PCI address IN operations.
233 *
234 * @returns VBox status code.
235 *
236 * @param pDevIns The device instance.
237 * @param pvUser User argument - ignored.
238 * @param uPort Port number used for the IN operation.
239 * @param pu32 Where to store the result.
240 * @param cb Number of bytes read.
241 */
242PDMBOTHCBDECL(int) ich9pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
243{
244 NOREF(pvUser);
245 if (cb == 4)
246 {
247 PPCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
248 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_READ);
249 *pu32 = pThis->uConfigReg;
250 PCI_UNLOCK(pDevIns);
251 Log(("pciIOPortAddressRead: Port=%#x cb=%d -> %#x\n", Port, cb, *pu32));
252 return VINF_SUCCESS;
253 }
254
255 Log(("ich9pciIOPortAddressRead: Port=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", Port, cb));
256
257 return VERR_IOM_IOPORT_UNUSED;
258}
259
260static int ich9pciDataWrite(PPCIGLOBALS pGlobals, uint32_t addr, uint32_t val, int len)
261{
262 uint8_t iBus, iDevice;
263 uint32_t uConfigReg;
264
265 Log(("ich9pciDataWrite: addr=%08x val=%08x len=%d\n", pGlobals->uConfigReg, val, len));
266
267 if (!(pGlobals->uConfigReg & (1 << 31)))
268 return VINF_SUCCESS;
269
270 if ((pGlobals->uConfigReg & 0x3) != 0)
271 return VINF_SUCCESS;
272
273 /* Compute destination device */
274 iBus = (pGlobals->uConfigReg >> 16) & 0xff;
275 iDevice = (pGlobals->uConfigReg >> 8) & 0xff;
276 /* And config register */
277 uConfigReg = (pGlobals->uConfigReg & 0xfc) | (addr & 3);
278 if (iBus != 0)
279 {
280 if (pGlobals->aPciBus.cBridges)
281 {
282#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
283 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(&pGlobals->aPciBus, iBus);
284 if (pBridgeDevice)
285 {
286 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
287 pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, uConfigReg, val, len);
288 }
289#else
290 return VINF_IOM_HC_IOPORT_WRITE;
291#endif
292 }
293 }
294 else
295 {
296 if (pGlobals->aPciBus.apDevices[iDevice])
297 {
298#ifdef IN_RING3
299 R3PTRTYPE(PCIDevice *) aDev = pGlobals->aPciBus.apDevices[iDevice];
300 Log(("ich9pciConfigWrite: %s: addr=%02x val=%08x len=%d\n", aDev->name, uConfigReg, val, len));
301 aDev->Int.s.pfnConfigWrite(aDev, uConfigReg, val, len);
302#else
303 return VINF_IOM_HC_IOPORT_WRITE;
304#endif
305 }
306 }
307 return VINF_SUCCESS;
308}
309
310/**
311 * Port I/O Handler for PCI data OUT operations.
312 *
313 * @returns VBox status code.
314 *
315 * @param pDevIns The device instance.
316 * @param pvUser User argument - ignored.
317 * @param uPort Port number used for the OUT operation.
318 * @param u32 The value to output.
319 * @param cb The value size in bytes.
320 */
321PDMBOTHCBDECL(int) ich9pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
322{
323 Log(("pciIOPortDataWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
324 NOREF(pvUser);
325 int rc = VINF_SUCCESS;
326 if (!(Port % cb))
327 {
328 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_WRITE);
329 rc = ich9pciDataWrite(PDMINS_2_DATA(pDevIns, PPCIGLOBALS), Port, u32, cb);
330 PCI_UNLOCK(pDevIns);
331 }
332 else
333 AssertMsgFailed(("Unaligned write to port %#x u32=%#x cb=%d\n", Port, u32, cb));
334 return rc;
335}
336
337static int ich9pciDataRead(PPCIGLOBALS pGlobals, uint32_t addr, int len, uint32_t *pu32)
338{
339 uint8_t iBus, iDevice;
340 uint32_t uConfigReg;
341
342 *pu32 = 0xffffffff;
343
344 if (!(pGlobals->uConfigReg & (1 << 31)))
345 return VINF_SUCCESS;
346
347 if ((pGlobals->uConfigReg & 0x3) != 0)
348 return VINF_SUCCESS;
349
350 /* Compute destination device */
351 iBus = (pGlobals->uConfigReg >> 16) & 0xff;
352 iDevice = (pGlobals->uConfigReg >> 8) & 0xff;
353 /* And config register */
354 uConfigReg = (pGlobals->uConfigReg & 0xfc) | (addr & 3);
355 if (iBus != 0)
356 {
357 if (pGlobals->aPciBus.cBridges)
358 {
359#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
360 PPCIDEVICE pBridgeDevice = ich9pciFindBridge(&pGlobals->aPciBus, iBus);
361 if (pBridgeDevice)
362 {
363 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
364 *pu32 = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, uConfigReg, len);
365 }
366#else
367 return VINF_IOM_HC_IOPORT_READ;
368#endif
369 }
370 }
371 else
372 {
373 if (pGlobals->aPciBus.apDevices[iDevice])
374 {
375#ifdef IN_RING3
376 R3PTRTYPE(PCIDevice *) aDev = pGlobals->aPciBus.apDevices[iDevice];
377 *pu32 = aDev->Int.s.pfnConfigRead(aDev, uConfigReg, len);
378 Log(("ich9pciConfigRead: %s: addr=%02x val=%08x len=%d\n", aDev->name, uConfigReg, *pu32, len));
379#else
380 return VINF_IOM_HC_IOPORT_READ;
381#endif
382 }
383 }
384
385 return VINF_SUCCESS;
386}
387
388/**
389 * Port I/O Handler for PCI data IN operations.
390 *
391 * @returns VBox status code.
392 *
393 * @param pDevIns The device instance.
394 * @param pvUser User argument - ignored.
395 * @param uPort Port number used for the IN operation.
396 * @param pu32 Where to store the result.
397 * @param cb Number of bytes read.
398 */
399PDMBOTHCBDECL(int) ich9pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
400{
401 NOREF(pvUser);
402 if (!(Port % cb))
403 {
404 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_READ);
405 int rc = ich9pciDataRead(PDMINS_2_DATA(pDevIns, PPCIGLOBALS), Port, cb, pu32);
406 PCI_UNLOCK(pDevIns);
407 Log(("pciIOPortDataRead: Port=%#x cb=%#x -> %#x (%Rrc)\n", Port, cb, *pu32, rc));
408 return rc;
409 }
410 AssertMsgFailed(("Unaligned read from port %#x cb=%d\n", Port, cb));
411 return VERR_IOM_IOPORT_UNUSED;
412}
413
414/* Compute mapping of PCI slot and IRQ number to APIC interrupt line */
415static inline int ich9pciSlot2ApicIrq(uint8_t uSlot, int irq_num)
416{
417 return (irq_num + uSlot) & 7;
418}
419
420/* Add one more level up request on APIC input line */
421static inline void ich9pciApicLevelUp(PPCIGLOBALS pGlobals, int irq_num)
422{
423 ASMAtomicIncU32(&pGlobals->uaPciApicIrqLevels[irq_num]);
424}
425
426/* Remove one level up request on APIC input line */
427static inline void ich9pciApicLevelDown(PPCIGLOBALS pGlobals, int irq_num)
428{
429 ASMAtomicDecU32(&pGlobals->uaPciApicIrqLevels[irq_num]);
430}
431
432static void ich9pciApicSetIrq(PPCIBUS pBus, uint8_t uDevFn, PCIDevice *pPciDev, int irq_num1, int iLevel, int iForcedIrq)
433{
434 /* This is only allowed to be called with a pointer to the root bus. */
435 AssertMsg(pBus->iBus == 0, ("iBus=%u\n", pBus->iBus));
436
437 if (iForcedIrq == -1)
438 {
439 int apic_irq, apic_level;
440 PPCIGLOBALS pGlobals = PCIROOTBUS_2_PCIGLOBALS(pBus);
441 int irq_num = ich9pciSlot2ApicIrq(uDevFn >> 3, irq_num1);
442
443 if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_HIGH)
444 ich9pciApicLevelUp(pGlobals, irq_num);
445 else if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_LOW)
446 ich9pciApicLevelDown(pGlobals, irq_num);
447
448 apic_irq = irq_num + 0x10;
449 apic_level = pGlobals->uaPciApicIrqLevels[irq_num] != 0;
450 Log3(("ich9pciApicSetIrq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d\n",
451 R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num));
452 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level);
453
454 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
455 {
456 /**
457 * we raised it few lines above, as PDM_IRQ_LEVEL_FLIP_FLOP has
458 * PDM_IRQ_LEVEL_HIGH bit set
459 */
460 ich9pciApicLevelDown(pGlobals, irq_num);
461 pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
462 apic_level = pGlobals->uaPciApicIrqLevels[irq_num] != 0;
463 Log3(("ich9pciApicSetIrq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d (flop)\n",
464 R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num));
465 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level);
466 }
467 } else {
468 Log3(("ich9pciApicSetIrq: %s: irq_num1=%d level=%d acpi_irq=%d\n",
469 R3STRING(pPciDev->name), irq_num1, iLevel, iForcedIrq));
470 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), iForcedIrq, iLevel);
471 }
472}
473
474static void ich9pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev, int iIrq, int iLevel)
475{
476 PPCIBUS pBus = &pGlobals->aPciBus;
477 const bool fIsAcpiDevice = PCIDevGetDeviceId(pPciDev) == 0x7113;
478
479 /* Check if the state changed. */
480 if (pPciDev->Int.s.uIrqPinState != iLevel)
481 {
482 pPciDev->Int.s.uIrqPinState = (iLevel & PDM_IRQ_LEVEL_HIGH);
483
484 /* Send interrupt to I/O APIC only now. */
485 if (fIsAcpiDevice)
486 /*
487 * ACPI needs special treatment since SCI is hardwired and
488 * should not be affected by PCI IRQ routing tables at the
489 * same time SCI IRQ is shared in PCI sense hence this
490 * kludge (i.e. we fetch the hardwired value from ACPIs
491 * PCI device configuration space).
492 */
493 ich9pciApicSetIrq(pBus, uDevFn, pPciDev, -1, iLevel, PCIDevGetInterruptLine(pPciDev));
494 else
495 ich9pciApicSetIrq(pBus, uDevFn, pPciDev, iIrq, iLevel, -1);
496 }
497}
498
499#ifdef IN_RING3
500DECLINLINE(PPCIDEVICE) ich9pciFindBridge(PPCIBUS pBus, uint8_t iBus)
501{
502 /* Search for a fitting bridge. */
503 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
504 {
505 /*
506 * Examine secondary and subordinate bus number.
507 * If the target bus is in the range we pass the request on to the bridge.
508 */
509 PPCIDEVICE pBridgeTemp = pBus->papBridgesR3[iBridge];
510 AssertMsg(pBridgeTemp && pBridgeTemp->Int.s.fPciToPciBridge,
511 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
512
513 if ( iBus >= pBridgeTemp->config[VBOX_PCI_SECONDARY_BUS]
514 && iBus <= pBridgeTemp->config[VBOX_PCI_SUBORDINATE_BUS])
515 return pBridgeTemp;
516 }
517
518 /* Nothing found. */
519 return NULL;
520}
521
522static inline uint32_t ich9pciGetRegionReg(int iRegion)
523{
524 return (iRegion == PCI_ROM_SLOT) ?
525 VBOX_PCI_ROM_ADDRESS : (VBOX_PCI_BASE_ADDRESS_0 + iRegion * 4);
526}
527
528#define INVALID_PCI_ADDRESS ~0U
529
530static void ich9pciUpdateMappings(PCIDevice* pDev)
531{
532 PPCIBUS pBus = pDev->Int.s.CTX_SUFF(pBus);
533 uint32_t uLast, uNew;
534
535 int iCmd = PCIDevGetCommand(pDev);
536 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
537 {
538 PCIIORegion* pRegion = &pDev->Int.s.aIORegions[iRegion];
539 uint32_t uConfigReg = ich9pciGetRegionReg(iRegion);
540 int32_t iRegionSize = pRegion->size;
541 int rc;
542
543 if (iRegionSize == 0)
544 continue;
545
546 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
547 {
548 /* port IO region */
549 if (iCmd & PCI_COMMAND_IOACCESS)
550 {
551 /* IO access allowed */
552 uNew = ich9pciConfigRead(pDev, uConfigReg, 4);
553 uNew &= ~(iRegionSize - 1);
554 uLast = uNew + iRegionSize - 1;
555 /* only 64K ioports on PC */
556 if (uLast <= uNew || uNew == 0 || uLast >= 0x10000)
557 uNew = INVALID_PCI_ADDRESS;
558 } else
559 uNew = INVALID_PCI_ADDRESS;
560 }
561 else
562 {
563 /* MMIO region */
564 if (iCmd & PCI_COMMAND_MEMACCESS)
565 {
566 uNew = ich9pciConfigRead(pDev, uConfigReg, 4);
567 /* the ROM slot has a specific enable bit */
568 if (iRegion == PCI_ROM_SLOT && !(uNew & 1))
569 uNew = INVALID_PCI_ADDRESS;
570 else
571 {
572 uNew &= ~(iRegionSize - 1);
573 uLast = uNew + iRegionSize - 1;
574 /* NOTE: we do not support wrapping */
575 /* XXX: as we cannot support really dynamic
576 mappings, we handle specific values as invalid
577 mappings. */
578 if (uLast <= uNew || uNew == 0 || uLast == ~0U)
579 uNew = INVALID_PCI_ADDRESS;
580 }
581 } else
582 uNew = INVALID_PCI_ADDRESS;
583 }
584 /* now do the real mapping */
585 if (uNew != pRegion->addr)
586 {
587 if (pRegion->addr != INVALID_PCI_ADDRESS)
588 {
589 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
590 {
591 /* Port IO */
592 int devclass;
593 /* NOTE: specific hack for IDE in PC case:
594 only one byte must be mapped. */
595 /// @todo: do we need it?
596 devclass = pDev->config[0x0a] | (pDev->config[0x0b] << 8);
597 if (devclass == 0x0101 && iRegionSize == 4)
598 {
599 rc = PDMDevHlpIOPortDeregister(pDev->pDevIns, pRegion->addr + 2, 1);
600 AssertRC(rc);
601 }
602 else
603 {
604 rc = PDMDevHlpIOPortDeregister(pDev->pDevIns, pRegion->addr, pRegion->size);
605 AssertRC(rc);
606 }
607 }
608 else
609 {
610 RTGCPHYS GCPhysBase = pRegion->addr;
611 if (pBus->pPciHlpR3->pfnIsMMIO2Base(pBus->pDevInsR3, pDev->pDevIns, GCPhysBase))
612 {
613 /* unmap it. */
614 rc = pRegion->map_func(pDev, iRegion, NIL_RTGCPHYS, pRegion->size, (PCIADDRESSSPACE)(pRegion->type));
615 AssertRC(rc);
616 rc = PDMDevHlpMMIO2Unmap(pDev->pDevIns, iRegion, GCPhysBase);
617 }
618 else
619 rc = PDMDevHlpMMIODeregister(pDev->pDevIns, GCPhysBase, pRegion->size);
620 AssertMsgRC(rc, ("rc=%Rrc d=%s i=%d GCPhysBase=%RGp size=%#x\n", rc, pDev->name, iRegion, GCPhysBase, pRegion->size));
621 }
622 }
623 pRegion->addr = uNew;
624 if (pRegion->addr != INVALID_PCI_ADDRESS)
625 {
626 /* finally, map the region */
627 rc = pRegion->map_func(pDev, iRegion,
628 pRegion->addr, pRegion->size,
629 (PCIADDRESSSPACE)(pRegion->type));
630 AssertRC(rc);
631 }
632 }
633 }
634}
635
636static DECLCALLBACK(int) ich9pciRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
637{
638 PPCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
639
640 /*
641 * Check input.
642 */
643 if ( !pszName
644 || !pPciDev
645 || iDev >= (int)RT_ELEMENTS(pBus->apDevices)
646 )
647 {
648 AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
649 return VERR_INVALID_PARAMETER;
650 }
651
652 /*
653 * Register the device.
654 */
655 return ich9pciRegisterInternal(pBus, iDev, pPciDev, pszName);
656}
657
658static DECLCALLBACK(int) ich9pcibridgeRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
659{
660 return 0;
661}
662
663static DECLCALLBACK(int) ich9pciIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, uint32_t cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
664{
665 /*
666 * Validate.
667 */
668 AssertMsgReturn( enmType == PCI_ADDRESS_SPACE_MEM
669 || enmType == PCI_ADDRESS_SPACE_IO
670 || enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH,
671 ("Invalid enmType=%#x? Or was this a bitmask after all...\n", enmType),
672 VERR_INVALID_PARAMETER);
673 AssertMsgReturn((unsigned)iRegion < PCI_NUM_REGIONS,
674 ("Invalid iRegion=%d PCI_NUM_REGIONS=%d\n", iRegion, PCI_NUM_REGIONS),
675 VERR_INVALID_PARAMETER);
676 int iLastSet = ASMBitLastSetU32(cbRegion);
677 AssertMsgReturn( iLastSet != 0
678 && RT_BIT_32(iLastSet - 1) == cbRegion,
679 ("Invalid cbRegion=%#x iLastSet=%#x (not a power of 2 or 0)\n", cbRegion, iLastSet),
680 VERR_INVALID_PARAMETER);
681
682 /*
683 * Register the I/O region.
684 */
685 PPCIIOREGION pRegion = &pPciDev->Int.s.aIORegions[iRegion];
686 pRegion->addr = ~0U;
687 pRegion->size = cbRegion;
688 pRegion->type = enmType;
689 pRegion->map_func = pfnCallback;
690
691 /* Set type in the config space. */
692 uint32_t u32Address = ich9pciGetRegionReg(iRegion);
693 uint32_t u32Value = (enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH ? (1 << 3) : 0)
694 | (enmType == PCI_ADDRESS_SPACE_IO ? 1 : 0);
695 *(uint32_t *)(pPciDev->config + u32Address) = RT_H2LE_U32(u32Value);
696
697 return VINF_SUCCESS;
698}
699
700static DECLCALLBACK(void) ich9pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
701 PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
702{
703 if (ppfnReadOld)
704 *ppfnReadOld = pPciDev->Int.s.pfnConfigRead;
705 pPciDev->Int.s.pfnConfigRead = pfnRead;
706
707 if (ppfnWriteOld)
708 *ppfnWriteOld = pPciDev->Int.s.pfnConfigWrite;
709 pPciDev->Int.s.pfnConfigWrite = pfnWrite;
710}
711
712/**
713 * Saves a state of the PCI device.
714 *
715 * @returns VBox status code.
716 * @param pDevIns Device instance of the PCI Bus.
717 * @param pPciDev Pointer to PCI device.
718 * @param pSSM The handle to save the state to.
719 */
720static DECLCALLBACK(int) pciGenericSaveExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSM)
721{
722 return SSMR3PutMem(pSSM, &pPciDev->config[0], sizeof(pPciDev->config));
723}
724
725static int pciR3CommonSaveExec(PPCIBUS pBus, PSSMHANDLE pSSM)
726{
727 /*
728 * Iterate thru all the devices.
729 */
730 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
731 {
732 PPCIDEVICE pDev = pBus->apDevices[i];
733 if (pDev)
734 {
735 SSMR3PutU32(pSSM, i);
736 SSMR3PutMem(pSSM, pDev->config, sizeof(pDev->config));
737
738 int rc = SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
739 if (RT_FAILURE(rc))
740 return rc;
741 }
742 }
743 return SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
744}
745
746static DECLCALLBACK(int) pciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
747{
748 PPCIBUS pThis = PDMINS_2_DATA(pDevIns, PPCIBUS);
749 return pciR3CommonSaveExec(pThis, pSSM);
750}
751
752
753static DECLCALLBACK(int) pcibridgeR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
754{
755 PPCIBUS pThis = PDMINS_2_DATA(pDevIns, PPCIBUS);
756 return pciR3CommonSaveExec(pThis, pSSM);
757}
758
759static DECLCALLBACK(int) pciR3CommonLoadExec(PPCIBUS pBus, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
760{
761 return 0;
762}
763
764/**
765 * Loads a saved PCI device state.
766 *
767 * @returns VBox status code.
768 * @param pDevIns Device instance of the PCI Bus.
769 * @param pPciDev Pointer to PCI device.
770 * @param pSSM The handle to the saved state.
771 */
772static DECLCALLBACK(int) pciGenericLoadExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSM)
773{
774 return SSMR3GetMem(pSSM, &pPciDev->config[0], sizeof(pPciDev->config));
775}
776
777static DECLCALLBACK(int) pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
778{
779 PPCIBUS pThis = PDMINS_2_DATA(pDevIns, PPCIBUS);
780 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION)
781 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
782 return pciR3CommonLoadExec(pThis, pSSM, uVersion, uPass);
783}
784
785static DECLCALLBACK(int) pcibridgeR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
786{
787 PPCIBUS pThis = PDMINS_2_DATA(pDevIns, PPCIBUS);
788 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION)
789 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
790 return pciR3CommonLoadExec(pThis, pSSM, uVersion, uPass);
791}
792
793static uint32_t ich9pciConfigRead(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t len)
794{
795 /* Set destination address */
796 /// @todo: device locking?
797 pGlobals->uConfigReg = 0x80000000 | (uBus << 16) |
798 (uDevFn << 8) | (addr & ~3);
799 uint32_t u32Val;
800 int rc = ich9pciDataRead(pGlobals, addr & 3, len, &u32Val);
801 AssertRC(rc);
802 return u32Val;
803}
804
805static void ich9pciConfigWrite(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t val, uint32_t len)
806{
807 /* Set destination address */
808 /// @todo: device locking?
809 pGlobals->uConfigReg = 0x80000000 | (uBus << 16) |
810 (uDevFn << 8) | addr;
811 ich9pciDataWrite(pGlobals, 0, val, len);
812}
813
814static void ich9pciSetRegionAddress(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, int iRegion, uint32_t addr)
815{
816 uint32_t uReg = ich9pciGetRegionReg(iRegion);
817
818 /* Read memory type first. */
819 uint8_t uResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, uReg, 1);
820 /* Read command register. */
821 uint16_t uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 2);
822
823 if ( iRegion == PCI_ROM_SLOT )
824 uCmd |= PCI_COMMAND_MEMACCESS;
825 else if ((uResourceType & PCI_ADDRESS_SPACE_IO) == PCI_ADDRESS_SPACE_IO)
826 uCmd |= PCI_COMMAND_IOACCESS; /* Enable I/O space access. */
827 else /* The region is MMIO. */
828 uCmd |= PCI_COMMAND_MEMACCESS; /* Enable MMIO access. */
829
830 /* Write address of the device. */
831 ich9pciConfigWrite(pGlobals, uBus, uDevFn, uReg, addr, 4);
832
833 /* enable memory mappings */
834 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, uCmd, 2);
835}
836
837
838static void ich9pciBiosInitBridge(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint8_t cBridgeDepth, uint8_t *paBridgePositions)
839{
840 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_SECONDARY_BUS, pGlobals->uBus, 1);
841 /* Temporary until we know how many other bridges are behind this one. */
842 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_SUBORDINATE_BUS, 0xff, 1);
843
844 /* Add position of this bridge into the array. */
845 paBridgePositions[cBridgeDepth+1] = (uDevFn >> 3);
846
847 /*
848 * The I/O range for the bridge must be aligned to a 4KB boundary.
849 * This does not change anything really as the access to the device is not going
850 * through the bridge but we want to be compliant to the spec.
851 */
852 if ((pGlobals->uPciBiosIo % 4096) != 0)
853 {
854 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
855 Log(("%s: Aligned I/O start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosIo));
856 }
857 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_BASE, (pGlobals->uPciBiosIo >> 8) & 0xf0, 1);
858
859 /* The MMIO range for the bridge must be aligned to a 1MB boundary. */
860 if ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0)
861 {
862 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
863 Log(("%s: Aligned MMIO start address. New address %#x\n", __FUNCTION__, pGlobals->uPciBiosMmio));
864 }
865 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_BASE, (pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xffff0), 2);
866
867 /* Save values to compare later to. */
868 uint32_t u32IoAddressBase = pGlobals->uPciBiosIo;
869 uint32_t u32MMIOAddressBase = pGlobals->uPciBiosMmio;
870
871 /* Init devices behind the bridge and possibly other bridges as well. */
872 for (int iDev = 0; iDev <= 255; iDev++)
873 ich9pciBiosInitDevice(pGlobals, uBus + 1, iDev, cBridgeDepth + 1, paBridgePositions);
874
875 /* The number of bridges behind the this one is now available. */
876 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_SUBORDINATE_BUS, pGlobals->uBus, 1);
877
878 /*
879 * Set I/O limit register. If there is no device with I/O space behind the bridge
880 * we set a lower value than in the base register.
881 * The result with a real bridge is that no I/O transactions are passed to the secondary
882 * interface. Again this doesn't really matter here but we want to be compliant to the spec.
883 */
884 if ((u32IoAddressBase != pGlobals->uPciBiosIo) && ((pGlobals->uPciBiosIo % 4096) != 0))
885 {
886 /* The upper boundary must be one byte less than a 4KB boundary. */
887 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, 4*1024);
888 }
889
890 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_IO_LIMIT, ((pGlobals->uPciBiosIo >> 8) & 0xf0) - 1, 1);
891
892 /* Same with the MMIO limit register but with 1MB boundary here. */
893 if ((u32MMIOAddressBase != pGlobals->uPciBiosMmio) && ((pGlobals->uPciBiosMmio % (1024 * 1024)) != 0))
894 {
895 /* The upper boundary must be one byte less than a 1MB boundary. */
896 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, 1024*1024);
897 }
898 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_LIMIT, ((pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xfff0)) - 1, 2);
899
900 /*
901 * Set the prefetch base and limit registers. We currently have no device with a prefetchable region
902 * which may be behind a bridge. Thatswhy it is unconditionally disabled here atm by writing a higher value into
903 * the base register than in the limit register.
904 */
905 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_BASE, 0xfff0, 2);
906 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_LIMIT, 0x0, 2);
907 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_BASE_UPPER32, 0x00, 4);
908 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_LIMIT_UPPER32, 0x00, 4);
909}
910
911static void ich9pciBiosInitDevice(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint8_t cBridgeDepth, uint8_t *paBridgePositions)
912{
913 uint32_t *paddr;
914 int i, pin, pic_irq;
915 uint16_t uDevClass, uVendor, uDevice;
916
917 uDevClass = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_CLASS_DEVICE, 2);
918 uVendor = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_VENDOR_ID, 2);
919 uDevice = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_DEVICE_ID, 2);
920
921 /* If device is present */
922 if (uVendor == 0xffff)
923 return;
924
925 switch (uDevice)
926 {
927 case 0x0101:
928 /* IDE controller */
929 ich9pciConfigWrite(pGlobals, uBus, uDevFn, 0x40, 0x8000, 2); /* enable IDE0 */
930 ich9pciConfigWrite(pGlobals, uBus, uDevFn, 0x42, 0x8000, 2); /* enable IDE1 */
931 goto default_map;
932 break;
933 case 0x0300:
934 /* VGA controller */
935 if (uVendor != 0x80ee)
936 goto default_map;
937 /* VGA: map frame buffer to default Bochs VBE address */
938 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, 0, 0xE0000000);
939 /*
940 * Legacy VGA I/O ports are implicitly decoded by a VGA class device. But
941 * only the framebuffer (i.e., a memory region) is explicitly registered via
942 * ich9pciSetRegionAddress, so I/O decoding must be enabled manually.
943 */
944 uint8_t uCmd = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND, 1);
945 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_COMMAND,
946 /* Enable I/O space access. */
947 uCmd | PCI_COMMAND_IOACCESS,
948 1);
949 break;
950 case 0x0800:
951 /* PIC */
952 if (uVendor == 0x1014)
953 {
954 /* IBM */
955 if (uDevice == 0x0046 || uDevice == 0xFFFF)
956 /* MPIC & MPIC2 */
957 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, 0, 0x80800000 + 0x00040000);
958 }
959 break;
960 case 0xff00:
961 if ((uVendor == 0x0106b)
962 && (uDevice == 0x0017 || uDevice == 0x0022))
963 {
964 /* macio bridge */
965 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, 0, 0x80800000);
966 }
967 break;
968 case 0x0604:
969 /* PCI-to-PCI bridge. */
970 ich9pciConfigWrite(pGlobals, uBus, uDevFn, VBOX_PCI_PRIMARY_BUS, uBus, 1);
971
972 AssertMsg(pGlobals->uBus < 255, ("Too many bridges on the bus\n"));
973 pGlobals->uBus++;
974 ich9pciBiosInitBridge(pGlobals, uBus, uDevFn, cBridgeDepth, paBridgePositions);
975 break;
976 default:
977 default_map:
978 {
979 /* default memory mappings */
980 /*
981 * We ignore ROM region here.
982 */
983 for (int iRegion = 0; iRegion < (PCI_NUM_REGIONS-1); iRegion++)
984 {
985 uint32_t u32Address = ich9pciGetRegionReg(iRegion);
986
987 /* Calculate size. */
988 uint8_t u8ResourceType = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 1);
989 ich9pciConfigWrite(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff), 4);
990 uint32_t u32Size = ich9pciConfigRead(pGlobals, uBus, uDevFn, u32Address, 4);
991 /* Clear resource information depending on resource type. */
992 if ((u8ResourceType & PCI_COMMAND_IOACCESS) == PCI_COMMAND_IOACCESS) /* I/O */
993 u32Size &= ~(0x01);
994 else /* MMIO */
995 u32Size &= ~(0x0f);
996
997 bool fIsPio = ((u8ResourceType & PCI_COMMAND_IOACCESS) == PCI_COMMAND_IOACCESS);
998 /*
999 * Invert all bits and add 1 to get size of the region.
1000 * (From PCI implementation note)
1001 */
1002 if (fIsPio && (u32Size & UINT32_C(0xffff0000)) == 0)
1003 u32Size = (~(u32Size | UINT32_C(0xffff0000))) + 1;
1004 else
1005 u32Size = (~u32Size) + 1;
1006
1007 Log(("%s: Size of region %u for device %d on bus %d is %u\n", __FUNCTION__, i, uDevFn, uBus, u32Size));
1008
1009 if (u32Size)
1010 {
1011 paddr = fIsPio ? &pGlobals->uPciBiosIo : &pGlobals->uPciBiosMmio;
1012 *paddr = (*paddr + u32Size - 1) & ~(u32Size - 1);
1013 Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, (fIsPio ? "I/O" : "MMIO"), i, *paddr));
1014 ich9pciSetRegionAddress(pGlobals, uBus, uDevFn, i, *paddr);
1015 *paddr += u32Size;
1016 Log(("%s: New address is %#x\n", __FUNCTION__, *paddr));
1017 }
1018 }
1019 break;
1020 }
1021 }
1022
1023 /* map the interrupt */
1024 uint32_t uPin = ich9pciConfigRead(pGlobals, uBus, uDevFn, VBOX_PCI_INTERRUPT_PIN, 1);
1025 if (uPin != 0)
1026 {
1027 uint8_t uBridgeDevFn = uDevFn;
1028 uPin--;
1029
1030 /* We need to go up to the host bus to see which irq this device will assert there. */
1031 while (cBridgeDepth != 0)
1032 {
1033 /* Get the pin the device would assert on the bridge. */
1034 uPin = ((uBridgeDevFn >> 3) + uPin) & 3;
1035 uBridgeDevFn = paBridgePositions[cBridgeDepth];
1036 cBridgeDepth--;
1037 }
1038#if 0
1039 uPin = pci_slot_get_pirq(uDevFn, pin);
1040 pic_irq = pci_irqs[pin];
1041 ich9pciConfigWrite(pGlobals, uBus, uDevFn, PCI_INTERRUPT_LINE, pic_irq);
1042#endif
1043 }
1044}
1045
1046static const uint8_t auPciIrqs[4] = { 11, 9, 11, 9 };
1047
1048static DECLCALLBACK(int) ich9pciFakePCIBIOS(PPDMDEVINS pDevIns)
1049{
1050 unsigned i;
1051 uint8_t elcr[2] = {0, 0};
1052 PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
1053 PVM pVM = PDMDevHlpGetVM(pDevIns);
1054 Assert(pVM);
1055
1056 /*
1057 * Set the start addresses.
1058 */
1059 pGlobals->uPciBiosIo = 0xd000;
1060 pGlobals->uPciBiosMmio = UINT32_C(0xf0000000);
1061 pGlobals->uBus = 0;
1062
1063 /*
1064 * Activate IRQ mappings.
1065 */
1066 for (i = 0; i < 4; i++)
1067 {
1068 uint8_t irq = auPciIrqs[i];
1069 /* Set to trigger level. */
1070 elcr[irq >> 3] |= (1 << (irq & 7));
1071 }
1072
1073 /* Tell to the PIC. */
1074 VBOXSTRICTRC rcStrict = IOMIOPortWrite(pVM, 0x4d0, elcr[0], sizeof(uint8_t));
1075 if (rcStrict == VINF_SUCCESS)
1076 rcStrict = IOMIOPortWrite(pVM, 0x4d1, elcr[1], sizeof(uint8_t));
1077 if (rcStrict != VINF_SUCCESS)
1078 {
1079 AssertMsgFailed(("Writing to PIC failed! rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
1080 return RT_SUCCESS(rcStrict) ? VERR_INTERNAL_ERROR : VBOXSTRICTRC_VAL(rcStrict);
1081 }
1082
1083 /*
1084 * Init the devices.
1085 */
1086 for (i = 0; i < 256; i++)
1087 {
1088 uint8_t aBridgePositions[256];
1089
1090 memset(aBridgePositions, 0, sizeof(aBridgePositions));
1091 Log2(("PCI: Initializing device %d (%#x)\n",
1092 i, 0x80000000 | (i << 8)));
1093 ich9pciBiosInitDevice(pGlobals, 0, i, 0, aBridgePositions);
1094 }
1095
1096 return VINF_SUCCESS;
1097}
1098
1099static DECLCALLBACK(uint32_t) ich9pciConfigRead(PCIDevice *aDev, uint32_t u32Address, unsigned len)
1100{
1101 AssertMsgReturn(u32Address + len <= 256, ("Read after end of PCI config space\n"),
1102 0);
1103 switch (len)
1104 {
1105 case 1:
1106 return aDev->config[u32Address];
1107 case 2:
1108 return RT_LE2H_U16(*(uint16_t *)(aDev->config + u32Address));
1109 default:
1110 case 4:
1111 return RT_LE2H_U32(*(uint32_t *)(aDev->config + u32Address));
1112 }
1113}
1114
1115
1116/**
1117 * See paragraph 7.5 of PCI Express specification (p. 349) for definition of
1118 * registers and their writability policy.
1119 */
1120static DECLCALLBACK(void) ich9pciConfigWrite(PCIDevice *aDev, uint32_t u32Address,
1121 uint32_t val, unsigned len)
1122{
1123 /* Fast case - update one of BARs or ROM address, 'while' only for 'break' */
1124 while (len == 4 &&
1125 (u32Address >= VBOX_PCI_BASE_ADDRESS_0 &&
1126 u32Address < VBOX_PCI_BASE_ADDRESS_0 + 6 * 4)
1127 ||
1128 (u32Address >= VBOX_PCI_ROM_ADDRESS && u32Address < VBOX_PCI_ROM_ADDRESS+4))
1129 {
1130 PCIIORegion *pRegion;
1131 int reg, regionSize;
1132
1133 reg = (u32Address >= VBOX_PCI_ROM_ADDRESS) ? PCI_ROM_SLOT : (u32Address - VBOX_PCI_BASE_ADDRESS_0) >> 2;
1134 pRegion = &aDev->Int.s.aIORegions[reg];
1135 regionSize = pRegion->size;
1136 if (regionSize == 0)
1137 break;
1138 /* compute the stored value */
1139 if (reg == PCI_ROM_SLOT) {
1140 /* keep ROM enable bit */
1141 val &= (~(regionSize - 1)) | 1;
1142 } else {
1143 val &= ~(regionSize - 1);
1144 val |= pRegion->type;
1145 }
1146 *(uint32_t *)(aDev->config + u32Address) = RT_H2LE_U32(val);
1147 ich9pciUpdateMappings(aDev);
1148 return;
1149 }
1150
1151 uint32_t addr = u32Address;
1152 bool fUpdateMappings = false;
1153 for (uint32_t i = 0; i < len; i++)
1154 {
1155 bool fWritable = false;
1156 switch (PCIDevGetHeaderType(aDev))
1157 {
1158 case 0x00: /* normal device */
1159 case 0x80: /* multi-function device */
1160 switch (addr)
1161 {
1162 /* Read-only registers, see */
1163 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
1164 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
1165 case VBOX_PCI_REVISION_ID:
1166 case VBOX_PCI_CLASS_PROG:
1167 case VBOX_PCI_CLASS_SUB:
1168 case VBOX_PCI_CLASS_BASE:
1169 case VBOX_PCI_HEADER_TYPE:
1170 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:
1171 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:
1172 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:
1173 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:
1174 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:
1175 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:
1176 case VBOX_PCI_SUBSYSTEM_VENDOR_ID: case VBOX_PCI_SUBSYSTEM_VENDOR_ID+1:
1177 case VBOX_PCI_SUBSYSTEM_ID: case VBOX_PCI_SUBSYSTEM_ID+1:
1178 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS+1: case VBOX_PCI_ROM_ADDRESS+2: case VBOX_PCI_ROM_ADDRESS+3:
1179 case VBOX_PCI_CAPABILITY_LIST:
1180 case VBOX_PCI_INTERRUPT_PIN:
1181 fWritable = false;
1182 break;
1183 /* Others can be written */
1184 default:
1185 fWritable = true;
1186 break;
1187 }
1188 break;
1189 default:
1190 case 0x01: /* bridge */
1191 switch (addr)
1192 {
1193 /* Read-only registers */
1194 case VBOX_PCI_VENDOR_ID: case VBOX_PCI_VENDOR_ID+1:
1195 case VBOX_PCI_DEVICE_ID: case VBOX_PCI_DEVICE_ID+1:
1196 case VBOX_PCI_REVISION_ID:
1197 case VBOX_PCI_CLASS_PROG:
1198 case VBOX_PCI_CLASS_SUB:
1199 case VBOX_PCI_CLASS_BASE:
1200 case VBOX_PCI_HEADER_TYPE:
1201 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:
1202 case VBOX_PCI_INTERRUPT_PIN:
1203 fWritable = false;
1204 break;
1205 default:
1206 fWritable = true;
1207 break;
1208 }
1209 break;
1210 }
1211
1212 switch (addr)
1213 {
1214 case VBOX_PCI_COMMAND: /* Command register, bits 0-7. */
1215 fUpdateMappings = true;
1216 aDev->config[addr] = val;
1217 break;
1218 case VBOX_PCI_COMMAND+1: /* Command register, bits 8-15. */
1219 /* don't change reserved bits (11-15) */
1220 val &= UINT32_C(~0xf8);
1221 fUpdateMappings = true;
1222 aDev->config[addr] = val;
1223 break;
1224 case VBOX_PCI_STATUS: /* Status register, bits 0-7. */
1225 /* don't change read-only bits => actually all lower bits are read-only */
1226 val &= UINT32_C(~0xff);
1227 /* status register, low part: clear bits by writing a '1' to the corresponding bit */
1228 aDev->config[addr] &= ~val;
1229 break;
1230 case VBOX_PCI_STATUS+1: /* Status register, bits 8-15. */
1231 /* don't change read-only bits */
1232 val &= UINT32_C(~0x06);
1233 /* status register, high part: clear bits by writing a '1' to the corresponding bit */
1234 aDev->config[addr] &= ~val;
1235 break;
1236 default:
1237 if (fWritable)
1238 aDev->config[addr] = val;
1239 }
1240 addr++;
1241 val >>= 8;
1242 }
1243
1244 if (fUpdateMappings)
1245 /* if the command register is modified, we must modify the mappings */
1246 ich9pciUpdateMappings(aDev);
1247}
1248
1249/* Slot/functions assignment per table at p. 12 of ICH9 family spec update */
1250static const struct {
1251 const char* pszName;
1252 int32_t iSlot;
1253 int32_t iFunction;
1254} PciSlotAssignments[] = {
1255 {
1256 "piix3ide", 1, 1 // do we really need it?
1257 },
1258 {
1259 "lan", 25, 0
1260 },
1261 {
1262 "hda", 27, 0 /* High Definition Audio */
1263 },
1264 {
1265 "i82801", 30, 0 /* Host Controller */
1266 },
1267 {
1268 "lpc", 31, 0 /* Low Pin Count bus */
1269 },
1270 {
1271 "ahci", 31, 2 /* SATA controller */
1272 },
1273 {
1274 "smbus", 31, 3 /* System Management Bus */
1275 },
1276 {
1277 "thermal", 31, 6 /* Thermal controller */
1278 },
1279};
1280
1281static int assignPosition(PPCIBUS pBus, PPCIDEVICE pPciDev, const char *pszName)
1282{
1283 /* Hardcoded slots/functions, per chipset spec */
1284 for (size_t i = 0; i < RT_ELEMENTS(PciSlotAssignments); i++)
1285 {
1286 if (!strcmp(pszName, PciSlotAssignments[i].pszName))
1287 {
1288 pPciDev->Int.s.fRequestedDevFn = true;
1289 return (PciSlotAssignments[i].iSlot << 3) + PciSlotAssignments[i].iFunction;
1290 }
1291 }
1292
1293 /* Otherwise when assigning a slot, we need to make sure all its functions are available */
1294 for (int iPos = 0; iPos < (int)RT_ELEMENTS(pBus->apDevices); iPos += 8)
1295 if ( !pBus->apDevices[iPos]
1296 && !pBus->apDevices[iPos + 1]
1297 && !pBus->apDevices[iPos + 2]
1298 && !pBus->apDevices[iPos + 3]
1299 && !pBus->apDevices[iPos + 4]
1300 && !pBus->apDevices[iPos + 5]
1301 && !pBus->apDevices[iPos + 6]
1302 && !pBus->apDevices[iPos + 7])
1303 {
1304 pPciDev->Int.s.fRequestedDevFn = false;
1305 return iPos;
1306 }
1307
1308 return -1;
1309}
1310
1311static bool hasHardAssignedDevsInSlot(PPCIBUS pBus, int iSlot)
1312{
1313 PCIDevice** aSlot = &pBus->apDevices[iSlot << 3];
1314
1315 return (aSlot[0] && aSlot[0]->Int.s.fRequestedDevFn)
1316 || (aSlot[1] && aSlot[1]->Int.s.fRequestedDevFn)
1317 || (aSlot[2] && aSlot[2]->Int.s.fRequestedDevFn)
1318 || (aSlot[3] && aSlot[3]->Int.s.fRequestedDevFn)
1319 || (aSlot[4] && aSlot[4]->Int.s.fRequestedDevFn)
1320 || (aSlot[5] && aSlot[5]->Int.s.fRequestedDevFn)
1321 || (aSlot[6] && aSlot[6]->Int.s.fRequestedDevFn)
1322 || (aSlot[7] && aSlot[7]->Int.s.fRequestedDevFn)
1323 ;
1324}
1325
1326static int ich9pciRegisterInternal(PPCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName)
1327{
1328 /*
1329 * Find device position
1330 */
1331 if (iDev < 0)
1332 {
1333 iDev = assignPosition(pBus, pPciDev, pszName);
1334 if (iDev < 0)
1335 {
1336 AssertMsgFailed(("Couldn't find free spot!\n"));
1337 return VERR_PDM_TOO_PCI_MANY_DEVICES;
1338 }
1339 }
1340
1341 /*
1342 * Check if we can really take this slot, possibly by relocating
1343 * its current habitant, if it wasn't hard assigned too.
1344 */
1345 if (pPciDev->Int.s.fRequestedDevFn &&
1346 pBus->apDevices[iDev] &&
1347 pBus->apDevices[iDev]->Int.s.fRequestedDevFn)
1348 {
1349 /*
1350 * Smth like hasHardAssignedDevsInSlot(pBus, iDev >> 3) shall be use to make
1351 * it compatible with DevPCI.cpp version, but this way we cannot assign
1352 * in accordance with the chipset spec.
1353 */
1354 AssertReleaseMsgFailed(("Configuration error:'%s' and '%s' are both configured as device %d\n",
1355 pszName, pBus->apDevices[iDev]->name, iDev));
1356 return VERR_INTERNAL_ERROR;
1357 }
1358
1359 if (pBus->apDevices[iDev])
1360 {
1361 /* if we got here, we shall (and usually can) relocate the device */
1362 int iRelDev = assignPosition(pBus, pBus->apDevices[iDev], pBus->apDevices[iDev]->name);
1363 if (iRelDev < 0 || iRelDev == iDev)
1364 {
1365 AssertMsgFailed(("Couldn't find free spot!\n"));
1366 return VERR_PDM_TOO_PCI_MANY_DEVICES;
1367 }
1368 /* Copy device function by function to its new position */
1369 for (int i = 0; i < 8; i++)
1370 {
1371 if (!pBus->apDevices[iDev + i])
1372 continue;
1373 Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->apDevices[iDev + i]->name, iDev + i, iRelDev + i));
1374 pBus->apDevices[iRelDev + i] = pBus->apDevices[iDev + i];
1375 pBus->apDevices[iRelDev + i]->devfn = i;
1376 pBus->apDevices[iDev + i] = NULL;
1377 }
1378 }
1379
1380 /*
1381 * Fill in device information.
1382 */
1383 pPciDev->devfn = iDev;
1384 pPciDev->name = pszName;
1385 pPciDev->Int.s.pBusR3 = pBus;
1386 pPciDev->Int.s.pBusR0 = MMHyperR3ToR0(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
1387 pPciDev->Int.s.pBusRC = MMHyperR3ToRC(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
1388 pPciDev->Int.s.pfnConfigRead = ich9pciConfigRead;
1389 pPciDev->Int.s.pfnConfigWrite = ich9pciConfigWrite;
1390 pBus->apDevices[iDev] = pPciDev;
1391 if (pPciDev->Int.s.fPciToPciBridge)
1392 {
1393 AssertMsg(pBus->cBridges < RT_ELEMENTS(pBus->apDevices), ("Number of bridges exceeds the number of possible devices on the bus\n"));
1394 AssertMsg(pPciDev->Int.s.pfnBridgeConfigRead && pPciDev->Int.s.pfnBridgeConfigWrite,
1395 ("device is a bridge but does not implement read/write functions\n"));
1396 pBus->papBridgesR3[pBus->cBridges] = pPciDev;
1397 pBus->cBridges++;
1398 }
1399
1400 Log(("PCI: Registered device %d function %d (%#x) '%s'.\n",
1401 iDev >> 3, iDev & 7, 0x80000000 | (iDev << 8), pszName));
1402
1403 return VINF_SUCCESS;
1404}
1405
1406static DECLCALLBACK(int) ich9pciConstruct(PPDMDEVINS pDevIns,
1407 int iInstance,
1408 PCFGMNODE pCfg)
1409{
1410 int rc;
1411 Assert(iInstance == 0);
1412
1413 /*
1414 * Validate and read configuration.
1415 */
1416 if (!CFGMR3AreValuesValid(pCfg, "IOAPIC\0" "GCEnabled\0" "R0Enabled\0"))
1417 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1418
1419 /* query whether we got an IOAPIC */
1420 bool fUseIoApic;
1421 rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fUseIoApic, false);
1422 if (RT_FAILURE(rc))
1423 return PDMDEV_SET_ERROR(pDevIns, rc,
1424 N_("Configuration error: Failed to query boolean value \"IOAPIC\""));
1425
1426 /* check if RC code is enabled. */
1427 bool fGCEnabled;
1428 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
1429 if (RT_FAILURE(rc))
1430 return PDMDEV_SET_ERROR(pDevIns, rc,
1431 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
1432
1433 /* check if R0 code is enabled. */
1434 bool fR0Enabled;
1435 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
1436 if (RT_FAILURE(rc))
1437 return PDMDEV_SET_ERROR(pDevIns, rc,
1438 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
1439 Log(("PCI: fUseIoApic=%RTbool fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fUseIoApic, fGCEnabled, fR0Enabled));
1440
1441 /*
1442 * Init data.
1443 */
1444 PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
1445 PPCIBUS pBus = &pGlobals->aPciBus;
1446 /* Zero out everything */
1447 memset(pGlobals, 0, sizeof(*pGlobals));
1448 /* And fill values */
1449 if (!fUseIoApic)
1450 return PDMDEV_SET_ERROR(pDevIns, rc,
1451 N_("Must use IO-APIC with ICH9 chipset"));
1452 pGlobals->pDevInsR3 = pDevIns;
1453 pGlobals->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1454 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1455
1456 pGlobals->aPciBus.pDevInsR3 = pDevIns;
1457 pGlobals->aPciBus.pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
1458 pGlobals->aPciBus.pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1459 pGlobals->aPciBus.papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pGlobals->aPciBus.apDevices));
1460
1461 /*
1462 * Register bus
1463 */
1464 PDMPCIBUSREG PciBusReg;
1465 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
1466 PciBusReg.pfnRegisterR3 = ich9pciRegister;
1467 PciBusReg.pfnIORegionRegisterR3 = ich9pciIORegionRegister;
1468 PciBusReg.pfnSetConfigCallbacksR3 = ich9pciSetConfigCallbacks;
1469 PciBusReg.pfnSetIrqR3 = ich9pciSetIrq;
1470 PciBusReg.pfnSaveExecR3 = pciGenericSaveExec;
1471 PciBusReg.pfnLoadExecR3 = pciGenericLoadExec;
1472 PciBusReg.pfnFakePCIBIOSR3 = ich9pciFakePCIBIOS;
1473 PciBusReg.pszSetIrqRC = fGCEnabled ? "ich9pciSetIrq" : NULL;
1474 PciBusReg.pszSetIrqR0 = fR0Enabled ? "ich9pciSetIrq" : NULL;
1475 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
1476 if (RT_FAILURE(rc))
1477 return PDMDEV_SET_ERROR(pDevIns, rc,
1478 N_("Failed to register ourselves as a PCI Bus"));
1479 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
1480 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
1481 N_("PCI helper version mismatch; got %#x expected %#x"),
1482 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
1483
1484 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
1485 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
1486
1487 /*
1488 * Fill in PCI configs and add them to the bus.
1489 */
1490
1491 /**
1492 * We emulate 82801IB ICH9 IO chip used in Q35,
1493 * see http://ark.intel.com/Product.aspx?id=31892
1494 *
1495 * Stepping S-Spec Top Marking
1496 *
1497 * A2 SLA9M NH82801IB
1498 */
1499 PCIDevSetVendorId( &pBus->aPciDev, 0x8086); /* Intel */
1500 PCIDevSetDeviceId( &pBus->aPciDev, 0x244e); /* Desktop */
1501 PCIDevSetRevisionId(&pBus->aPciDev, 0x92); /* rev. A2 */
1502 PCIDevSetClassSub( &pBus->aPciDev, 0x00); /* Host/PCI bridge */
1503 PCIDevSetClassBase( &pBus->aPciDev, 0x06); /* bridge */
1504 PCIDevSetHeaderType(&pBus->aPciDev, 0x00);
1505
1506 pBus->aPciDev.pDevIns = pDevIns;
1507 pBus->aPciDev.Int.s.fRequestedDevFn = true;
1508 /* We register Host<->PCI controller on the bus */
1509 ich9pciRegisterInternal(pBus, 0, &pBus->aPciDev, "i82801");
1510
1511 /** @todo: ther chipset devices shall be registered too */
1512 /** @todo: bridges? */
1513
1514 return VINF_SUCCESS;
1515}
1516
1517/**
1518 * @copydoc FNPDMDEVRELOCATE
1519 */
1520static DECLCALLBACK(void) ich9pciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1521{
1522 PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
1523 PPCIBUS pBus = &pGlobals->aPciBus;
1524 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1525
1526 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
1527 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
1528
1529 /* Relocate RC pointers for the attached pci devices. */
1530 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->apDevices); i++)
1531 {
1532 if (pBus->apDevices[i])
1533 pBus->apDevices[i]->Int.s.pBusRC += offDelta;
1534 }
1535
1536}
1537
1538/**
1539 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1540 */
1541static DECLCALLBACK(int) ich9pcibridgeConstruct(PPDMDEVINS pDevIns,
1542 int iInstance,
1543 PCFGMNODE pCfg)
1544{
1545 int rc;
1546
1547 /*
1548 * Validate and read configuration.
1549 */
1550 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
1551 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1552
1553 /* check if RC code is enabled. */
1554 bool fGCEnabled;
1555 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
1556 if (RT_FAILURE(rc))
1557 return PDMDEV_SET_ERROR(pDevIns, rc,
1558 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
1559
1560 /* check if R0 code is enabled. */
1561 bool fR0Enabled;
1562 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
1563 if (RT_FAILURE(rc))
1564 return PDMDEV_SET_ERROR(pDevIns, rc,
1565 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
1566 Log(("PCI: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
1567
1568 return VINF_SUCCESS;
1569}
1570
1571/**
1572 * @copydoc FNPDMDEVRESET
1573 */
1574static DECLCALLBACK(void) ich9pcibridgeReset(PPDMDEVINS pDevIns)
1575{
1576}
1577
1578
1579/**
1580 * @copydoc FNPDMDEVRELOCATE
1581 */
1582static DECLCALLBACK(void) ich9pcibridgeRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1583{
1584}
1585
1586/**
1587 * The PCI bus device registration structure.
1588 */
1589const PDMDEVREG g_DevicePciIch9 =
1590{
1591 /* u32Version */
1592 PDM_DEVREG_VERSION,
1593 /* szName */
1594 "ich9pci",
1595 /* szRCMod */
1596 "VBoxDDGC.gc",
1597 /* szR0Mod */
1598 "VBoxDDR0.r0",
1599 /* pszDescription */
1600 "ICH9 PCI bridge",
1601 /* fFlags */
1602 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1603 /* fClass */
1604 PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
1605 /* cMaxInstances */
1606 1,
1607 /* cbInstance */
1608 sizeof(PCIGLOBALS),
1609 /* pfnConstruct */
1610 ich9pciConstruct,
1611 /* pfnDestruct */
1612 NULL,
1613 /* pfnRelocate */
1614 ich9pciRelocate,
1615 /* pfnIOCtl */
1616 NULL,
1617 /* pfnPowerOn */
1618 NULL,
1619 /* pfnReset */
1620 NULL,
1621 /* pfnSuspend */
1622 NULL,
1623 /* pfnResume */
1624 NULL,
1625 /* pfnAttach */
1626 NULL,
1627 /* pfnDetach */
1628 NULL,
1629 /* pfnQueryInterface */
1630 NULL,
1631 /* pfnInitComplete */
1632 NULL,
1633 /* pfnPowerOff */
1634 NULL,
1635 /* pfnSoftReset */
1636 NULL,
1637 /* u32VersionEnd */
1638 PDM_DEVREG_VERSION
1639};
1640
1641/**
1642 * The device registration structure
1643 * for the PCI-to-PCI bridge.
1644 */
1645const PDMDEVREG g_DevicePciIch9Bridge =
1646{
1647 /* u32Version */
1648 PDM_DEVREG_VERSION,
1649 /* szName */
1650 "ich9pcibridge",
1651 /* szRCMod */
1652 "VBoxDDGC.gc",
1653 /* szR0Mod */
1654 "VBoxDDR0.r0",
1655 /* pszDescription */
1656 "ICH9 PCI to PCI bridge",
1657 /* fFlags */
1658 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1659 /* fClass */
1660 PDM_DEVREG_CLASS_BUS_PCI,
1661 /* cMaxInstances */
1662 ~0,
1663 /* cbInstance */
1664 sizeof(PCIBUS),
1665 /* pfnConstruct */
1666 ich9pcibridgeConstruct,
1667 /* pfnDestruct */
1668 NULL,
1669 /* pfnRelocate */
1670 ich9pcibridgeRelocate,
1671 /* pfnIOCtl */
1672 NULL,
1673 /* pfnPowerOn */
1674 NULL,
1675 /* pfnReset */
1676 ich9pcibridgeReset,
1677 /* pfnSuspend */
1678 NULL,
1679 /* pfnResume */
1680 NULL,
1681 /* pfnAttach */
1682 NULL,
1683 /* pfnDetach */
1684 NULL,
1685 /* pfnQueryInterface */
1686 NULL,
1687 /* pfnInitComplete */
1688 NULL,
1689 /* pfnPowerOff */
1690 NULL,
1691 /* pfnSoftReset */
1692 NULL,
1693 /* u32VersionEnd */
1694 PDM_DEVREG_VERSION
1695};
1696
1697#endif /* IN_RING3 */
1698#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