VirtualBox

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

Last change on this file since 64463 was 64463, checked in by vboxsync, 8 years ago

DevPci: Cleaning up ich9pciConfigWriteDev.

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