VirtualBox

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

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

DevPci: Share the devpciR3CommonRestoreConfig.

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