VirtualBox

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

Last change on this file since 81902 was 81765, checked in by vboxsync, 5 years ago

Devices: Use new volatile SSM getters and enum macros. bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 170.8 KB
Line 
1/* $Id: DevPciIch9.cpp 81765 2019-11-11 16:00:31Z 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 * DO NOT use the PDMPciDev* or PCIDev* family of functions in this
13 * file except in the two callbacks for config space access (and the
14 * functions which are used exclusively by that code) and the two
15 * device constructors when setting up the config space for the
16 * bridges. Everything else need extremely careful review. Using
17 * them elsewhere (especially in the init code) causes weird failures
18 * with PCI passthrough, as it would only update the array of
19 * (emulated) config space, but not talk to the actual device (needs
20 * invoking the respective callback).
21 */
22
23/*
24 * Copyright (C) 2010-2019 Oracle Corporation
25 *
26 * This file is part of VirtualBox Open Source Edition (OSE), as
27 * available from http://www.virtualbox.org. This file is free software;
28 * you can redistribute it and/or modify it under the terms of the GNU
29 * General Public License (GPL) as published by the Free Software
30 * Foundation, in version 2 as it comes in the "COPYING" file of the
31 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
32 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
33 */
34
35
36/*********************************************************************************************************************************
37* Header Files *
38*********************************************************************************************************************************/
39#define LOG_GROUP LOG_GROUP_DEV_PCI
40#define PDMPCIDEV_INCLUDE_PRIVATE /* Hack to get pdmpcidevint.h included at the right point. */
41#include <VBox/vmm/pdmpcidev.h>
42
43#include <VBox/msi.h>
44#include <VBox/vmm/pdmdev.h>
45#include <VBox/vmm/mm.h>
46#include <iprt/asm.h>
47#include <iprt/assert.h>
48#include <iprt/string.h>
49#ifdef IN_RING3
50# include <iprt/mem.h>
51# include <iprt/uuid.h>
52#endif
53
54#include "PciInline.h"
55#include "VBoxDD.h"
56#include "MsiCommon.h"
57#include "DevPciInternal.h"
58
59
60/*********************************************************************************************************************************
61* Structures and Typedefs *
62*********************************************************************************************************************************/
63/**
64 * PCI configuration space address.
65 */
66typedef struct
67{
68 uint8_t iBus;
69 uint8_t iDeviceFunc;
70 uint16_t iRegister;
71} PciAddress;
72
73
74/*********************************************************************************************************************************
75* Defined Constants And Macros *
76*********************************************************************************************************************************/
77/** Saved state version of the ICH9 PCI bus device. */
78#define VBOX_ICH9PCI_SAVED_STATE_VERSION VBOX_ICH9PCI_SAVED_STATE_VERSION_4KB_CFG_SPACE
79/** 4KB config space */
80#define VBOX_ICH9PCI_SAVED_STATE_VERSION_4KB_CFG_SPACE 4
81/** Adds I/O region types and sizes for dealing changes in resource regions. */
82#define VBOX_ICH9PCI_SAVED_STATE_VERSION_REGION_SIZES 3
83/** This appears to be the first state we need to care about. */
84#define VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI 2
85/** This is apparently not supported or has a grossly incomplete state, juding
86 * from hints in the code. */
87#define VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI 1
88
89/** Invalid PCI region mapping address. */
90#define INVALID_PCI_ADDRESS UINT32_MAX
91
92
93/*********************************************************************************************************************************
94* Internal Functions *
95*********************************************************************************************************************************/
96/* Prototypes */
97static void ich9pciSetIrqInternal(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUSCC pBusCC,
98 uint8_t uDevFn, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc);
99#ifdef IN_RING3
100static int ich9pciFakePCIBIOS(PPDMDEVINS pDevIns);
101DECLINLINE(PPDMPCIDEV) ich9pciFindBridge(PDEVPCIBUS pBus, uint8_t uBus);
102static void ich9pciBiosInitAllDevicesOnBus(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus);
103static bool ich9pciBiosInitAllDevicesPrefetchableOnBus(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus, bool fUse64Bit, bool fDryrun);
104#endif
105
106
107/**
108 * See 7.2.2. PCI Express Enhanced Configuration Mechanism for details of address
109 * mapping, we take n=6 approach
110 */
111DECLINLINE(void) ich9pciPhysToPciAddr(PDEVPCIROOT pPciRoot, RTGCPHYS GCPhysAddr, PciAddress *pPciAddr)
112{
113 NOREF(pPciRoot);
114 pPciAddr->iBus = (GCPhysAddr >> 20) & ((1<<6) - 1);
115 pPciAddr->iDeviceFunc = (GCPhysAddr >> 12) & ((1<<(5+3)) - 1); // 5 bits - device, 3 bits - function
116 pPciAddr->iRegister = (GCPhysAddr >> 0) & ((1<<(6+4+2)) - 1); // 6 bits - register, 4 bits - extended register, 2 bits -Byte Enable
117 RT_UNTRUSTED_VALIDATED_FENCE(); /* paranoia */
118}
119
120DECLINLINE(void) ich9pciStateToPciAddr(PDEVPCIROOT pPciRoot, RTGCPHYS addr, PciAddress *pPciAddr)
121{
122 pPciAddr->iBus = (pPciRoot->uConfigReg >> 16) & 0xff;
123 pPciAddr->iDeviceFunc = (pPciRoot->uConfigReg >> 8) & 0xff;
124 pPciAddr->iRegister = (pPciRoot->uConfigReg & 0xfc) | (addr & 3);
125 RT_UNTRUSTED_VALIDATED_FENCE(); /* paranoia */
126}
127
128static void ich9pciSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
129{
130 LogFlowFunc(("invoked by %p/%d: iIrq=%d iLevel=%d uTagSrc=%#x\n", pDevIns, pDevIns->iInstance, iIrq, iLevel, uTagSrc));
131 ich9pciSetIrqInternal(pDevIns, PDMINS_2_DATA(pDevIns, PDEVPCIROOT), PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC),
132 pPciDev->uDevFn, pPciDev, iIrq, iLevel, uTagSrc);
133}
134
135/**
136 * Worker for ich9pcibridgeSetIrq and pcibridgeSetIrq that walks up to the root
137 * bridges and permutates iIrq accordingly.
138 *
139 * See ich9pciBiosInitAllDevicesOnBus for corresponding configuration code.
140 */
141DECLHIDDEN(PPDMDEVINS) devpcibridgeCommonSetIrqRootWalk(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq,
142 PDEVPCIBUS *ppBus, uint8_t *puDevFnBridge, int *piIrqPinBridge)
143{
144 PDEVPCIBUSCC const pBridgeBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC); /* For keep using our own pcihlp. */
145 PPDMDEVINS const pBridgeDevIns = pDevIns; /* ditto */
146
147 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
148 PPDMDEVINS pDevInsBus;
149 PPDMPCIDEV pPciDevBus = pDevIns->apPciDevs[0];
150 uint8_t uDevFnBridge = pPciDevBus->uDevFn;
151 int iIrqPinBridge = ((pPciDev->uDevFn >> 3) + iIrq) & 3;
152 uint64_t bmSeen[256/64] = { 0, 0, 0, 0 };
153 AssertCompile(sizeof(pPciDevBus->Int.s.idxPdmBus) == 1);
154 ASMBitSet(bmSeen, pPciDevBus->Int.s.idxPdmBus);
155
156 /* Walk the chain until we reach the host bus. */
157 Assert(pBus->iBus != 0);
158 for (;;)
159 {
160 /* Get the parent. */
161 pDevInsBus = pBridgeBusCC->CTX_SUFF(pPciHlp)->pfnGetBusByNo(pBridgeDevIns, pPciDevBus->Int.s.idxPdmBus);
162 AssertLogRelReturn(pDevInsBus, NULL);
163
164 pBus = PDMINS_2_DATA(pDevInsBus, PDEVPCIBUS);
165 pPciDevBus = pDevInsBus->apPciDevs[0];
166 if (pBus->iBus == 0)
167 {
168 *ppBus = pBus;
169 *puDevFnBridge = uDevFnBridge;
170 *piIrqPinBridge = iIrqPinBridge;
171 return pDevInsBus;
172 }
173
174 uDevFnBridge = pPciDevBus->uDevFn;
175 iIrqPinBridge = ((uDevFnBridge >> 3) + iIrqPinBridge) & 3;
176
177 /* Make sure that we cannot end up in a loop here: */
178 AssertCompile(sizeof(pPciDevBus->Int.s.idxPdmBus) == 1);
179 AssertMsgReturn(ASMBitTestAndSet(bmSeen, pPciDevBus->Int.s.idxPdmBus),
180 ("idxPdmBus=%u\n", pPciDevBus->Int.s.idxPdmBus),
181 NULL);
182 }
183
184}
185
186static void ich9pcibridgeSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
187{
188 /*
189 * The PCI-to-PCI bridge specification defines how the interrupt pins
190 * are routed from the secondary to the primary bus (see chapter 9).
191 * iIrq gives the interrupt pin the pci device asserted.
192 * We change iIrq here according to the spec and call the SetIrq function
193 * of our parent passing the device which asserted the interrupt instead of the device of the bridge.
194 *
195 * See ich9pciBiosInitAllDevicesOnBus for corresponding configuration code.
196 */
197 PDEVPCIBUS pBus;
198 uint8_t uDevFnBridge;
199 int iIrqPinBridge;
200 PPDMDEVINS pDevInsBus = devpcibridgeCommonSetIrqRootWalk(pDevIns, pPciDev, iIrq, &pBus, &uDevFnBridge, &iIrqPinBridge);
201 AssertReturnVoid(pDevInsBus);
202 AssertMsg(pBus->iBus == 0, ("This is not the host pci bus iBus=%d\n", pBus->iBus));
203 Assert(pDevInsBus->pReg == &g_DevicePciIch9); /* ASSUMPTION: Same style root bus. Need callback interface to mix types. */
204
205 /*
206 * For MSI/MSI-X enabled devices the iIrq doesn't denote the pin but rather a vector which is completely
207 * orthogonal to the pin based approach. The vector is not subject to the pin based routing with PCI bridges.
208 */
209 int iIrqPinVector = iIrqPinBridge;
210 if ( MsiIsEnabled(pPciDev)
211 || MsixIsEnabled(pPciDev))
212 iIrqPinVector = iIrq;
213 ich9pciSetIrqInternal(pDevInsBus, DEVPCIBUS_2_DEVPCIROOT(pBus), PDMINS_2_DATA_CC(pDevInsBus, PDEVPCIBUSCC),
214 uDevFnBridge, pPciDev, iIrqPinVector, iLevel, uTagSrc);
215}
216
217#ifdef IN_RING3
218
219/**
220 * @callback_method_impl{FNIOMIOPORTNEWOUT,
221 * Port I/O Handler for Fake PCI BIOS trigger OUT operations at 0410h.}
222 */
223static DECLCALLBACK(VBOXSTRICTRC)
224ich9pciR3IOPortMagicPCIWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
225{
226 Assert(offPort == 0); RT_NOREF2(pvUser, offPort);
227 LogFlowFunc(("offPort=%#x u32=%#x cb=%d\n", offPort, u32, cb));
228 if (cb == 4)
229 {
230 if (u32 == UINT32_C(19200509)) // Richard Adams
231 {
232 int rc = ich9pciFakePCIBIOS(pDevIns);
233 AssertRC(rc);
234 }
235 }
236
237 return VINF_SUCCESS;
238}
239
240
241/**
242 * @callback_method_impl{FNIOMIOPORTNEWIN,
243 * Port I/O Handler for Fake PCI BIOS trigger IN operations at 0410h.}
244 */
245static DECLCALLBACK(VBOXSTRICTRC)
246ich9pciR3IOPortMagicPCIRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
247{
248 Assert(offPort == 0); RT_NOREF5(pDevIns, pvUser, offPort, pu32, cb);
249 LogFunc(("offPort=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", offPort, cb));
250 return VERR_IOM_IOPORT_UNUSED;
251}
252
253#endif /* IN_RING3 */
254
255/**
256 * @callback_method_impl{FNIOMIOPORTNEWOUT,
257 * Port I/O Handler for PCI address OUT operations.}
258 *
259 * Emulates writes to Configuration Address Port at 0CF8h for Configuration
260 * Mechanism \#1.
261 */
262static DECLCALLBACK(VBOXSTRICTRC)
263ich9pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
264{
265 LogFlowFunc(("offPort=%#x u32=%#x cb=%d\n", offPort, u32, cb));
266 Assert(offPort == 0); RT_NOREF2(offPort, pvUser);
267 if (cb == 4)
268 {
269 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
270
271 /*
272 * bits [1:0] are hard-wired, read-only and must return zeroes
273 * when read.
274 */
275 u32 &= ~3;
276
277 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
278 pThis->uConfigReg = u32;
279 PCI_UNLOCK(pDevIns);
280 }
281
282 return VINF_SUCCESS;
283}
284
285
286/**
287 * @callback_method_impl{FNIOMIOPORTNEWIN,
288 * Port I/O Handler for PCI data IN operations.}
289 *
290 * Emulates reads from Configuration Address Port at 0CF8h for Configuration
291 * Mechanism \#1.
292 */
293static DECLCALLBACK(VBOXSTRICTRC)
294ich9pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
295{
296 Assert(offPort == 0); RT_NOREF2(offPort, pvUser);
297 if (cb == 4)
298 {
299 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
300
301 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_READ);
302 *pu32 = pThis->uConfigReg;
303 PCI_UNLOCK(pDevIns);
304
305 LogFlowFunc(("offPort=%#x cb=%d -> %#x\n", offPort, cb, *pu32));
306 return VINF_SUCCESS;
307 }
308
309 LogFunc(("offPort=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", offPort, cb));
310 return VERR_IOM_IOPORT_UNUSED;
311}
312
313
314/**
315 * Perform configuration space write.
316 */
317static VBOXSTRICTRC ich9pciConfigWrite(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PciAddress const *pPciAddr,
318 uint32_t u32Value, int cb, int rcReschedule)
319{
320 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
321
322 if (pPciAddr->iBus != 0) /* forward to subordinate bus */
323 {
324 if (pPciRoot->PciBus.cBridges)
325 {
326#ifdef IN_RING3 /** @todo do lookup in R0/RC too! r=klaus don't think that it can work, since the config space access callback only works in R3 */
327 PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(&pPciRoot->PciBus, pPciAddr->iBus);
328 if (pBridgeDevice)
329 {
330 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
331 rcStrict = pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), pPciAddr->iBus,
332 pPciAddr->iDeviceFunc, pPciAddr->iRegister, cb, u32Value);
333 }
334#else
335 rcStrict = rcReschedule;
336#endif
337 }
338 }
339 else /* forward to directly connected device */
340 {
341 R3PTRTYPE(PDMPCIDEV *) pPciDev = pPciRoot->PciBus.apDevices[pPciAddr->iDeviceFunc];
342 if (pPciDev)
343 {
344#ifdef IN_RING3
345 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
346 if (pPciDev->Int.s.pfnConfigWrite)
347 rcStrict = pPciDev->Int.s.pfnConfigWrite(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev,
348 pPciAddr->iRegister, cb, u32Value);
349 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
350 rcStrict = devpciR3CommonConfigWriteWorker(pDevIns, PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC),
351 pPciDev, pPciAddr->iRegister, cb, u32Value);
352 RT_NOREF(rcReschedule);
353#else
354 rcStrict = rcReschedule;
355 RT_NOREF(pDevIns, u32Value, cb);
356#endif
357 }
358 }
359
360 Log2Func(("%02x:%02x.%u reg %x(%u) %x %Rrc\n", pPciAddr->iBus, pPciAddr->iDeviceFunc >> 3, pPciAddr->iDeviceFunc & 0x7,
361 pPciAddr->iRegister, cb, u32Value, VBOXSTRICTRC_VAL(rcStrict)));
362 return rcStrict;
363}
364
365
366/**
367 * @callback_method_impl{FNIOMIOPORTNEWOUT,
368 * Port I/O Handler for PCI data OUT operations.}
369 *
370 * Emulates writes to Configuration Data Port at 0CFCh for Configuration
371 * Mechanism \#1.
372 */
373static DECLCALLBACK(VBOXSTRICTRC)
374ich9pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
375{
376 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
377 LogFlowFunc(("offPort=%u u32=%#x cb=%d (config=%#10x)\n", offPort, u32, cb, pThis->uConfigReg));
378 Assert(offPort < 4); NOREF(pvUser);
379
380 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
381 if (!(offPort % cb))
382 {
383 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
384
385 if (pThis->uConfigReg & (1 << 31))
386 {
387
388 /* Decode target device from Configuration Address Port */
389 PciAddress aPciAddr;
390 ich9pciStateToPciAddr(pThis, offPort, &aPciAddr);
391
392 /* Perform configuration space write */
393 rcStrict = ich9pciConfigWrite(pDevIns, pThis, &aPciAddr, u32, cb, VINF_IOM_R3_IOPORT_WRITE);
394 }
395
396 PCI_UNLOCK(pDevIns);
397 }
398 else
399 AssertMsgFailed(("Unaligned write to offPort=%u u32=%#x cb=%d\n", offPort, u32, cb));
400
401 return rcStrict;
402}
403
404
405/**
406 * Perform configuration space read.
407 */
408static VBOXSTRICTRC ich9pciConfigRead(PDEVPCIROOT pPciRoot, PciAddress* pPciAddr, int cb, uint32_t *pu32Value, int rcReschedule)
409{
410 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
411#ifdef IN_RING3
412 NOREF(rcReschedule);
413#else
414 NOREF(cb);
415#endif
416
417 if (pPciAddr->iBus != 0) /* forward to subordinate bus */
418 {
419 if (pPciRoot->PciBus.cBridges)
420 {
421#ifdef IN_RING3 /** @todo do lookup in R0/RC too! r=klaus don't think that it can work, since the config space access callback only works in R3 */
422 PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(&pPciRoot->PciBus, pPciAddr->iBus);
423 if (pBridgeDevice)
424 {
425 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
426 rcStrict = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), pPciAddr->iBus,
427 pPciAddr->iDeviceFunc, pPciAddr->iRegister, cb, pu32Value);
428 }
429 else
430 *pu32Value = UINT32_MAX;
431#else
432 rcStrict = rcReschedule;
433#endif
434 }
435 else
436 *pu32Value = 0xffffffff;
437 }
438 else /* forward to directly connected device */
439 {
440 R3PTRTYPE(PDMPCIDEV *) pPciDev = pPciRoot->PciBus.apDevices[pPciAddr->iDeviceFunc];
441 if (pPciDev)
442 {
443#ifdef IN_RING3
444 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
445 if (pPciDev->Int.s.pfnConfigRead)
446 rcStrict = pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev,
447 pPciAddr->iRegister, cb, pu32Value);
448 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
449 rcStrict = devpciR3CommonConfigReadWorker(pPciDev, pPciAddr->iRegister, cb, pu32Value);
450#else
451 rcStrict = rcReschedule;
452#endif
453 }
454 else
455 *pu32Value = UINT32_MAX;
456 }
457
458 Log3Func(("%02x:%02x.%d reg %x(%d) gave %x %Rrc\n", pPciAddr->iBus, pPciAddr->iDeviceFunc >> 3, pPciAddr->iDeviceFunc & 0x7,
459 pPciAddr->iRegister, cb, *pu32Value, VBOXSTRICTRC_VAL(rcStrict) ));
460 return rcStrict;
461}
462
463
464/**
465 * @callback_method_impl{FNIOMIOPORTNEWIN,
466 * Port I/O Handler for PCI data IN operations.}
467 *
468 * Emulates reads from Configuration Data Port at 0CFCh for Configuration
469 * Mechanism \#1.
470 */
471static DECLCALLBACK(VBOXSTRICTRC)
472ich9pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
473{
474 NOREF(pvUser);
475 Assert(offPort < 4);
476 if (!(offPort % cb))
477 {
478 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
479 *pu32 = 0xffffffff;
480
481 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_READ);
482
483 /* Configuration space mapping enabled? */
484 VBOXSTRICTRC rcStrict;
485 if (!(pThis->uConfigReg & (1 << 31)))
486 rcStrict = VINF_SUCCESS;
487 else
488 {
489 /* Decode target device and configuration space register */
490 PciAddress aPciAddr;
491 ich9pciStateToPciAddr(pThis, offPort, &aPciAddr);
492
493 /* Perform configuration space read */
494 rcStrict = ich9pciConfigRead(pThis, &aPciAddr, cb, pu32, VINF_IOM_R3_IOPORT_READ);
495 }
496
497 PCI_UNLOCK(pDevIns);
498
499 LogFlowFunc(("offPort=%u cb=%#x (config=%#10x) -> %#x (%Rrc)\n", offPort, cb, *pu32, pThis->uConfigReg, VBOXSTRICTRC_VAL(rcStrict)));
500 return rcStrict;
501 }
502 AssertMsgFailed(("Unaligned read from offPort=%u cb=%d\n", offPort, cb));
503 return VERR_IOM_IOPORT_UNUSED;
504}
505
506
507/* Compute mapping of PCI slot and IRQ number to APIC interrupt line */
508DECLINLINE(int) ich9pciSlot2ApicIrq(uint8_t uSlot, int irq_num)
509{
510 return (irq_num + uSlot) & 7;
511}
512
513#ifdef IN_RING3
514
515/* return the global irq number corresponding to a given device irq
516 pin. We could also use the bus number to have a more precise
517 mapping. This is the implementation note described in the PCI spec chapter 2.2.6 */
518DECLINLINE(int) ich9pciSlotGetPirq(uint8_t uBus, uint8_t uDevFn, uint8_t uIrqNum)
519{
520 NOREF(uBus);
521 int iSlotAddend = (uDevFn >> 3) - 1;
522 return (uIrqNum + iSlotAddend) & 3;
523}
524
525/* irqs corresponding to PCI irqs A-D, must match pci_irq_list in pcibios.inc */
526/** @todo r=klaus inconsistent! ich9 doesn't implement PIRQ yet, so both needs to be addressed and tested thoroughly. */
527static const uint8_t aPciIrqs[4] = { 11, 10, 9, 5 };
528
529#endif /* IN_RING3 */
530
531/* Add one more level up request on APIC input line */
532DECLINLINE(void) ich9pciApicLevelUp(PDEVPCIROOT pPciRoot, int irq_num)
533{
534 ASMAtomicIncU32(&pPciRoot->auPciApicIrqLevels[irq_num]);
535}
536
537/* Remove one level up request on APIC input line */
538DECLINLINE(void) ich9pciApicLevelDown(PDEVPCIROOT pPciRoot, int irq_num)
539{
540 ASMAtomicDecU32(&pPciRoot->auPciApicIrqLevels[irq_num]);
541}
542
543static void ich9pciApicSetIrq(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PDEVPCIBUSCC pBusCC,
544 uint8_t uDevFn, PDMPCIDEV *pPciDev, int irq_num1, int iLevel, uint32_t uTagSrc, int iForcedIrq)
545{
546 /* This is only allowed to be called with a pointer to the root bus. */
547 AssertMsg(pBus->iBus == 0, ("iBus=%u\n", pBus->iBus));
548
549 if (iForcedIrq == -1)
550 {
551 int apic_irq, apic_level;
552 PDEVPCIROOT pPciRoot = DEVPCIBUS_2_DEVPCIROOT(pBus);
553 int irq_num = ich9pciSlot2ApicIrq(uDevFn >> 3, irq_num1);
554
555 if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_HIGH)
556 ich9pciApicLevelUp(pPciRoot, irq_num);
557 else if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_LOW)
558 ich9pciApicLevelDown(pPciRoot, irq_num);
559
560 apic_irq = irq_num + 0x10;
561 apic_level = pPciRoot->auPciApicIrqLevels[irq_num] != 0;
562 Log3Func(("%s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d uTagSrc=%#x\n",
563 R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, apic_irq, apic_level, irq_num, uTagSrc));
564 pBusCC->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pDevIns, apic_irq, apic_level, uTagSrc);
565
566 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
567 {
568 /*
569 * we raised it few lines above, as PDM_IRQ_LEVEL_FLIP_FLOP has
570 * PDM_IRQ_LEVEL_HIGH bit set
571 */
572 ich9pciApicLevelDown(pPciRoot, irq_num);
573 pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
574 apic_level = pPciRoot->auPciApicIrqLevels[irq_num] != 0;
575 Log3Func(("%s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d uTagSrc=%#x (flop)\n",
576 R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, apic_irq, apic_level, irq_num, uTagSrc));
577 pBusCC->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pDevIns, apic_irq, apic_level, uTagSrc);
578 }
579 } else {
580 Log3Func(("(forced) %s: irq_num1=%d level=%d acpi_irq=%d uTagSrc=%#x\n",
581 R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, iForcedIrq, uTagSrc));
582 pBusCC->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pDevIns, iForcedIrq, iLevel, uTagSrc);
583 }
584}
585
586static void ich9pciSetIrqInternal(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUSCC pBusCC,
587 uint8_t uDevFn, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
588{
589 /* If MSI or MSI-X is enabled, PCI INTx# signals are disabled regardless of the PCI command
590 * register interrupt bit state.
591 * PCI 3.0 (section 6.8) forbids MSI and MSI-X to be enabled at the same time and makes
592 * that undefined behavior. We check for MSI first, then MSI-X.
593 */
594 if (MsiIsEnabled(pPciDev))
595 {
596 Assert(!MsixIsEnabled(pPciDev)); /* Not allowed -- see note above. */
597 LogFlowFunc(("PCI Dev %p : MSI\n", pPciDev));
598 MsiNotify(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel, uTagSrc);
599 return;
600 }
601
602 if (MsixIsEnabled(pPciDev))
603 {
604 LogFlowFunc(("PCI Dev %p : MSI-X\n", pPciDev));
605 MsixNotify(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, iIrq, iLevel, uTagSrc);
606 return;
607 }
608
609 PDEVPCIBUS pBus = &pPciRoot->PciBus;
610 /* safe, only needs to go to the config space array */
611 const bool fIsAcpiDevice = PDMPciDevGetDeviceId(pPciDev) == 0x7113;
612
613 LogFlowFunc(("PCI Dev %p : IRQ\n", pPciDev));
614 /* Check if the state changed. */
615 if (pPciDev->Int.s.uIrqPinState != iLevel)
616 {
617 pPciDev->Int.s.uIrqPinState = (iLevel & PDM_IRQ_LEVEL_HIGH);
618
619 /** @todo r=klaus: implement PIRQ handling (if APIC isn't active). Needed for legacy OSes which don't use the APIC stuff. */
620
621 /* Send interrupt to I/O APIC only now. */
622 if (fIsAcpiDevice)
623 /*
624 * ACPI needs special treatment since SCI is hardwired and
625 * should not be affected by PCI IRQ routing tables at the
626 * same time SCI IRQ is shared in PCI sense hence this
627 * kludge (i.e. we fetch the hardwired value from ACPIs
628 * PCI device configuration space).
629 */
630 /* safe, only needs to go to the config space array */
631 ich9pciApicSetIrq(pDevIns, pBus, pBusCC, uDevFn, pPciDev, -1, iLevel, uTagSrc, PDMPciDevGetInterruptLine(pPciDev));
632 else
633 ich9pciApicSetIrq(pDevIns, pBus, pBusCC, uDevFn, pPciDev, iIrq, iLevel, uTagSrc, -1);
634 }
635}
636
637
638/**
639 * Memory mapped I/O Handler for write operations.
640 *
641 * Emulates writes to configuration space.
642 *
643 * @returns VBox status code.
644 *
645 * @param pDevIns The device instance.
646 * @param pvUser User argument.
647 * @param GCPhysAddr Physical address (in GC) where the read starts.
648 * @param pv Where to fetch the result.
649 * @param cb Number of bytes to write.
650 * @remarks Caller enters the device critical section.
651 */
652PDMBOTHCBDECL(int) ich9pciMcfgMMIOWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
653{
654 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
655 uint32_t u32 = 0;
656 NOREF(pvUser);
657
658 Log2Func(("%RGp(%d) \n", GCPhysAddr, cb));
659
660 PCI_LOCK(pDevIns, VINF_IOM_R3_MMIO_WRITE);
661
662 /* Decode target device and configuration space register */
663 PciAddress aDest;
664 ich9pciPhysToPciAddr(pPciRoot, GCPhysAddr, &aDest);
665
666 switch (cb)
667 {
668 case 1:
669 u32 = *(uint8_t*)pv;
670 break;
671 case 2:
672 u32 = *(uint16_t*)pv;
673 break;
674 case 4:
675 u32 = *(uint32_t*)pv;
676 break;
677 default:
678 Assert(false);
679 break;
680 }
681
682 /* Perform configuration space write */
683 VBOXSTRICTRC rcStrict = ich9pciConfigWrite(pDevIns, pPciRoot, &aDest, u32, cb, VINF_IOM_R3_MMIO_WRITE);
684 PCI_UNLOCK(pDevIns);
685
686 return VBOXSTRICTRC_TODO(rcStrict);
687}
688
689
690/**
691 * Memory mapped I/O Handler for read operations.
692 *
693 * Emulates reads from configuration space.
694 *
695 * @returns VBox status code.
696 *
697 * @param pDevIns The device instance.
698 * @param pvUser User argument.
699 * @param GCPhysAddr Physical address (in GC) where the read starts.
700 * @param pv Where to store the result.
701 * @param cb Number of bytes read.
702 * @remarks Caller enters the device critical section.
703 */
704PDMBOTHCBDECL(int) ich9pciMcfgMMIORead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
705{
706 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
707 NOREF(pvUser);
708
709 LogFlowFunc(("%RGp(%d) \n", GCPhysAddr, cb));
710
711 PCI_LOCK(pDevIns, VINF_IOM_R3_MMIO_READ);
712
713 /* Decode target device and configuration space register */
714 PciAddress aDest;
715 ich9pciPhysToPciAddr(pPciRoot, GCPhysAddr, &aDest);
716
717 /* Perform configuration space read */
718 uint32_t u32Value;
719 VBOXSTRICTRC rcStrict = ich9pciConfigRead(pPciRoot, &aDest, cb, &u32Value, VINF_IOM_R3_MMIO_READ);
720 if (RT_SUCCESS(rcStrict)) /** @todo this is wrong, though it probably works fine due to double buffering... */
721 {
722 switch (cb)
723 {
724 case 1:
725 *(uint8_t *)pv = (uint8_t)u32Value;
726 break;
727 case 2:
728 *(uint16_t *)pv = (uint16_t)u32Value;
729 break;
730 case 4:
731 *(uint32_t *)pv = u32Value;
732 break;
733 default:
734 AssertFailed();
735 break;
736 }
737 }
738
739 PCI_UNLOCK(pDevIns);
740 return VBOXSTRICTRC_TODO(rcStrict);
741}
742
743#ifdef IN_RING3
744
745DECLINLINE(PPDMPCIDEV) ich9pciFindBridge(PDEVPCIBUS pBus, uint8_t uBus)
746{
747 /* Search for a fitting bridge. */
748 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
749 {
750 /*
751 * Examine secondary and subordinate bus number.
752 * If the target bus is in the range we pass the request on to the bridge.
753 */
754 PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
755 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
756 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
757 /* safe, only needs to go to the config space array */
758 uint32_t uSecondary = PDMPciDevGetByte(pBridge, VBOX_PCI_SECONDARY_BUS);
759 /* safe, only needs to go to the config space array */
760 uint32_t uSubordinate = PDMPciDevGetByte(pBridge, VBOX_PCI_SUBORDINATE_BUS);
761 Log3Func(("bus %p, bridge %d: %d in %d..%d\n", pBus, iBridge, uBus, uSecondary, uSubordinate));
762 if (uBus >= uSecondary && uBus <= uSubordinate)
763 return pBridge;
764 }
765
766 /* Nothing found. */
767 return NULL;
768}
769
770uint32_t devpciR3GetCfg(PPDMPCIDEV pPciDev, int32_t iRegister, int cb)
771{
772 uint32_t u32Value = UINT32_MAX;
773 VBOXSTRICTRC rcStrict = VINF_PDM_PCI_DO_DEFAULT;
774 if (pPciDev->Int.s.pfnConfigRead)
775 rcStrict = pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, iRegister, cb, &u32Value);
776 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
777 rcStrict = devpciR3CommonConfigReadWorker(pPciDev, iRegister, cb, &u32Value);
778 AssertRCSuccess(VBOXSTRICTRC_VAL(rcStrict));
779 return u32Value;
780}
781
782DECLINLINE(uint32_t) devpciGetRegionReg(int iRegion)
783{
784 return iRegion == VBOX_PCI_ROM_SLOT
785 ? VBOX_PCI_ROM_ADDRESS : (VBOX_PCI_BASE_ADDRESS_0 + iRegion * 4);
786}
787
788/**
789 * Worker for devpciR3SetByte(), devpciR3SetWord() and devpciR3SetDWord(), also
790 * used during state restore.
791 */
792void devpciR3SetCfg(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int32_t iRegister, uint32_t u32Value, int cb)
793{
794 Assert(cb <= 4 && cb != 3);
795 VBOXSTRICTRC rcStrict = VINF_PDM_PCI_DO_DEFAULT;
796 if (pPciDev->Int.s.pfnConfigWrite)
797 rcStrict = pPciDev->Int.s.pfnConfigWrite(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, iRegister, cb, u32Value);
798 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
799 rcStrict = devpciR3CommonConfigWriteWorker(pDevIns, PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC),
800 pPciDev, iRegister, cb, u32Value);
801 AssertRCSuccess(VBOXSTRICTRC_VAL(rcStrict));
802}
803
804
805/* -=-=-=-=-=- PCI Bus Interface Methods (PDMPCIBUSREG) -=-=-=-=-=- */
806
807/**
808 * Search for a completely unused device entry (all 8 functions are unused).
809 *
810 * @returns VBox status code.
811 * @param pBus The bus to register with.
812 * @remarks Caller enters the PDM critical section.
813 */
814static uint8_t devpciR3CommonFindUnusedDeviceNo(PDEVPCIBUS pBus)
815{
816 for (uint8_t uPciDevNo = pBus->iDevSearch >> VBOX_PCI_DEVFN_DEV_SHIFT; uPciDevNo < VBOX_PCI_MAX_DEVICES; uPciDevNo++)
817 if ( !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 0)]
818 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 1)]
819 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 2)]
820 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 3)]
821 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 4)]
822 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 5)]
823 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 6)]
824 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 7)])
825 return uPciDevNo;
826 return UINT8_MAX;
827}
828
829
830
831/**
832 * Registers the device with the specified PCI bus.
833 *
834 * This is shared between the pci bus and pci bridge code.
835 *
836 * @returns VBox status code.
837 * @param pDevIns The PCI bus device instance.
838 * @param pBus The bus to register with.
839 * @param pPciDev The PCI device structure.
840 * @param fFlags Reserved for future use, PDMPCIDEVREG_F_MBZ.
841 * @param uPciDevNo PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, or a specific
842 * device number (0-31).
843 * @param uPciFunNo PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific
844 * function number (0-7).
845 * @param pszName Device name (static but not unique).
846 *
847 * @remarks Caller enters the PDM critical section.
848 */
849static int devpciR3CommonRegisterDeviceOnBus(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev, uint32_t fFlags,
850 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
851{
852 RT_NOREF(pDevIns);
853
854 /*
855 * Validate input.
856 */
857 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
858 AssertPtrReturn(pPciDev, VERR_INVALID_POINTER);
859 AssertReturn(!(fFlags & ~PDMPCIDEVREG_F_VALID_MASK), VERR_INVALID_FLAGS);
860 AssertReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES || uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER);
861 AssertReturn(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS || uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER);
862
863 /*
864 * Assign device & function numbers.
865 */
866
867 /* Work the optional assignment flag. */
868 if (fFlags & PDMPCIDEVREG_F_NOT_MANDATORY_NO)
869 {
870 AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES && uPciFunNo < VBOX_PCI_MAX_FUNCTIONS,
871 ("PDMPCIDEVREG_F_NOT_MANDATORY_NO not implemented for #Dev=%#x / #Fun=%#x\n", uPciDevNo, uPciFunNo),
872 VERR_NOT_IMPLEMENTED);
873 if (pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)])
874 {
875 uPciDevNo = PDMPCIDEVREG_DEV_NO_FIRST_UNUSED;
876 uPciFunNo = PDMPCIDEVREG_FUN_NO_FIRST_UNUSED;
877 }
878 }
879
880 if (uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED)
881 {
882 /* Just find the next unused device number and we're good. */
883 uPciDevNo = devpciR3CommonFindUnusedDeviceNo(pBus);
884 AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES, ("Couldn't find a free spot!\n"), VERR_PDM_TOO_PCI_MANY_DEVICES);
885 if (uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED)
886 uPciFunNo = 0;
887 }
888 else
889 {
890 /*
891 * Direct assignment of device number can be more complicated.
892 */
893 PPDMPCIDEV pClash;
894 if (uPciFunNo != PDMPCIDEVREG_FUN_NO_FIRST_UNUSED)
895 {
896 /* In the case of a specified function, we only relocate an existing
897 device if it belongs to a different device instance. Reasoning is
898 that the device should figure out it's own function assignments.
899 Note! We could make this more flexible by relocating functions assigned
900 via PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, but it can wait till it's needed. */
901 pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)];
902 if (!pClash)
903 { /* likely */ }
904 else if (pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3)
905 AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (same pDevIns)!\n",
906 uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName),
907 VERR_PDM_TOO_PCI_MANY_DEVICES);
908 else if (!pClash->Int.s.fReassignableDevNo)
909 AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (different pDevIns)!\n",
910 uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName),
911 VERR_PDM_TOO_PCI_MANY_DEVICES);
912 }
913 else
914 {
915 /* First unused function slot. Again, we only relocate the whole
916 thing if all the device instance differs, because we otherwise
917 reason that a device should manage its own functions correctly. */
918 unsigned cSameDevInses = 0;
919 for (uPciFunNo = 0, pClash = NULL; uPciFunNo < VBOX_PCI_MAX_FUNCTIONS; uPciFunNo++)
920 {
921 pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)];
922 if (!pClash)
923 break;
924 cSameDevInses += pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3;
925 }
926 if (!pClash)
927 Assert(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS);
928 else
929 AssertLogRelMsgReturn(cSameDevInses == 0,
930 ("PCI Configuration conflict at %u.* appending %s (%u of %u pDevIns matches)!\n",
931 uPciDevNo, pszName, cSameDevInses, VBOX_PCI_MAX_FUNCTIONS),
932 VERR_PDM_TOO_PCI_MANY_DEVICES);
933 }
934 if (pClash)
935 {
936 /*
937 * Try relocate the existing device.
938 */
939 /* Check that all functions can be moved. */
940 for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++)
941 {
942 PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)];
943 AssertLogRelMsgReturn(!pMovePciDev || pMovePciDev->Int.s.fReassignableDevNo,
944 ("PCI Configuration conflict at %u.%u: %s vs %s\n",
945 uPciDevNo, uMoveFun, pMovePciDev->pszNameR3, pszName),
946 VERR_PDM_TOO_PCI_MANY_DEVICES);
947 }
948
949 /* Find a free device number to move it to. */
950 uint8_t uMoveToDevNo = devpciR3CommonFindUnusedDeviceNo(pBus);
951 Assert(uMoveToDevNo != uPciFunNo);
952 AssertLogRelMsgReturn(uMoveToDevNo < VBOX_PCI_MAX_DEVICES,
953 ("No space to relocate device at %u so '%s' can be placed there instead!\n", uPciFunNo, pszName),
954 VERR_PDM_TOO_PCI_MANY_DEVICES);
955
956 /* Execute the move. */
957 for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++)
958 {
959 PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)];
960 if (pMovePciDev)
961 {
962 Log(("PCI: Relocating '%s' from %u.%u to %u.%u.\n", pMovePciDev->pszNameR3, uPciDevNo, uMoveFun, uMoveToDevNo, uMoveFun));
963 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)] = NULL;
964 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun)] = pMovePciDev;
965 pMovePciDev->uDevFn = VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun);
966 }
967 }
968 }
969 }
970
971 /*
972 * Now, initialize the rest of the PCI device structure.
973 */
974 Assert(!pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)]);
975 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)] = pPciDev;
976
977 pPciDev->uDevFn = VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo);
978 pPciDev->Int.s.pBusR3 = pBus;
979 Assert(pBus == PDMINS_2_DATA(pDevIns, PDEVPCIBUS));
980 pPciDev->Int.s.pfnConfigRead = NULL;
981 pPciDev->Int.s.pfnConfigWrite = NULL;
982 if (pBus->fTypePiix3 && pPciDev->cbConfig > 256)
983 pPciDev->cbConfig = 256;
984
985 /* Remember and mark bridges. */
986 if (fFlags & PDMPCIDEVREG_F_PCI_BRIDGE)
987 {
988 AssertLogRelMsgReturn(pBus->cBridges < RT_ELEMENTS(pBus->apDevices),
989 ("Number of bridges exceeds the number of possible devices on the bus\n"),
990 VERR_INTERNAL_ERROR_3);
991 pBus->papBridgesR3[pBus->cBridges++] = pPciDev;
992 pciDevSetPci2PciBridge(pPciDev);
993 }
994
995 Log(("PCI: Registered device %d function %d (%#x) '%s'.\n",
996 uPciDevNo, uPciFunNo, UINT32_C(0x80000000) | (pPciDev->uDevFn << 8), pszName));
997
998 return VINF_SUCCESS;
999}
1000
1001
1002/**
1003 * @interface_method_impl{PDMPCIBUSREGR3,pfnRegisterR3}
1004 */
1005DECLCALLBACK(int) devpciR3CommonRegisterDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
1006 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
1007{
1008 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1009 AssertCompileMemberOffset(DEVPCIROOT, PciBus, 0);
1010 return devpciR3CommonRegisterDeviceOnBus(pDevIns, pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName);
1011}
1012
1013
1014/**
1015 * @interface_method_impl{PDMPCIBUSREGR3,pfnRegisterR3}
1016 */
1017DECLCALLBACK(int) devpcibridgeR3CommonRegisterDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
1018 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
1019{
1020 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1021 return devpciR3CommonRegisterDeviceOnBus(pDevIns, pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName);
1022}
1023
1024
1025static DECLCALLBACK(int) ich9pciRegisterMsi(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg)
1026{
1027 //PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1028 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
1029
1030 int rc = MsiR3Init(pPciDev, pMsiReg);
1031 if (RT_SUCCESS(rc))
1032 rc = MsixR3Init(pBusCC->CTX_SUFF(pPciHlp), pPciDev, pMsiReg);
1033
1034 return rc;
1035}
1036
1037
1038/**
1039 * @interface_method_impl{PDMPCIBUSREGR3,pfnIORegionRegisterR3}
1040 */
1041DECLCALLBACK(int) devpciR3CommonIORegionRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
1042 RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, uint32_t fFlags,
1043 uint64_t hHandle, PFNPCIIOREGIONMAP pfnMapUnmap)
1044{
1045 LogFunc(("%s: region #%u size %RGp type %x fFlags=%#x hHandle=%#RX64\n",
1046 pPciDev->pszNameR3, iRegion, cbRegion, enmType, fFlags, hHandle));
1047 RT_NOREF(pDevIns);
1048
1049 /*
1050 * Validate.
1051 */
1052 AssertMsgReturn( enmType == (PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR32)
1053 || enmType == (PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_BAR32)
1054 || enmType == (PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_BAR64)
1055 || enmType == (PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_BAR64)
1056 || enmType == PCI_ADDRESS_SPACE_IO
1057 ,
1058 ("Invalid enmType=%#x? Or was this a bitmask after all...\n", enmType),
1059 VERR_INVALID_PARAMETER);
1060 AssertMsgReturn((unsigned)iRegion < VBOX_PCI_NUM_REGIONS,
1061 ("Invalid iRegion=%d VBOX_PCI_NUM_REGIONS=%d\n", iRegion, VBOX_PCI_NUM_REGIONS),
1062 VERR_INVALID_PARAMETER);
1063 int iLastSet = ASMBitLastSetU64(cbRegion);
1064 AssertMsgReturn( iLastSet != 0
1065 && RT_BIT_64(iLastSet - 1) == cbRegion,
1066 ("Invalid cbRegion=%RGp iLastSet=%#x (not a power of 2 or 0)\n", cbRegion, iLastSet),
1067 VERR_INVALID_PARAMETER);
1068 switch (fFlags & PDMPCIDEV_IORGN_F_HANDLE_MASK)
1069 {
1070 case PDMPCIDEV_IORGN_F_IOPORT_HANDLE:
1071 case PDMPCIDEV_IORGN_F_MMIO_HANDLE:
1072 case PDMPCIDEV_IORGN_F_MMIO2_HANDLE:
1073 AssertReturn(hHandle != UINT64_MAX, VERR_INVALID_HANDLE);
1074 break;
1075 default:
1076 AssertReturn(hHandle == UINT64_MAX, VERR_INVALID_HANDLE);
1077 }
1078
1079 /* Make sure that we haven't marked this region as continuation of 64-bit region. */
1080 AssertReturn(pPciDev->Int.s.aIORegions[iRegion].type != 0xff, VERR_NOT_AVAILABLE);
1081
1082 /*
1083 * Register the I/O region.
1084 */
1085 PPCIIOREGION pRegion = &pPciDev->Int.s.aIORegions[iRegion];
1086 pRegion->addr = INVALID_PCI_ADDRESS;
1087 pRegion->size = cbRegion;
1088 pRegion->fFlags = fFlags;
1089 pRegion->hHandle = hHandle;
1090 pRegion->type = enmType;
1091 pRegion->pfnMap = pfnMapUnmap;
1092
1093 if ((enmType & PCI_ADDRESS_SPACE_BAR64) != 0)
1094 {
1095 /* VBOX_PCI_BASE_ADDRESS_5 and VBOX_PCI_ROM_ADDRESS are excluded. */
1096 AssertMsgReturn(iRegion < VBOX_PCI_NUM_REGIONS - 2,
1097 ("Region %d cannot be 64-bit\n", iRegion),
1098 VERR_INVALID_PARAMETER);
1099 /* Mark next region as continuation of this one. */
1100 pPciDev->Int.s.aIORegions[iRegion + 1].type = 0xff;
1101 }
1102
1103 /* Set type in the PCI config space. */
1104 AssertCompile(PCI_ADDRESS_SPACE_MEM == 0);
1105 AssertCompile(PCI_ADDRESS_SPACE_IO == 1);
1106 AssertCompile(PCI_ADDRESS_SPACE_BAR64 == RT_BIT_32(2));
1107 AssertCompile(PCI_ADDRESS_SPACE_MEM_PREFETCH == RT_BIT_32(3));
1108 uint32_t u32Value = (uint32_t)enmType & (PCI_ADDRESS_SPACE_IO | PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_MEM_PREFETCH);
1109 /* safe, only needs to go to the config space array */
1110 PDMPciDevSetDWord(pPciDev, devpciGetRegionReg(iRegion), u32Value);
1111
1112 return VINF_SUCCESS;
1113}
1114
1115
1116/**
1117 * @interface_method_impl{PDMPCIBUSREGR3,pfnInterceptConfigAccesses}
1118 */
1119DECLCALLBACK(void) devpciR3CommonInterceptConfigAccesses(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
1120 PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite)
1121{
1122 NOREF(pDevIns);
1123
1124 pPciDev->Int.s.pfnConfigRead = pfnRead;
1125 pPciDev->Int.s.pfnConfigWrite = pfnWrite;
1126}
1127
1128
1129static int ich9pciR3CommonSaveExec(PDEVPCIBUS pBus, PSSMHANDLE pSSM)
1130{
1131 /*
1132 * Iterate thru all the devices.
1133 */
1134 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
1135 {
1136 PPDMPCIDEV pDev = pBus->apDevices[uDevFn];
1137 if (pDev)
1138 {
1139 /* Device position */
1140 SSMR3PutU32(pSSM, uDevFn);
1141
1142 /* PCI config registers */
1143 SSMR3PutU32(pSSM, sizeof(pDev->abConfig));
1144 SSMR3PutMem(pSSM, pDev->abConfig, sizeof(pDev->abConfig));
1145
1146 /* Device flags */
1147 SSMR3PutU32(pSSM, pDev->Int.s.fFlags);
1148
1149 /* IRQ pin state */
1150 SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
1151
1152 /* MSI info */
1153 SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapOffset);
1154 SSMR3PutU8(pSSM, pDev->Int.s.u8MsiCapSize);
1155
1156 /* MSI-X info */
1157 SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapOffset);
1158 SSMR3PutU8(pSSM, pDev->Int.s.u8MsixCapSize);
1159
1160 /* Save MSI-X page state */
1161 if (pDev->Int.s.u8MsixCapOffset != 0)
1162 {
1163 SSMR3PutU32(pSSM, pDev->Int.s.cbMsixRegion);
1164 SSMR3PutMem(pSSM, pDev->abMsixState, pDev->Int.s.cbMsixRegion);
1165 }
1166 else
1167 SSMR3PutU32(pSSM, 0);
1168
1169 /* Save the type an size of all the regions. */
1170 for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
1171 {
1172 SSMR3PutU8(pSSM, pDev->Int.s.aIORegions[iRegion].type);
1173 SSMR3PutU64(pSSM, pDev->Int.s.aIORegions[iRegion].size);
1174 }
1175 }
1176 }
1177 return SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
1178}
1179
1180static DECLCALLBACK(int) ich9pciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1181{
1182 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
1183
1184 /*
1185 * Bus state data.
1186 */
1187 SSMR3PutU32(pSSM, pThis->uConfigReg);
1188
1189 /*
1190 * Save IRQ states.
1191 */
1192 for (unsigned i = 0; i < RT_ELEMENTS(pThis->auPciApicIrqLevels); i++)
1193 SSMR3PutU32(pSSM, pThis->auPciApicIrqLevels[i]);
1194
1195 SSMR3PutU32(pSSM, UINT32_MAX); /* separator */
1196
1197 return ich9pciR3CommonSaveExec(&pThis->PciBus, pSSM);
1198}
1199
1200
1201static DECLCALLBACK(int) ich9pcibridgeR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1202{
1203 PDEVPCIBUS pThis = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1204 return ich9pciR3CommonSaveExec(pThis, pSSM);
1205}
1206
1207
1208/**
1209 * @callback_method_impl{FNPCIBRIDGECONFIGWRITE}
1210 */
1211static DECLCALLBACK(VBOXSTRICTRC) ich9pcibridgeConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice,
1212 uint32_t u32Address, unsigned cb, uint32_t u32Value)
1213{
1214 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1215 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1216 LogFlowFunc(("pDevIns=%p iBus=%d iDevice=%d u32Address=%#x cb=%d u32Value=%#x\n", pDevIns, iBus, iDevice, u32Address, cb, u32Value));
1217
1218 /* If the current bus is not the target bus search for the bus which contains the device. */
1219 /* safe, only needs to go to the config space array */
1220 if (iBus != PDMPciDevGetByte(pDevIns->apPciDevs[0], VBOX_PCI_SECONDARY_BUS))
1221 {
1222 PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1223 if (pBridgeDevice)
1224 {
1225 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
1226 pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus, iDevice,
1227 u32Address, cb, u32Value);
1228 }
1229 }
1230 else
1231 {
1232 /* This is the target bus, pass the write to the device. */
1233 PPDMPCIDEV pPciDev = pBus->apDevices[iDevice];
1234 if (pPciDev)
1235 {
1236 LogFunc(("%s: addr=%02x val=%08x len=%d\n", pPciDev->pszNameR3, u32Address, u32Value, cb));
1237 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
1238 if (pPciDev->Int.s.pfnConfigWrite)
1239 rcStrict = pPciDev->Int.s.pfnConfigWrite(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, u32Address, cb, u32Value);
1240 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
1241 rcStrict = devpciR3CommonConfigWriteWorker(pDevIns, PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC),
1242 pPciDev, u32Address, cb, u32Value);
1243 }
1244 }
1245 return rcStrict;
1246}
1247
1248/**
1249 * @callback_method_impl{FNPCIBRIDGECONFIGREAD}
1250 */
1251static DECLCALLBACK(VBOXSTRICTRC) ich9pcibridgeConfigRead(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice,
1252 uint32_t u32Address, unsigned cb, uint32_t *pu32Value)
1253{
1254 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1255 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1256 LogFlowFunc(("pDevIns=%p iBus=%d iDevice=%d u32Address=%#x cb=%d\n", pDevIns, iBus, iDevice, u32Address, cb));
1257
1258 /* If the current bus is not the target bus search for the bus which contains the device. */
1259 /* safe, only needs to go to the config space array */
1260 if (iBus != PDMPciDevGetByte(pDevIns->apPciDevs[0], VBOX_PCI_SECONDARY_BUS))
1261 {
1262 PPDMPCIDEV pBridgeDevice = ich9pciFindBridge(pBus, iBus);
1263 if (pBridgeDevice)
1264 {
1265 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
1266 rcStrict = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus, iDevice,
1267 u32Address, cb, pu32Value);
1268 }
1269 else
1270 *pu32Value = UINT32_MAX;
1271 }
1272 else
1273 {
1274 /* This is the target bus, pass the read to the device. */
1275 PPDMPCIDEV pPciDev = pBus->apDevices[iDevice];
1276 if (pPciDev)
1277 {
1278 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
1279 if (pPciDev->Int.s.pfnConfigRead)
1280 rcStrict = pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, u32Address, cb, pu32Value);
1281 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
1282 rcStrict = devpciR3CommonConfigReadWorker(pPciDev, u32Address, cb, pu32Value);
1283 LogFunc(("%s: u32Address=%02x *pu32Value=%#010x cb=%d\n", pPciDev->pszNameR3, u32Address, *pu32Value, cb));
1284 }
1285 else
1286 *pu32Value = UINT32_MAX;
1287 }
1288
1289 return rcStrict;
1290}
1291
1292
1293
1294/* -=-=-=-=-=- Saved State -=-=-=-=-=- */
1295
1296
1297/**
1298 * Common routine for restoring the config registers of a PCI device.
1299 *
1300 * @param pDevIns The device instance of the PC bus.
1301 * @param pDev The PCI device.
1302 * @param pbSrcConfig The configuration register values to be loaded.
1303 */
1304void devpciR3CommonRestoreConfig(PPDMDEVINS pDevIns, PPDMPCIDEV pDev, uint8_t const *pbSrcConfig)
1305{
1306 /*
1307 * This table defines the fields for normal devices and bridge devices, and
1308 * the order in which they need to be restored.
1309 */
1310 static const struct PciField
1311 {
1312 uint8_t off;
1313 uint8_t cb;
1314 uint8_t fWritable;
1315 uint8_t fBridge;
1316 const char *pszName;
1317 } s_aFields[] =
1318 {
1319 /* off,cb,fW,fB, pszName */
1320 { 0x00, 2, 0, 3, "VENDOR_ID" },
1321 { 0x02, 2, 0, 3, "DEVICE_ID" },
1322 { 0x06, 2, 1, 3, "STATUS" },
1323 { 0x08, 1, 0, 3, "REVISION_ID" },
1324 { 0x09, 1, 0, 3, "CLASS_PROG" },
1325 { 0x0a, 1, 0, 3, "CLASS_SUB" },
1326 { 0x0b, 1, 0, 3, "CLASS_BASE" },
1327 { 0x0c, 1, 1, 3, "CACHE_LINE_SIZE" },
1328 { 0x0d, 1, 1, 3, "LATENCY_TIMER" },
1329 { 0x0e, 1, 0, 3, "HEADER_TYPE" },
1330 { 0x0f, 1, 1, 3, "BIST" },
1331 { 0x10, 4, 1, 3, "BASE_ADDRESS_0" },
1332 { 0x14, 4, 1, 3, "BASE_ADDRESS_1" },
1333 { 0x18, 4, 1, 1, "BASE_ADDRESS_2" },
1334 { 0x18, 1, 1, 2, "PRIMARY_BUS" },
1335 { 0x19, 1, 1, 2, "SECONDARY_BUS" },
1336 { 0x1a, 1, 1, 2, "SUBORDINATE_BUS" },
1337 { 0x1b, 1, 1, 2, "SEC_LATENCY_TIMER" },
1338 { 0x1c, 4, 1, 1, "BASE_ADDRESS_3" },
1339 { 0x1c, 1, 1, 2, "IO_BASE" },
1340 { 0x1d, 1, 1, 2, "IO_LIMIT" },
1341 { 0x1e, 2, 1, 2, "SEC_STATUS" },
1342 { 0x20, 4, 1, 1, "BASE_ADDRESS_4" },
1343 { 0x20, 2, 1, 2, "MEMORY_BASE" },
1344 { 0x22, 2, 1, 2, "MEMORY_LIMIT" },
1345 { 0x24, 4, 1, 1, "BASE_ADDRESS_5" },
1346 { 0x24, 2, 1, 2, "PREF_MEMORY_BASE" },
1347 { 0x26, 2, 1, 2, "PREF_MEMORY_LIMIT" },
1348 { 0x28, 4, 0, 1, "CARDBUS_CIS" },
1349 { 0x28, 4, 1, 2, "PREF_BASE_UPPER32" },
1350 { 0x2c, 2, 0, 1, "SUBSYSTEM_VENDOR_ID" },
1351 { 0x2c, 4, 1, 2, "PREF_LIMIT_UPPER32" },
1352 { 0x2e, 2, 0, 1, "SUBSYSTEM_ID" },
1353 { 0x30, 4, 1, 1, "ROM_ADDRESS" },
1354 { 0x30, 2, 1, 2, "IO_BASE_UPPER16" },
1355 { 0x32, 2, 1, 2, "IO_LIMIT_UPPER16" },
1356 { 0x34, 4, 0, 3, "CAPABILITY_LIST" },
1357 { 0x38, 4, 1, 1, "RESERVED_38" },
1358 { 0x38, 4, 1, 2, "ROM_ADDRESS_BR" },
1359 { 0x3c, 1, 1, 3, "INTERRUPT_LINE" },
1360 { 0x3d, 1, 0, 3, "INTERRUPT_PIN" },
1361 { 0x3e, 1, 0, 1, "MIN_GNT" },
1362 { 0x3e, 2, 1, 2, "BRIDGE_CONTROL" },
1363 { 0x3f, 1, 0, 1, "MAX_LAT" },
1364 /* The COMMAND register must come last as it requires the *ADDRESS*
1365 registers to be restored before we pretent to change it from 0 to
1366 whatever value the guest assigned it. */
1367 { 0x04, 2, 1, 3, "COMMAND" },
1368 };
1369
1370#ifdef RT_STRICT
1371 /* Check that we've got full register coverage. */
1372 uint32_t bmDevice[0x40 / 32];
1373 uint32_t bmBridge[0x40 / 32];
1374 RT_ZERO(bmDevice);
1375 RT_ZERO(bmBridge);
1376 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1377 {
1378 uint8_t off = s_aFields[i].off;
1379 uint8_t cb = s_aFields[i].cb;
1380 uint8_t f = s_aFields[i].fBridge;
1381 while (cb-- > 0)
1382 {
1383 if (f & 1) AssertMsg(!ASMBitTest(bmDevice, off), ("%#x\n", off));
1384 if (f & 2) AssertMsg(!ASMBitTest(bmBridge, off), ("%#x\n", off));
1385 if (f & 1) ASMBitSet(bmDevice, off);
1386 if (f & 2) ASMBitSet(bmBridge, off);
1387 off++;
1388 }
1389 }
1390 for (uint32_t off = 0; off < 0x40; off++)
1391 {
1392 AssertMsg(ASMBitTest(bmDevice, off), ("%#x\n", off));
1393 AssertMsg(ASMBitTest(bmBridge, off), ("%#x\n", off));
1394 }
1395#endif
1396
1397 /*
1398 * Loop thru the fields covering the 64 bytes of standard registers.
1399 */
1400 uint8_t const fBridge = pciDevIsPci2PciBridge(pDev) ? 2 : 1;
1401 Assert(!pciDevIsPassthrough(pDev));
1402 uint8_t *pbDstConfig = &pDev->abConfig[0];
1403
1404 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1405 if (s_aFields[i].fBridge & fBridge)
1406 {
1407 uint8_t const off = s_aFields[i].off;
1408 uint8_t const cb = s_aFields[i].cb;
1409 uint32_t u32Src;
1410 uint32_t u32Dst;
1411 switch (cb)
1412 {
1413 case 1:
1414 u32Src = pbSrcConfig[off];
1415 u32Dst = pbDstConfig[off];
1416 break;
1417 case 2:
1418 u32Src = *(uint16_t const *)&pbSrcConfig[off];
1419 u32Dst = *(uint16_t const *)&pbDstConfig[off];
1420 break;
1421 case 4:
1422 u32Src = *(uint32_t const *)&pbSrcConfig[off];
1423 u32Dst = *(uint32_t const *)&pbDstConfig[off];
1424 break;
1425 default:
1426 AssertFailed();
1427 continue;
1428 }
1429
1430 if ( u32Src != u32Dst
1431 || off == VBOX_PCI_COMMAND)
1432 {
1433 if (u32Src != u32Dst)
1434 {
1435 if (!s_aFields[i].fWritable)
1436 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x - !READ ONLY!\n",
1437 pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1438 else
1439 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x\n",
1440 pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1441 }
1442 if (off == VBOX_PCI_COMMAND)
1443 /* safe, only needs to go to the config space array */
1444 PDMPciDevSetCommand(pDev, 0); /* For remapping, see pciR3CommonLoadExec/ich9pciR3CommonLoadExec. */
1445 devpciR3SetCfg(pDevIns, pDev, off, u32Src, cb);
1446 }
1447 }
1448
1449 /*
1450 * The device dependent registers.
1451 *
1452 * We will not use ConfigWrite here as we have no clue about the size
1453 * of the registers, so the device is responsible for correctly
1454 * restoring functionality governed by these registers.
1455 */
1456 for (uint32_t off = 0x40; off < sizeof(pDev->abConfig); off++)
1457 if (pbDstConfig[off] != pbSrcConfig[off])
1458 {
1459 LogRel(("PCI: %8s/%u: register %02x: %02x -> %02x\n",
1460 pDev->pszNameR3, pDev->Int.s.CTX_SUFF(pDevIns)->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
1461 pbDstConfig[off] = pbSrcConfig[off];
1462 }
1463}
1464
1465
1466/**
1467 * @callback_method_impl{FNPCIIOREGIONOLDSETTER}
1468 */
1469static DECLCALLBACK(int) devpciR3CommonRestoreOldSetRegion(PPDMPCIDEV pPciDev, uint32_t iRegion,
1470 RTGCPHYS cbRegion, PCIADDRESSSPACE enmType)
1471{
1472 AssertLogRelReturn(iRegion < RT_ELEMENTS(pPciDev->Int.s.aIORegions), VERR_INVALID_PARAMETER);
1473 pPciDev->Int.s.aIORegions[iRegion].type = enmType;
1474 pPciDev->Int.s.aIORegions[iRegion].size = cbRegion;
1475 return VINF_SUCCESS;
1476}
1477
1478
1479/**
1480 * @callback_method_impl{FNPCIIOREGIONSWAP}
1481 */
1482static DECLCALLBACK(int) devpciR3CommonRestoreSwapRegions(PPDMPCIDEV pPciDev, uint32_t iRegion, uint32_t iOtherRegion)
1483{
1484 AssertReturn(iRegion < iOtherRegion, VERR_INVALID_PARAMETER);
1485 AssertLogRelReturn(iOtherRegion < RT_ELEMENTS(pPciDev->Int.s.aIORegions), VERR_INVALID_PARAMETER);
1486 AssertReturn(pPciDev->Int.s.bPadding0 == (0xe0 | (uint8_t)iRegion), VERR_INVALID_PARAMETER);
1487
1488 PCIIOREGION Tmp = pPciDev->Int.s.aIORegions[iRegion];
1489 pPciDev->Int.s.aIORegions[iRegion] = pPciDev->Int.s.aIORegions[iOtherRegion];
1490 pPciDev->Int.s.aIORegions[iOtherRegion] = Tmp;
1491
1492 return VINF_SUCCESS;
1493}
1494
1495
1496/**
1497 * Checks for and deals with changes in resource sizes and types.
1498 *
1499 * @returns VBox status code.
1500 * @param pSSM The Saved state handle.
1501 * @param pPciDev The PCI device in question.
1502 * @param paIoRegions I/O regions with the size and type fields from
1503 * the saved state.
1504 * @param fNewState Set if this is a new state with I/O region sizes
1505 * and types, clear if old one.
1506 */
1507int devpciR3CommonRestoreRegions(PSSMHANDLE pSSM, PPDMPCIDEV pPciDev, PPCIIOREGION paIoRegions, bool fNewState)
1508{
1509 int rc;
1510 if (fNewState)
1511 {
1512 for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
1513 {
1514 if ( pPciDev->Int.s.aIORegions[iRegion].type != paIoRegions[iRegion].type
1515 || pPciDev->Int.s.aIORegions[iRegion].size != paIoRegions[iRegion].size)
1516 {
1517 AssertLogRelMsgFailed(("PCI: %8s/%u: region #%u size/type load change: %#RGp/%#x -> %#RGp/%#x\n",
1518 pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, iRegion,
1519 pPciDev->Int.s.aIORegions[iRegion].size, pPciDev->Int.s.aIORegions[iRegion].type,
1520 paIoRegions[iRegion].size, paIoRegions[iRegion].type));
1521 if (pPciDev->pfnRegionLoadChangeHookR3)
1522 {
1523 pPciDev->Int.s.bPadding0 = 0xe0 | (uint8_t)iRegion;
1524 rc = pPciDev->pfnRegionLoadChangeHookR3(pPciDev->Int.s.pDevInsR3, pPciDev, iRegion, paIoRegions[iRegion].size,
1525 (PCIADDRESSSPACE)paIoRegions[iRegion].type, NULL /*pfnOldSetter*/,
1526 devpciR3CommonRestoreSwapRegions);
1527 pPciDev->Int.s.bPadding0 = 0;
1528 if (RT_FAILURE(rc))
1529 return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS,
1530 N_("Device %s/%u failed to respond to region #%u size/type changing from %#RGp/%#x to %#RGp/%#x: %Rrc"),
1531 pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, iRegion,
1532 pPciDev->Int.s.aIORegions[iRegion].size, pPciDev->Int.s.aIORegions[iRegion].type,
1533 paIoRegions[iRegion].size, paIoRegions[iRegion].type, rc);
1534 }
1535 pPciDev->Int.s.aIORegions[iRegion].type = paIoRegions[iRegion].type;
1536 pPciDev->Int.s.aIORegions[iRegion].size = paIoRegions[iRegion].size;
1537 }
1538 }
1539 }
1540 /* Old saved state without sizes and types. Do a special hook call to give
1541 devices with changes a chance to adjust resources back to old values. */
1542 else if (pPciDev->pfnRegionLoadChangeHookR3)
1543 {
1544 rc = pPciDev->pfnRegionLoadChangeHookR3(pPciDev->Int.s.pDevInsR3, pPciDev, UINT32_MAX, RTGCPHYS_MAX, (PCIADDRESSSPACE)-1,
1545 devpciR3CommonRestoreOldSetRegion, NULL);
1546 if (RT_FAILURE(rc))
1547 return SSMR3SetLoadError(pSSM, rc, RT_SRC_POS, N_("Device %s/%u failed to resize its resources: %Rrc"),
1548 pPciDev->pszNameR3, pPciDev->Int.s.CTX_SUFF(pDevIns)->iInstance, rc);
1549 }
1550 return VINF_SUCCESS;
1551}
1552
1553
1554/**
1555 * Common worker for ich9pciR3LoadExec and ich9pcibridgeR3LoadExec.
1556 *
1557 * @returns VBox status code.
1558 * @param pDevIns The device instance of the bus.
1559 * @param pBus The bus which data is being loaded.
1560 * @param pSSM The saved state handle.
1561 * @param uVersion The data version.
1562 * @param uPass The pass.
1563 */
1564static int ich9pciR3CommonLoadExec(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1565{
1566 uint32_t u32;
1567 int rc;
1568
1569 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1570 if ( uVersion < VBOX_ICH9PCI_SAVED_STATE_VERSION_MSI
1571 || uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION)
1572 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1573
1574 /*
1575 * Iterate thru all the devices and write 0 to the COMMAND register so
1576 * that all the memory is unmapped before we start restoring the saved
1577 * mapping locations.
1578 *
1579 * The register value is restored afterwards so we can do proper
1580 * LogRels in devpciR3CommonRestoreConfig.
1581 */
1582 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
1583 {
1584 PPDMPCIDEV pDev = pBus->apDevices[uDevFn];
1585 if (pDev)
1586 {
1587 /* safe, only needs to go to the config space array */
1588 uint16_t u16 = PDMPciDevGetCommand(pDev);
1589 devpciR3SetCfg(pDevIns, pDev, VBOX_PCI_COMMAND, 0 /*u32Value*/, 2 /*cb*/);
1590 /* safe, only needs to go to the config space array */
1591 PDMPciDevSetCommand(pDev, u16);
1592 /* safe, only needs to go to the config space array */
1593 Assert(PDMPciDevGetCommand(pDev) == u16);
1594 }
1595 }
1596
1597 /*
1598 * Iterate all the devices.
1599 */
1600 for (uint32_t uDevFn = 0;; uDevFn++)
1601 {
1602 /* index / terminator */
1603 rc = SSMR3GetU32(pSSM, &u32);
1604 if (RT_FAILURE(rc))
1605 break;
1606 if (u32 == (uint32_t)~0)
1607 break;
1608 AssertLogRelMsgBreak(u32 < RT_ELEMENTS(pBus->apDevices) && u32 >= uDevFn, ("u32=%#x uDevFn=%#x\n", u32, uDevFn));
1609
1610 /* skip forward to the device checking that no new devices are present. */
1611 PPDMPCIDEV pDev;
1612 for (; uDevFn < u32; uDevFn++)
1613 {
1614 pDev = pBus->apDevices[uDevFn];
1615 if (pDev)
1616 {
1617 /* safe, only needs to go to the config space array */
1618 LogRel(("PCI: New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", uDevFn, pDev->pszNameR3,
1619 PDMPciDevGetVendorId(pDev), PDMPciDevGetDeviceId(pDev)));
1620 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1621 {
1622 /* safe, only needs to go to the config space array */
1623 rc = SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("New device in slot %#x, %s (vendor=%#06x device=%#06x)"),
1624 uDevFn, pDev->pszNameR3, PDMPciDevGetVendorId(pDev), PDMPciDevGetDeviceId(pDev));
1625 break;
1626 }
1627 }
1628 }
1629 if (RT_FAILURE(rc))
1630 break;
1631 pDev = pBus->apDevices[uDevFn];
1632
1633 /* get the data */
1634 union
1635 {
1636 PDMPCIDEV DevTmp;
1637 uint8_t abPadding[RT_UOFFSETOF(PDMPCIDEV, abMsixState) + _32K + _16K]; /* the MSI-X state shouldn't be much more than 32KB. */
1638 } u;
1639 RT_ZERO(u);
1640 u.DevTmp.Int.s.fFlags = 0;
1641 u.DevTmp.Int.s.u8MsiCapOffset = 0;
1642 u.DevTmp.Int.s.u8MsiCapSize = 0;
1643 u.DevTmp.Int.s.u8MsixCapOffset = 0;
1644 u.DevTmp.Int.s.u8MsixCapSize = 0;
1645 u.DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
1646 uint32_t cbConfig = 256;
1647 if (uVersion >= VBOX_ICH9PCI_SAVED_STATE_VERSION_4KB_CFG_SPACE)
1648 {
1649 rc = SSMR3GetU32(pSSM, &cbConfig);
1650 AssertRCReturn(rc, rc);
1651 if (cbConfig != 256 && cbConfig != _4K)
1652 return SSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
1653 "cbConfig=%#RX32, expected 0x100 or 0x1000", cbConfig);
1654 }
1655 SSMR3GetMem(pSSM, u.DevTmp.abConfig, cbConfig);
1656
1657 SSMR3GetU32(pSSM, &u.DevTmp.Int.s.fFlags);
1658 SSMR3GetS32(pSSM, &u.DevTmp.Int.s.uIrqPinState);
1659 SSMR3GetU8(pSSM, &u.DevTmp.Int.s.u8MsiCapOffset);
1660 SSMR3GetU8(pSSM, &u.DevTmp.Int.s.u8MsiCapSize);
1661 SSMR3GetU8(pSSM, &u.DevTmp.Int.s.u8MsixCapOffset);
1662 rc = SSMR3GetU8(pSSM, &u.DevTmp.Int.s.u8MsixCapSize);
1663 AssertRCReturn(rc, rc);
1664
1665 /* Load MSI-X page state */
1666 uint32_t cbMsixState = u.DevTmp.Int.s.u8MsixCapOffset != 0 ? _4K : 0;
1667 if (uVersion >= VBOX_ICH9PCI_SAVED_STATE_VERSION_4KB_CFG_SPACE)
1668 {
1669 rc = SSMR3GetU32(pSSM, &cbMsixState);
1670 AssertRCReturn(rc, rc);
1671 }
1672 if (cbMsixState)
1673 {
1674 if ( cbMsixState > (uint32_t)(pDev ? pDev->cbMsixState : _32K + _16K)
1675 || cbMsixState > sizeof(u) - RT_UOFFSETOF(PDMPCIDEV, abMsixState))
1676 return SSMR3SetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS,
1677 "cbMsixState=%#RX32, expected at most RT_MIN(%#x, %#zx)",
1678 cbMsixState, (pDev ? pDev->cbMsixState : _32K + _16K),
1679 sizeof(u) - RT_UOFFSETOF(PDMPCIDEV, abMsixState));
1680 rc = SSMR3GetMem(pSSM, u.DevTmp.abMsixState, cbMsixState);
1681 AssertRCReturn(rc, rc);
1682 }
1683
1684 /* Load the region types and sizes. */
1685 if (uVersion >= VBOX_ICH9PCI_SAVED_STATE_VERSION_REGION_SIZES)
1686 {
1687 for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
1688 {
1689 SSMR3GetU8(pSSM, &u.DevTmp.Int.s.aIORegions[iRegion].type);
1690 rc = SSMR3GetU64(pSSM, &u.DevTmp.Int.s.aIORegions[iRegion].size);
1691 AssertLogRelRCReturn(rc, rc);
1692 }
1693 }
1694
1695 /*
1696 * Check that it's still around.
1697 */
1698 pDev = pBus->apDevices[uDevFn];
1699 if (!pDev)
1700 {
1701 /* safe, only needs to go to the config space array */
1702 LogRel(("PCI: Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", uDevFn,
1703 PDMPciDevGetVendorId(&u.DevTmp), PDMPciDevGetDeviceId(&u.DevTmp)));
1704 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1705 {
1706 /* safe, only needs to go to the config space array */
1707 rc = SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x has been removed! vendor=%#06x device=%#06x"),
1708 uDevFn, PDMPciDevGetVendorId(&u.DevTmp), PDMPciDevGetDeviceId(&u.DevTmp));
1709 break;
1710 }
1711 continue;
1712 }
1713
1714 /* match the vendor id assuming that this will never be changed. */
1715 /* safe, only needs to go to the config space array */
1716 if (PDMPciDevGetVendorId(&u.DevTmp) != PDMPciDevGetVendorId(pDev))
1717 {
1718 /* safe, only needs to go to the config space array */
1719 rc = SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
1720 uDevFn, pDev->pszNameR3, PDMPciDevGetVendorId(&u.DevTmp), PDMPciDevGetVendorId(pDev));
1721 break;
1722 }
1723
1724 /* commit the loaded device config. */
1725 rc = devpciR3CommonRestoreRegions(pSSM, pDev, u.DevTmp.Int.s.aIORegions,
1726 uVersion >= VBOX_ICH9PCI_SAVED_STATE_VERSION_REGION_SIZES);
1727 if (RT_FAILURE(rc))
1728 break;
1729 Assert(!pciDevIsPassthrough(pDev));
1730 devpciR3CommonRestoreConfig(pDevIns, pDev, &u.DevTmp.abConfig[0]);
1731
1732 pDev->Int.s.uIrqPinState = u.DevTmp.Int.s.uIrqPinState;
1733 pDev->Int.s.u8MsiCapOffset = u.DevTmp.Int.s.u8MsiCapOffset;
1734 pDev->Int.s.u8MsiCapSize = u.DevTmp.Int.s.u8MsiCapSize;
1735 pDev->Int.s.u8MsixCapOffset = u.DevTmp.Int.s.u8MsixCapOffset;
1736 pDev->Int.s.u8MsixCapSize = u.DevTmp.Int.s.u8MsixCapSize;
1737 if (u.DevTmp.Int.s.u8MsixCapSize != 0) /** @todo r=bird: Why isn't this checkin u8MsixCapOffset??? */
1738 {
1739 Assert(pDev->Int.s.cbMsixRegion != 0);
1740 Assert(pDev->cbMsixState != 0);
1741 memcpy(pDev->abMsixState, u.DevTmp.abMsixState, RT_MIN(pDev->Int.s.cbMsixRegion, _32K + _16K));
1742 }
1743 }
1744
1745 return rc;
1746}
1747
1748static DECLCALLBACK(int) ich9pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1749{
1750 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
1751 PDEVPCIBUS pBus = &pThis->PciBus;
1752 uint32_t u32;
1753 int rc;
1754
1755 /* We ignore this version as there's no saved state with it anyway */
1756 if (uVersion <= VBOX_ICH9PCI_SAVED_STATE_VERSION_NOMSI)
1757 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1758 if (uVersion > VBOX_ICH9PCI_SAVED_STATE_VERSION)
1759 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1760
1761 /*
1762 * Bus state data.
1763 */
1764 SSMR3GetU32(pSSM, &pThis->uConfigReg);
1765
1766 /*
1767 * Load IRQ states.
1768 */
1769 for (unsigned i = 0; i < RT_ELEMENTS(pThis->auPciApicIrqLevels); i++)
1770 SSMR3GetU32V(pSSM, &pThis->auPciApicIrqLevels[i]);
1771
1772 /* separator */
1773 rc = SSMR3GetU32(pSSM, &u32);
1774 if (RT_FAILURE(rc))
1775 return rc;
1776 if (u32 != (uint32_t)~0)
1777 AssertMsgFailedReturn(("u32=%#x\n", u32), rc);
1778
1779 return ich9pciR3CommonLoadExec(pDevIns, pBus, pSSM, uVersion, uPass);
1780}
1781
1782static DECLCALLBACK(int) ich9pcibridgeR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1783{
1784 PDEVPCIBUS pThis = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1785 return ich9pciR3CommonLoadExec(pDevIns, pThis, pSSM, uVersion, uPass);
1786}
1787
1788
1789
1790/* -=-=-=-=-=- Fake PCI BIOS Init -=-=-=-=-=- */
1791
1792
1793void devpciR3BiosInitSetRegionAddress(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev, int iRegion, uint64_t addr)
1794{
1795 NOREF(pBus);
1796 uint32_t uReg = devpciGetRegionReg(iRegion);
1797
1798 /* Read memory type first. */
1799 uint8_t uResourceType = devpciR3GetByte(pPciDev, uReg);
1800 bool f64Bit = (uResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
1801 == PCI_ADDRESS_SPACE_BAR64;
1802
1803 Log(("Set region address: %02x:%02x.%d region %d address=%RX64%s\n",
1804 pBus->iBus, pPciDev->uDevFn >> 3, pPciDev->uDevFn & 7, iRegion, addr, f64Bit ? " (64-bit)" : ""));
1805
1806 /* Write address of the device. */
1807 devpciR3SetDWord(pDevIns, pPciDev, uReg, (uint32_t)addr);
1808 if (f64Bit)
1809 devpciR3SetDWord(pDevIns, pPciDev, uReg + 4, (uint32_t)(addr >> 32));
1810}
1811
1812
1813static void ich9pciBiosInitBridge(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus)
1814{
1815 PPDMPCIDEV pBridge = pDevIns->apPciDevs[0];
1816 Log(("BIOS init bridge: %02x:%02x.%d\n", pBus->iBus, pBridge->uDevFn >> 3, pBridge->uDevFn & 7));
1817
1818 /*
1819 * The I/O range for the bridge must be aligned to a 4KB boundary.
1820 * This does not change anything really as the access to the device is not going
1821 * through the bridge but we want to be compliant to the spec.
1822 */
1823 if ((pPciRoot->uPciBiosIo % _4K) != 0)
1824 {
1825 pPciRoot->uPciBiosIo = RT_ALIGN_32(pPciRoot->uPciBiosIo, _4K);
1826 LogFunc(("Aligned I/O start address. New address %#x\n", pPciRoot->uPciBiosIo));
1827 }
1828 devpciR3SetByte(pDevIns, pBridge, VBOX_PCI_IO_BASE, (pPciRoot->uPciBiosIo >> 8) & 0xf0);
1829
1830 /* The MMIO range for the bridge must be aligned to a 1MB boundary. */
1831 if ((pPciRoot->uPciBiosMmio % _1M) != 0)
1832 {
1833 pPciRoot->uPciBiosMmio = RT_ALIGN_32(pPciRoot->uPciBiosMmio, _1M);
1834 LogFunc(("Aligned MMIO start address. New address %#x\n", pPciRoot->uPciBiosMmio));
1835 }
1836 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_MEMORY_BASE, (pPciRoot->uPciBiosMmio >> 16) & UINT32_C(0xffff0));
1837
1838 /* Save values to compare later to. */
1839 uint32_t u32IoAddressBase = pPciRoot->uPciBiosIo;
1840 uint32_t u32MMIOAddressBase = pPciRoot->uPciBiosMmio;
1841
1842 /* Init all devices behind the bridge (recursing to further buses). */
1843 ich9pciBiosInitAllDevicesOnBus(pDevIns, pPciRoot, pBus);
1844
1845 /*
1846 * Set I/O limit register. If there is no device with I/O space behind the
1847 * bridge we set a lower value than in the base register.
1848 */
1849 if (u32IoAddressBase != pPciRoot->uPciBiosIo)
1850 {
1851 /* Need again alignment to a 4KB boundary. */
1852 pPciRoot->uPciBiosIo = RT_ALIGN_32(pPciRoot->uPciBiosIo, _4K);
1853 devpciR3SetByte(pDevIns, pBridge, VBOX_PCI_IO_LIMIT, ((pPciRoot->uPciBiosIo - 1) >> 8) & 0xf0);
1854 }
1855 else
1856 {
1857 devpciR3SetByte(pDevIns, pBridge, VBOX_PCI_IO_BASE, 0xf0);
1858 devpciR3SetByte(pDevIns, pBridge, VBOX_PCI_IO_LIMIT, 0x00);
1859 }
1860
1861 /* Same with the MMIO limit register but with 1MB boundary here. */
1862 if (u32MMIOAddressBase != pPciRoot->uPciBiosMmio)
1863 {
1864 pPciRoot->uPciBiosMmio = RT_ALIGN_32(pPciRoot->uPciBiosMmio, _1M);
1865 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_MEMORY_LIMIT, ((pPciRoot->uPciBiosMmio - 1) >> 16) & UINT32_C(0xfff0));
1866 }
1867 else
1868 {
1869 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_MEMORY_BASE, 0xfff0);
1870 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_MEMORY_LIMIT, 0x0000);
1871 }
1872
1873 /*
1874 * Set the prefetch base and limit registers. We currently have no device with a prefetchable region
1875 * which may be behind a bridge. That's why it is unconditionally disabled here atm by writing a higher value into
1876 * the base register than in the limit register.
1877 */
1878 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_PREF_MEMORY_BASE, 0xfff0);
1879 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_PREF_MEMORY_LIMIT, 0x0000);
1880 devpciR3SetDWord(pDevIns, pBridge, VBOX_PCI_PREF_BASE_UPPER32, 0x00000000);
1881 devpciR3SetDWord(pDevIns, pBridge, VBOX_PCI_PREF_LIMIT_UPPER32, 0x00000000);
1882}
1883
1884static int ich9pciBiosInitDeviceGetRegions(PPDMPCIDEV pPciDev)
1885{
1886 uint8_t uHeaderType = devpciR3GetByte(pPciDev, VBOX_PCI_HEADER_TYPE) & 0x7f;
1887 if (uHeaderType == 0x00)
1888 /* Ignore ROM region here, which is included in VBOX_PCI_NUM_REGIONS. */
1889 return VBOX_PCI_NUM_REGIONS - 1;
1890 else if (uHeaderType == 0x01)
1891 /* PCI bridges have 2 BARs. */
1892 return 2;
1893 else
1894 {
1895 AssertMsgFailed(("invalid header type %#x\n", uHeaderType));
1896 return 0;
1897 }
1898}
1899
1900static void ich9pciBiosInitDeviceBARs(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev)
1901{
1902 int cRegions = ich9pciBiosInitDeviceGetRegions(pPciDev);
1903 bool fSuppressMem = false;
1904 bool fActiveMemRegion = false;
1905 bool fActiveIORegion = false;
1906 for (int iRegion = 0; iRegion < cRegions; iRegion++)
1907 {
1908 uint32_t u32Address = devpciGetRegionReg(iRegion);
1909
1910 /* Calculate size - we write all 1s into the BAR, and then evaluate which bits
1911 are cleared. */
1912 uint8_t u8ResourceType = devpciR3GetByte(pPciDev, u32Address);
1913
1914 bool fPrefetch = (u8ResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_IO)))
1915 == PCI_ADDRESS_SPACE_MEM_PREFETCH;
1916 bool f64Bit = (u8ResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
1917 == PCI_ADDRESS_SPACE_BAR64;
1918 bool fIsPio = ((u8ResourceType & PCI_ADDRESS_SPACE_IO) == PCI_ADDRESS_SPACE_IO);
1919 uint64_t cbRegSize64 = 0;
1920
1921 /* Hack: initialize prefetchable BARs for devices on the root bus
1922 * early, but for all other prefetchable BARs do it after the
1923 * non-prefetchable BARs are initialized on all buses. */
1924 if (fPrefetch && pBus->iBus != 0)
1925 {
1926 fSuppressMem = true;
1927 if (f64Bit)
1928 iRegion++; /* skip next region */
1929 continue;
1930 }
1931
1932 if (f64Bit)
1933 {
1934 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0xffffffff));
1935 devpciR3SetDWord(pDevIns, pPciDev, u32Address+4, UINT32_C(0xffffffff));
1936 cbRegSize64 = RT_MAKE_U64(devpciR3GetDWord(pPciDev, u32Address),
1937 devpciR3GetDWord(pPciDev, u32Address+4));
1938 cbRegSize64 &= ~UINT64_C(0x0f);
1939 cbRegSize64 = (~cbRegSize64) + 1;
1940
1941 /* No 64-bit PIO regions possible. */
1942#ifndef DEBUG_bird /* EFI triggers this for DevAHCI. */
1943 AssertMsg((u8ResourceType & PCI_ADDRESS_SPACE_IO) == 0, ("type=%#x rgn=%d\n", u8ResourceType, iRegion));
1944#endif
1945 }
1946 else
1947 {
1948 uint32_t cbRegSize32;
1949 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0xffffffff));
1950 cbRegSize32 = devpciR3GetDWord(pPciDev, u32Address);
1951
1952 /* Clear resource information depending on resource type. */
1953 if (fIsPio) /* PIO */
1954 cbRegSize32 &= ~UINT32_C(0x01);
1955 else /* MMIO */
1956 cbRegSize32 &= ~UINT32_C(0x0f);
1957
1958 /*
1959 * Invert all bits and add 1 to get size of the region.
1960 * (From PCI implementation note)
1961 */
1962 if (fIsPio && (cbRegSize32 & UINT32_C(0xffff0000)) == 0)
1963 cbRegSize32 = (~(cbRegSize32 | UINT32_C(0xffff0000))) + 1;
1964 else
1965 cbRegSize32 = (~cbRegSize32) + 1;
1966
1967 cbRegSize64 = cbRegSize32;
1968 }
1969 Log2Func(("Size of region %u for device %d on bus %d is %lld\n", iRegion, pPciDev->uDevFn, pBus->iBus, cbRegSize64));
1970
1971 if (cbRegSize64)
1972 {
1973 /* Try 32-bit base first. */
1974 uint32_t* paddr = fIsPio ? &pPciRoot->uPciBiosIo : &pPciRoot->uPciBiosMmio;
1975 uint64_t uNew = *paddr;
1976 /* Align starting address to region size. */
1977 uNew = (uNew + cbRegSize64 - 1) & ~(cbRegSize64 - 1);
1978 if (fIsPio)
1979 uNew &= UINT32_C(0xffff);
1980 /* Unconditionally exclude I/O-APIC/HPET/ROM. Pessimistic, but better than causing a mess. */
1981 if ( !uNew
1982 || (uNew <= UINT32_C(0xffffffff) && uNew + cbRegSize64 - 1 >= UINT32_C(0xfec00000))
1983 || uNew >= _4G)
1984 {
1985 /* Only prefetchable regions can be placed above 4GB, as the
1986 * address decoder for non-prefetchable addresses in bridges
1987 * is limited to 32 bits. */
1988 if (f64Bit && fPrefetch)
1989 {
1990 /* Map a 64-bit region above 4GB. */
1991 Assert(!fIsPio);
1992 uNew = pPciRoot->uPciBiosMmio64;
1993 /* Align starting address to region size. */
1994 uNew = (uNew + cbRegSize64 - 1) & ~(cbRegSize64 - 1);
1995 LogFunc(("Start address of 64-bit MMIO region %u/%u is %#llx\n", iRegion, iRegion + 1, uNew));
1996 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, iRegion, uNew);
1997 fActiveMemRegion = true;
1998 pPciRoot->uPciBiosMmio64 = uNew + cbRegSize64;
1999 Log2Func(("New 64-bit address is %#llx\n", pPciRoot->uPciBiosMmio64));
2000 }
2001 else
2002 {
2003 uint16_t uVendor = devpciR3GetWord(pPciDev, VBOX_PCI_VENDOR_ID);
2004 uint16_t uDevice = devpciR3GetWord(pPciDev, VBOX_PCI_DEVICE_ID);
2005 LogRel(("PCI: no space left for BAR%u of device %u/%u/%u (vendor=%#06x device=%#06x)\n",
2006 iRegion, pBus->iBus, pPciDev->uDevFn >> 3, pPciDev->uDevFn & 7, uVendor, uDevice)); /** @todo make this a VM start failure later. */
2007 /* Undo the mapping mess caused by the size probing. */
2008 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0));
2009 }
2010 }
2011 else
2012 {
2013 LogFunc(("Start address of %s region %u is %#x\n", (fIsPio ? "I/O" : "MMIO"), iRegion, uNew));
2014 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, iRegion, uNew);
2015 if (fIsPio)
2016 fActiveIORegion = true;
2017 else
2018 fActiveMemRegion = true;
2019 *paddr = uNew + cbRegSize64;
2020 Log2Func(("New 32-bit address is %#x\n", *paddr));
2021 }
2022
2023 if (f64Bit)
2024 iRegion++; /* skip next region */
2025 }
2026 }
2027
2028 /* Update the command word appropriately. */
2029 uint16_t uCmd = devpciR3GetWord(pPciDev, VBOX_PCI_COMMAND);
2030 if (fActiveMemRegion && !fSuppressMem)
2031 uCmd |= VBOX_PCI_COMMAND_MEMORY; /* Enable MMIO access. */
2032 if (fActiveIORegion)
2033 uCmd |= VBOX_PCI_COMMAND_IO; /* Enable I/O space access. */
2034 devpciR3SetWord(pDevIns, pPciDev, VBOX_PCI_COMMAND, uCmd);
2035}
2036
2037static bool ich9pciBiosInitDevicePrefetchableBARs(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev, bool fUse64Bit, bool fDryrun)
2038{
2039 int cRegions = ich9pciBiosInitDeviceGetRegions(pPciDev);
2040 bool fActiveMemRegion = false;
2041 for (int iRegion = 0; iRegion < cRegions; iRegion++)
2042 {
2043 uint32_t u32Address = devpciGetRegionReg(iRegion);
2044 uint8_t u8ResourceType = devpciR3GetByte(pPciDev, u32Address);
2045 bool fPrefetch = (u8ResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_MEM_PREFETCH | PCI_ADDRESS_SPACE_IO)))
2046 == PCI_ADDRESS_SPACE_MEM_PREFETCH;
2047 bool f64Bit = (u8ResourceType & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
2048 == PCI_ADDRESS_SPACE_BAR64;
2049 uint64_t cbRegSize64 = 0;
2050
2051 /* Everything besides prefetchable regions has been set up already. */
2052 if (!fPrefetch)
2053 continue;
2054
2055 if (f64Bit)
2056 {
2057 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0xffffffff));
2058 devpciR3SetDWord(pDevIns, pPciDev, u32Address+4, UINT32_C(0xffffffff));
2059 cbRegSize64 = RT_MAKE_U64(devpciR3GetDWord(pPciDev, u32Address),
2060 devpciR3GetDWord(pPciDev, u32Address+4));
2061 cbRegSize64 &= ~UINT64_C(0x0f);
2062 cbRegSize64 = (~cbRegSize64) + 1;
2063 }
2064 else
2065 {
2066 uint32_t cbRegSize32;
2067 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0xffffffff));
2068 cbRegSize32 = devpciR3GetDWord(pPciDev, u32Address);
2069 cbRegSize32 &= ~UINT32_C(0x0f);
2070 cbRegSize32 = (~cbRegSize32) + 1;
2071
2072 cbRegSize64 = cbRegSize32;
2073 }
2074 Log2Func(("Size of region %u for device %d on bus %d is %lld\n", iRegion, pPciDev->uDevFn, pBus->iBus, cbRegSize64));
2075
2076 if (cbRegSize64)
2077 {
2078 uint64_t uNew;
2079 if (!fUse64Bit)
2080 {
2081 uNew = pPciRoot->uPciBiosMmio;
2082 /* Align starting address to region size. */
2083 uNew = (uNew + cbRegSize64 - 1) & ~(cbRegSize64 - 1);
2084 /* Unconditionally exclude I/O-APIC/HPET/ROM. Pessimistic, but better than causing a mess. Okay for BIOS. */
2085 if ( !uNew
2086 || (uNew <= UINT32_C(0xffffffff) && uNew + cbRegSize64 - 1 >= UINT32_C(0xfec00000))
2087 || uNew >= _4G)
2088 {
2089 Log2Func(("region #%u: Rejecting address range: %#x LB %#RX64\n", iRegion, uNew, cbRegSize64));
2090 Assert(fDryrun);
2091 return true;
2092 }
2093 if (!fDryrun)
2094 {
2095 LogFunc(("Start address of MMIO region %u is %#x\n", iRegion, uNew));
2096 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, iRegion, uNew);
2097 fActiveMemRegion = true;
2098 }
2099 pPciRoot->uPciBiosMmio = uNew + cbRegSize64;
2100 }
2101 else
2102 {
2103 /* Can't handle 32-bit BARs when forcing 64-bit allocs. */
2104 if (!f64Bit)
2105 {
2106 Assert(fDryrun);
2107 return true;
2108 }
2109 uNew = pPciRoot->uPciBiosMmio64;
2110 /* Align starting address to region size. */
2111 uNew = (uNew + cbRegSize64 - 1) & ~(cbRegSize64 - 1);
2112 pPciRoot->uPciBiosMmio64 = uNew + cbRegSize64;
2113 if (!fDryrun)
2114 {
2115 LogFunc(("Start address of 64-bit MMIO region %u/%u is %#llx\n", iRegion, iRegion + 1, uNew));
2116 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, iRegion, uNew);
2117 fActiveMemRegion = true;
2118 }
2119 }
2120
2121 if (f64Bit)
2122 iRegion++; /* skip next region */
2123 }
2124 }
2125
2126 if (!fDryrun)
2127 {
2128 /* Update the command word appropriately. */
2129 uint16_t uCmd = devpciR3GetWord(pPciDev, VBOX_PCI_COMMAND);
2130 if (fActiveMemRegion)
2131 uCmd |= VBOX_PCI_COMMAND_MEMORY; /* Enable MMIO access. */
2132 devpciR3SetWord(pDevIns, pPciDev, VBOX_PCI_COMMAND, uCmd);
2133 }
2134 else
2135 Assert(!fActiveMemRegion);
2136
2137 return false;
2138}
2139
2140static bool ich9pciBiosInitBridgePrefetchable(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus, bool fUse64Bit, bool fDryrun)
2141{
2142 PPDMPCIDEV pBridge = pDevIns->apPciDevs[0];
2143 Log(("BIOS init bridge (prefetch): %02x:%02x.%d use64bit=%d dryrun=%d\n", pBus->iBus, pBridge->uDevFn >> 3, pBridge->uDevFn & 7, fUse64Bit, fDryrun));
2144
2145 pPciRoot->uPciBiosMmio = RT_ALIGN_32(pPciRoot->uPciBiosMmio, _1M);
2146 pPciRoot->uPciBiosMmio64 = RT_ALIGN_64(pPciRoot->uPciBiosMmio64, _1M);
2147
2148 /* Save values to compare later to. */
2149 uint32_t u32MMIOAddressBase = pPciRoot->uPciBiosMmio;
2150 uint64_t u64MMIOAddressBase = pPciRoot->uPciBiosMmio64;
2151
2152 /* Init all devices behind the bridge (recursing to further buses). */
2153 bool fRes = ich9pciBiosInitAllDevicesPrefetchableOnBus(pDevIns, pPciRoot, pBus, fUse64Bit, fDryrun);
2154 if (fDryrun)
2155 return fRes;
2156 Assert(!fRes);
2157
2158 /* Set prefetchable MMIO limit register with 1MB boundary. */
2159 uint64_t uBase, uLimit;
2160 if (fUse64Bit)
2161 {
2162 if (u64MMIOAddressBase == pPciRoot->uPciBiosMmio64)
2163 return false;
2164 uBase = u64MMIOAddressBase;
2165 uLimit = RT_ALIGN_64(pPciRoot->uPciBiosMmio64, _1M) - 1;
2166 }
2167 else
2168 {
2169 if (u32MMIOAddressBase == pPciRoot->uPciBiosMmio)
2170 return false;
2171 uBase = u32MMIOAddressBase;
2172 uLimit = RT_ALIGN_32(pPciRoot->uPciBiosMmio, _1M) - 1;
2173 }
2174 devpciR3SetDWord(pDevIns, pBridge, VBOX_PCI_PREF_BASE_UPPER32, uBase >> 32);
2175 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_PREF_MEMORY_BASE, (uint32_t)(uBase >> 16) & UINT32_C(0xfff0));
2176 devpciR3SetDWord(pDevIns, pBridge, VBOX_PCI_PREF_LIMIT_UPPER32, uLimit >> 32);
2177 devpciR3SetWord(pDevIns, pBridge, VBOX_PCI_PREF_MEMORY_LIMIT, (uint32_t)(uLimit >> 16) & UINT32_C(0xfff0));
2178
2179 return false;
2180}
2181
2182static bool ich9pciBiosInitAllDevicesPrefetchableOnBus(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus,
2183 bool fUse64Bit, bool fDryrun)
2184{
2185 /* First pass: assign resources to all devices. */
2186 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
2187 {
2188 PPDMPCIDEV pPciDev = pBus->apDevices[uDevFn];
2189
2190 /* check if device is present */
2191 if (!pPciDev)
2192 continue;
2193
2194 Log(("BIOS init device (prefetch): %02x:%02x.%d\n", pBus->iBus, uDevFn >> 3, uDevFn & 7));
2195
2196 /* prefetchable memory mappings */
2197 bool fRes = ich9pciBiosInitDevicePrefetchableBARs(pDevIns, pPciRoot, pBus, pPciDev, fUse64Bit, fDryrun);
2198 if (fRes)
2199 {
2200 Assert(fDryrun);
2201 return fRes;
2202 }
2203 }
2204
2205 /* Second pass: handle bridges recursively. */
2206 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2207 {
2208 PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
2209 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
2210 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
2211 PDEVPCIBUS pChildBus = PDMINS_2_DATA(pBridge->Int.s.CTX_SUFF(pDevIns), PDEVPCIBUS);
2212
2213 bool fRes = ich9pciBiosInitBridgePrefetchable(pDevIns, pPciRoot, pChildBus, fUse64Bit, fDryrun);
2214 if (fRes)
2215 {
2216 Assert(fDryrun);
2217 return fRes;
2218 }
2219 }
2220 return false;
2221}
2222
2223static void ich9pciBiosInitAllDevicesOnBus(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus)
2224{
2225 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
2226
2227 /* First pass: assign resources to all devices and map the interrupt. */
2228 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
2229 {
2230 PPDMPCIDEV pPciDev = pBus->apDevices[uDevFn];
2231
2232 /* check if device is present */
2233 if (!pPciDev)
2234 continue;
2235
2236 Log(("BIOS init device: %02x:%02x.%d\n", pBus->iBus, uDevFn >> 3, uDevFn & 7));
2237
2238 /* default memory mappings */
2239 ich9pciBiosInitDeviceBARs(pDevIns, pPciRoot, pBus, pPciDev);
2240 uint16_t uDevClass = devpciR3GetWord(pPciDev, VBOX_PCI_CLASS_DEVICE);
2241 switch (uDevClass)
2242 {
2243 case 0x0101:
2244 /* IDE controller */
2245 devpciR3SetWord(pDevIns, pPciDev, 0x40, 0x8000); /* enable IDE0 */
2246 devpciR3SetWord(pDevIns, pPciDev, 0x42, 0x8000); /* enable IDE1 */
2247 break;
2248 case 0x0300:
2249 {
2250 /* VGA controller */
2251
2252 /* NB: Default Bochs VGA LFB address is 0xE0000000. Old guest
2253 * software may break if the framebuffer isn't mapped there.
2254 */
2255
2256 /*
2257 * Legacy VGA I/O ports are implicitly decoded by a VGA class device. But
2258 * only the framebuffer (i.e., a memory region) is explicitly registered via
2259 * ich9pciSetRegionAddress, so don't forget to enable I/O decoding.
2260 */
2261 uint16_t uCmd = devpciR3GetWord(pPciDev, VBOX_PCI_COMMAND);
2262 devpciR3SetWord(pDevIns, pPciDev, VBOX_PCI_COMMAND, uCmd | VBOX_PCI_COMMAND_IO);
2263 break;
2264 }
2265 default:
2266 break;
2267 }
2268
2269 /* map the interrupt */
2270 uint8_t iPin = devpciR3GetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN);
2271 if (iPin != 0)
2272 {
2273 iPin--;
2274
2275 /* We need to go up to the host bus to see which irq pin this
2276 device will use there. See logic in ich9pcibridgeSetIrq(). */
2277 uint32_t idxPdmParentBus;
2278 PPDMDEVINS pDevInsParent = pDevIns;
2279 while ((idxPdmParentBus = pDevInsParent->apPciDevs[0]->Int.s.idxPdmBus) != 0)
2280 {
2281 /* Get the pin the device would assert on the bridge. */
2282 iPin = ((pDevInsParent->apPciDevs[0]->uDevFn >> 3) + iPin) & 3;
2283
2284 pDevInsParent = pBusCC->pPciHlpR3->pfnGetBusByNo(pDevIns, idxPdmParentBus);
2285 AssertLogRelBreak(pDevInsParent);
2286 }
2287
2288 int iIrq = aPciIrqs[ich9pciSlotGetPirq(pBus->iBus, uDevFn, iPin)];
2289 Log(("Using pin %d and IRQ %d for device %02x:%02x.%d\n",
2290 iPin, iIrq, pBus->iBus, uDevFn>>3, uDevFn&7));
2291 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_INTERRUPT_LINE, iIrq);
2292 }
2293 }
2294
2295 /* Second pass: handle bridges recursively. */
2296 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2297 {
2298 PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
2299 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
2300 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
2301 PDEVPCIBUS pChildBus = PDMINS_2_DATA(pBridge->Int.s.CTX_SUFF(pDevIns), PDEVPCIBUS);
2302
2303 ich9pciBiosInitBridge(pDevIns, pPciRoot, pChildBus);
2304 }
2305
2306 /* Third pass (only for bus 0): set up prefetchable BARs recursively. */
2307 if (pBus->iBus == 0)
2308 {
2309 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2310 {
2311 PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
2312 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
2313 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
2314 PDEVPCIBUS pChildBus = PDMINS_2_DATA(pBridge->Int.s.CTX_SUFF(pDevIns), PDEVPCIBUS);
2315
2316 Log(("BIOS init prefetchable memory behind bridge: %02x:%02x.%d\n", pChildBus->iBus, pBridge->uDevFn >> 3, pBridge->uDevFn & 7));
2317 /* Save values for the prefetchable dryruns. */
2318 uint32_t u32MMIOAddressBase = pPciRoot->uPciBiosMmio;
2319 uint64_t u64MMIOAddressBase = pPciRoot->uPciBiosMmio64;
2320
2321 bool fProbe = ich9pciBiosInitBridgePrefetchable(pDevIns, pPciRoot, pChildBus, false /* fUse64Bit */, true /* fDryrun */);
2322 pPciRoot->uPciBiosMmio = u32MMIOAddressBase;
2323 pPciRoot->uPciBiosMmio64 = u64MMIOAddressBase;
2324 if (fProbe)
2325 {
2326 fProbe = ich9pciBiosInitBridgePrefetchable(pDevIns, pPciRoot, pChildBus, true /* fUse64Bit */, true /* fDryrun */);
2327 pPciRoot->uPciBiosMmio = u32MMIOAddressBase;
2328 pPciRoot->uPciBiosMmio64 = u64MMIOAddressBase;
2329 if (fProbe)
2330 LogRel(("PCI: unresolvable prefetchable memory behind bridge %02x:%02x.%d\n", pChildBus->iBus, pBridge->uDevFn >> 3, pBridge->uDevFn & 7));
2331 else
2332 ich9pciBiosInitBridgePrefetchable(pDevIns, pPciRoot, pChildBus, true /* fUse64Bit */, false /* fDryrun */);
2333 }
2334 else
2335 ich9pciBiosInitBridgePrefetchable(pDevIns, pPciRoot, pChildBus, false /* fUse64Bit */, false /* fDryrun */);
2336 }
2337 }
2338}
2339
2340/**
2341 * Initializes bridges registers used for routing.
2342 *
2343 * We ASSUME PDM bus assignments are the same as the PCI bus assignments and
2344 * will complain if we find any conflicts. This because it is just soo much
2345 * simpler to have the two numbers match one another by default.
2346 *
2347 * @returns Max subordinate bus number.
2348 * @param pDevIns The device instance of the bus.
2349 * @param pPciRoot Global device instance data used to generate unique bus numbers.
2350 * @param pBus The PCI bus to initialize.
2351 * @param pbmUsed Pointer to a 32-bit bitmap tracking which device
2352 * (ranges) has been used.
2353 * @param uBusPrimary The primary bus number the bus is connected to.
2354 */
2355static uint8_t ich9pciBiosInitBridgeTopology(PPDMDEVINS pDevIns, PDEVPCIROOT pPciRoot, PDEVPCIBUS pBus,
2356 uint32_t *pbmUsed, uint8_t uBusPrimary)
2357{
2358 PPDMPCIDEV pBridgeDev = pDevIns->apPciDevs[0];
2359
2360 /* Check if the PDM bus assignment makes sense. */
2361 AssertLogRelMsg(!(*pbmUsed & RT_BIT_32(pBus->iBus)),
2362 ("PCIBIOS: Bad PCI bridge config! Conflict for bus %#x. Make sure to instantiate bridges for a sub-trees in sequence!\n",
2363 pBus->iBus));
2364 *pbmUsed |= RT_BIT_32(pBus->iBus);
2365
2366 /* Set only if we are not on the root bus, it has no primary bus attached. */
2367 if (pBus->iBus != 0)
2368 {
2369 devpciR3SetByte(pDevIns, pBridgeDev, VBOX_PCI_PRIMARY_BUS, uBusPrimary);
2370 devpciR3SetByte(pDevIns, pBridgeDev, VBOX_PCI_SECONDARY_BUS, pBus->iBus);
2371 /* Since the subordinate bus value can only be finalized once we
2372 * finished recursing through everything behind the bridge, the only
2373 * solution is temporarily configuring the subordinate to the maximum
2374 * possible value. This makes sure that the config space accesses work
2375 * (for our own sloppy emulation it apparently doesn't matter, but
2376 * this is vital for real PCI bridges/devices in passthrough mode). */
2377 devpciR3SetByte(pDevIns, pBridgeDev, VBOX_PCI_SUBORDINATE_BUS, 0xff);
2378 }
2379
2380 uint8_t uMaxSubNum = pBus->iBus;
2381 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2382 {
2383 PPDMPCIDEV pBridge = pBus->papBridgesR3[iBridge];
2384 AssertMsg(pBridge && pciDevIsPci2PciBridge(pBridge),
2385 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
2386 PDEVPCIBUS pChildBus = PDMINS_2_DATA(pBridge->Int.s.CTX_SUFF(pDevIns), PDEVPCIBUS);
2387 uint8_t uMaxChildSubBus = ich9pciBiosInitBridgeTopology(pDevIns, pPciRoot, pChildBus, pbmUsed, pBus->iBus);
2388 uMaxSubNum = RT_MAX(uMaxSubNum, uMaxChildSubBus);
2389 }
2390
2391 if (pBus->iBus != 0)
2392 devpciR3SetByte(pDevIns, pBridgeDev, VBOX_PCI_SUBORDINATE_BUS, uMaxSubNum);
2393 for (uint32_t i = pBus->iBus; i <= uMaxSubNum; i++)
2394 *pbmUsed |= RT_BIT_32(i);
2395
2396 /* Make sure that transactions are able to get through the bridge. Not
2397 * strictly speaking necessary this early (before any device is set up),
2398 * but on the other hand it can't hurt either. */
2399 if (pBus->iBus != 0)
2400 devpciR3SetWord(pDevIns, pBridgeDev, VBOX_PCI_COMMAND,
2401 VBOX_PCI_COMMAND_IO
2402 | VBOX_PCI_COMMAND_MEMORY
2403 | VBOX_PCI_COMMAND_MASTER);
2404
2405 /* safe, only needs to go to the config space array */
2406 Log2Func(("for bus %p: primary=%d secondary=%d subordinate=%d\n", pBus,
2407 PDMPciDevGetByte(pBridgeDev, VBOX_PCI_PRIMARY_BUS),
2408 PDMPciDevGetByte(pBridgeDev, VBOX_PCI_SECONDARY_BUS),
2409 PDMPciDevGetByte(pBridgeDev, VBOX_PCI_SUBORDINATE_BUS) ));
2410
2411 return uMaxSubNum;
2412}
2413
2414
2415/**
2416 * Worker for Fake PCI BIOS config
2417 *
2418 * @returns VBox status code.
2419 *
2420 * @param pDevIns ICH9 device instance.
2421 */
2422static int ich9pciFakePCIBIOS(PPDMDEVINS pDevIns)
2423{
2424 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
2425 PVM pVM = PDMDevHlpGetVM(pDevIns);
2426 uint32_t const cbBelow4GB = MMR3PhysGetRamSizeBelow4GB(pVM);
2427 uint64_t const cbAbove4GB = MMR3PhysGetRamSizeAbove4GB(pVM);
2428
2429 LogRel(("PCI: setting up topology, resources and interrupts\n"));
2430
2431 /** @todo r=klaus this needs to do the same elcr magic as DevPCI.cpp, as the BIOS can't be trusted to do the right thing. Of course it's more difficult than with the old code, as there are bridges to be handled. The interrupt routing needs to be taken into account. Also I highly suspect that the chipset has 8 interrupt lines which we might be able to use for handling things on the root bus better (by treating them as devices on the mainboard). */
2432
2433 /*
2434 * Set the start addresses.
2435 */
2436 pPciRoot->uPciBiosBus = 0;
2437 pPciRoot->uPciBiosIo = 0xd000;
2438 pPciRoot->uPciBiosMmio = cbBelow4GB;
2439 pPciRoot->uPciBiosMmio64 = cbAbove4GB + _4G;
2440
2441 /* NB: Assume that if PCI controller MMIO range is enabled, it is below the beginning of the memory hole. */
2442 if (pPciRoot->u64PciConfigMMioAddress)
2443 {
2444 AssertRelease(pPciRoot->u64PciConfigMMioAddress >= cbBelow4GB);
2445 pPciRoot->uPciBiosMmio = pPciRoot->u64PciConfigMMioAddress + pPciRoot->u64PciConfigMMioLength;
2446 }
2447 Log(("cbBelow4GB: %#RX32, uPciBiosMmio: %#RX64, cbAbove4GB: %#RX64, uPciBiosMmio64=%#RX64\n",
2448 cbBelow4GB, pPciRoot->uPciBiosMmio, cbAbove4GB, pPciRoot->uPciBiosMmio64));
2449
2450 /*
2451 * Assign bridge topology, for further routing to work.
2452 */
2453 PDEVPCIBUS pBus = &pPciRoot->PciBus;
2454 AssertLogRel(pBus->iBus == 0);
2455 uint32_t bmUsed = 0;
2456 ich9pciBiosInitBridgeTopology(pDevIns, pPciRoot, pBus, &bmUsed, 0);
2457
2458 /*
2459 * Init all devices on bus 0 (recursing to further buses).
2460 */
2461 ich9pciBiosInitAllDevicesOnBus(pDevIns, pPciRoot, pBus);
2462
2463 return VINF_SUCCESS;
2464}
2465
2466
2467/* -=-=-=-=-=- PCI Config Space -=-=-=-=-=- */
2468
2469
2470/**
2471 * Reads config space for a device, ignoring interceptors.
2472 */
2473DECLHIDDEN(VBOXSTRICTRC) devpciR3CommonConfigReadWorker(PPDMPCIDEV pPciDev, uint32_t uAddress, unsigned cb, uint32_t *pu32Value)
2474{
2475 uint32_t uValue;
2476 if (uAddress + cb <= RT_MIN(pPciDev->cbConfig, sizeof(pPciDev->abConfig)))
2477 {
2478 switch (cb)
2479 {
2480 case 1:
2481 /* safe, only needs to go to the config space array */
2482 uValue = PDMPciDevGetByte(pPciDev, uAddress);
2483 break;
2484 case 2:
2485 /* safe, only needs to go to the config space array */
2486 uValue = PDMPciDevGetWord(pPciDev, uAddress);
2487 break;
2488 case 4:
2489 /* safe, only needs to go to the config space array */
2490 uValue = PDMPciDevGetDWord(pPciDev, uAddress);
2491 break;
2492 default:
2493 AssertFailed();
2494 uValue = 0;
2495 break;
2496 }
2497
2498#ifdef LOG_ENABLED
2499 if ( pciDevIsMsiCapable(pPciDev)
2500 && uAddress - (uint32_t)pPciDev->Int.s.u8MsiCapOffset < (uint32_t)pPciDev->Int.s.u8MsiCapSize )
2501 Log2Func(("MSI CAP: %#x LB %u -> %#x\n", uAddress - (uint32_t)pPciDev->Int.s.u8MsiCapOffset, cb, uValue));
2502 else if ( pciDevIsMsixCapable(pPciDev)
2503 && uAddress - (uint32_t)pPciDev->Int.s.u8MsixCapOffset < (uint32_t)pPciDev->Int.s.u8MsixCapSize)
2504 Log2Func(("MSI-X CAP: %#x LB %u -> %#x\n", uAddress - (uint32_t)pPciDev->Int.s.u8MsiCapOffset, cb, uValue));
2505#endif
2506 }
2507 else
2508 {
2509 AssertMsgFailed(("Read after end of PCI config space: %#x LB %u\n", uAddress, cb));
2510 uValue = 0;
2511 }
2512
2513 *pu32Value = uValue;
2514 return VINF_SUCCESS;
2515}
2516
2517
2518/**
2519 * @interface_method_impl{PDMPCIBUSREGR3,pfnConfigRead}
2520 */
2521DECLCALLBACK(VBOXSTRICTRC) devpciR3CommonConfigRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
2522 uint32_t uAddress, unsigned cb, uint32_t *pu32Value)
2523{
2524 RT_NOREF(pDevIns);
2525 return devpciR3CommonConfigReadWorker(pPciDev, uAddress, cb, pu32Value);
2526}
2527
2528
2529/**
2530 * Worker for devpciR3ResetDevice and devpciR3UpdateMappings that unmaps a region.
2531 *
2532 * @returns VBox status code.
2533 * @param pDevIns The PCI bus device instance.
2534 * @param pDev The PCI device.
2535 * @param iRegion The region to unmap.
2536 */
2537static int devpciR3UnmapRegion(PPDMDEVINS pDevIns, PPDMPCIDEV pDev, int iRegion)
2538{
2539 PPCIIOREGION pRegion = &pDev->Int.s.aIORegions[iRegion];
2540 AssertReturn(pRegion->size != 0, VINF_SUCCESS);
2541
2542 int rc = VINF_SUCCESS;
2543 if (pRegion->addr != INVALID_PCI_ADDRESS)
2544 {
2545 if ( (pRegion->hHandle != UINT64_MAX)
2546 || (pRegion->fFlags & PDMPCIDEV_IORGN_F_NEW_STYLE))
2547 {
2548 /*
2549 * New style device with a IOM handle. Do callout first (optional),
2550 * then do the unmapping via handle.
2551 */
2552 if (pRegion->pfnMap)
2553 {
2554 rc = pRegion->pfnMap(pDev->Int.s.pDevInsR3, pDev, iRegion,
2555 NIL_RTGCPHYS, pRegion->size, (PCIADDRESSSPACE)(pRegion->type));
2556 AssertRC(rc);
2557 }
2558
2559 switch (pRegion->fFlags & PDMPCIDEV_IORGN_F_HANDLE_MASK)
2560 {
2561 case PDMPCIDEV_IORGN_F_IOPORT_HANDLE:
2562 rc = PDMDevHlpIoPortUnmap(pDev->Int.s.pDevInsR3, (IOMIOPORTHANDLE)pRegion->hHandle);
2563 AssertRC(rc);
2564 break;
2565
2566 case PDMPCIDEV_IORGN_F_MMIO_HANDLE:
2567 rc = PDMDevHlpMmioUnmap(pDev->Int.s.pDevInsR3, (IOMMMIOHANDLE)pRegion->hHandle);
2568 AssertRC(rc);
2569 break;
2570
2571 case PDMPCIDEV_IORGN_F_MMIO2_HANDLE:
2572 rc = PDMDevHlpMmio2Unmap(pDev->Int.s.pDevInsR3, (PGMMMIO2HANDLE)pRegion->hHandle);
2573 AssertRC(rc);
2574 break;
2575
2576 case PDMPCIDEV_IORGN_F_NO_HANDLE:
2577 Assert(pRegion->fFlags & PDMPCIDEV_IORGN_F_NEW_STYLE);
2578 Assert(pRegion->hHandle == UINT64_MAX);
2579 break;
2580
2581 default:
2582 AssertLogRelFailed();
2583 }
2584 }
2585 else
2586 {
2587 /*
2588 * Old style device, no handle here and only MMIOEx gets callouts.
2589 */
2590 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
2591 {
2592 /* Port IO */
2593 rc = PDMDevHlpIOPortDeregister(pDev->Int.s.pDevInsR3, pRegion->addr, pRegion->size);
2594 AssertRC(rc);
2595 }
2596 else
2597 {
2598 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
2599 RTGCPHYS GCPhysBase = pRegion->addr;
2600 if (pBusCC->pPciHlpR3->pfnIsMMIOExBase(pDevIns, pDev->Int.s.pDevInsR3, GCPhysBase))
2601 {
2602 /* unmap it. */
2603 rc = pRegion->pfnMap(pDev->Int.s.pDevInsR3, pDev, iRegion,
2604 NIL_RTGCPHYS, pRegion->size, (PCIADDRESSSPACE)(pRegion->type));
2605 AssertRC(rc);
2606 rc = PDMDevHlpMMIOExUnmap(pDev->Int.s.pDevInsR3, pDev, iRegion, GCPhysBase);
2607 }
2608 else
2609 rc = PDMDevHlpMMIODeregister(pDev->Int.s.pDevInsR3, GCPhysBase, pRegion->size);
2610 AssertRC(rc);
2611 }
2612 }
2613 pRegion->addr = INVALID_PCI_ADDRESS;
2614 }
2615 return rc;
2616}
2617
2618
2619/**
2620 * Worker for devpciR3CommonDefaultConfigWrite that updates BAR and ROM mappings.
2621 *
2622 * @returns VINF_SUCCESS of DBGFSTOP result.
2623 * @param pDevIns The PCI bus device instance.
2624 * @param pPciDev The PCI device to update the mappings for.
2625 * @param fP2PBridge Whether this is a PCI to PCI bridge or not.
2626 */
2627static VBOXSTRICTRC devpciR3UpdateMappings(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, bool fP2PBridge)
2628{
2629 /* safe, only needs to go to the config space array */
2630 uint16_t const u16Cmd = PDMPciDevGetWord(pPciDev, VBOX_PCI_COMMAND);
2631 Log4(("devpciR3UpdateMappings: dev %u/%u (%s): u16Cmd=%#x\n",
2632 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK, pPciDev->pszNameR3, u16Cmd));
2633 for (unsigned iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
2634 {
2635 /* Skip over BAR2..BAR5 for bridges, as they have a different meaning there. */
2636 if (fP2PBridge && iRegion >= 2 && iRegion <= 5)
2637 continue;
2638 PCIIOREGION *pRegion = &pPciDev->Int.s.aIORegions[iRegion];
2639 uint64_t const cbRegion = pRegion->size;
2640 if (cbRegion != 0)
2641 {
2642 uint32_t const offCfgReg = devpciGetRegionReg(iRegion);
2643 bool const f64Bit = (pRegion->type & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
2644 == PCI_ADDRESS_SPACE_BAR64;
2645 uint64_t uNew = INVALID_PCI_ADDRESS;
2646
2647 /*
2648 * Port I/O region. Check if mapped and within 1..65535 range.
2649 */
2650 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
2651 {
2652 if (u16Cmd & VBOX_PCI_COMMAND_IO)
2653 {
2654 /* safe, only needs to go to the config space array */
2655 uint32_t uIoBase = PDMPciDevGetDWord(pPciDev, offCfgReg);
2656 uIoBase &= ~(uint32_t)(cbRegion - 1);
2657
2658 uint64_t uLast = cbRegion - 1 + uIoBase;
2659 if ( uLast < _64K
2660 && uIoBase < uLast
2661 && uIoBase > 0)
2662 uNew = uIoBase;
2663 else
2664 Log4(("devpciR3UpdateMappings: dev %u/%u (%s): region #%u: Disregarding invalid I/O port range: %#RX32..%#RX64\n",
2665 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2666 pPciDev->pszNameR3, iRegion, uIoBase, uLast));
2667 }
2668 }
2669 /*
2670 * MMIO or ROM. Check ROM enable bit and range.
2671 *
2672 * Note! We exclude the I/O-APIC/HPET/ROM area at the end of the first 4GB to
2673 * prevent the (fake) PCI BIOS and others from making a mess. Pure paranoia.
2674 * Additionally addresses with the top 32 bits all set are excluded, to
2675 * catch silly OSes which probe 64-bit BARs without disabling the
2676 * corresponding transactions.
2677 *
2678 * Update: The pure paranoia above broke NT 3.51, so it was changed to only
2679 * exclude the 64KB BIOS mapping at the top. NT 3.51 excludes the
2680 * top 256KB, btw.
2681 */
2682 /** @todo Query upper boundrary from CPUM and PGMPhysRom instead of making
2683 * incorrect assumptions. */
2684 else if (u16Cmd & VBOX_PCI_COMMAND_MEMORY)
2685 {
2686 /* safe, only needs to go to the config space array */
2687 uint64_t uMemBase = PDMPciDevGetDWord(pPciDev, offCfgReg);
2688 if (f64Bit)
2689 {
2690 Assert(iRegion < VBOX_PCI_ROM_SLOT);
2691 /* safe, only needs to go to the config space array */
2692 uMemBase |= (uint64_t)PDMPciDevGetDWord(pPciDev, offCfgReg + 4) << 32;
2693 }
2694 if ( iRegion != PCI_ROM_SLOT
2695 || (uMemBase & RT_BIT_32(0))) /* ROM enable bit. */
2696 {
2697 uMemBase &= ~(cbRegion - 1);
2698
2699 uint64_t uLast = uMemBase + cbRegion - 1;
2700 if ( uMemBase < uLast
2701 && uMemBase > 0)
2702 {
2703 if ( ( uMemBase > UINT32_C(0xffffffff)
2704 || uLast < UINT32_C(0xffff0000) ) /* UINT32_C(0xfec00000) - breaks NT3.51! */
2705 && uMemBase < UINT64_C(0xffffffff00000000) )
2706 uNew = uMemBase;
2707 else
2708 Log(("devpciR3UpdateMappings: dev %u/%u (%s): region #%u: Rejecting address range: %#RX64..%#RX64!\n",
2709 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2710 pPciDev->pszNameR3, iRegion, uMemBase, uLast));
2711 }
2712 else
2713 Log2(("devpciR3UpdateMappings: dev %u/%u (%s): region #%u: Disregarding invalid address range: %#RX64..%#RX64\n",
2714 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2715 pPciDev->pszNameR3, iRegion, uMemBase, uLast));
2716 }
2717 }
2718
2719 /*
2720 * Do real unmapping and/or mapping if the address change.
2721 *
2722 * For new style device we'll do the actual mapping, whereas old ones
2723 * are expected to do it themselves via the callback.
2724 */
2725 Log4(("devpciR3UpdateMappings: dev %u/%u (%s): iRegion=%u addr=%#RX64 uNew=%#RX64\n",
2726 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK, pPciDev->pszNameR3,
2727 iRegion, pRegion->addr, uNew));
2728 if (uNew != pRegion->addr)
2729 {
2730 LogRel2(("PCI: config dev %u/%u (%s) BAR%i: %#RX64 -> %#RX64 (LB %RX64 (%RU64))\n",
2731 pPciDev->uDevFn >> VBOX_PCI_DEVFN_DEV_SHIFT, pPciDev->uDevFn & VBOX_PCI_DEVFN_FUN_MASK,
2732 pPciDev->pszNameR3, iRegion, pRegion->addr, uNew, cbRegion, cbRegion));
2733
2734 int rc = devpciR3UnmapRegion(pDevIns, pPciDev, iRegion);
2735 AssertLogRelRC(rc);
2736 pRegion->addr = uNew;
2737 if (uNew != INVALID_PCI_ADDRESS)
2738 {
2739 /* The callout is optional with new style devices: */
2740 if (pRegion->pfnMap)
2741 {
2742 rc = pRegion->pfnMap(pPciDev->Int.s.pDevInsR3, pPciDev, iRegion,
2743 uNew, cbRegion, (PCIADDRESSSPACE)(pRegion->type));
2744 AssertLogRelRC(rc);
2745 }
2746
2747 /* We do the mapping for new-style devices: */
2748 if (pRegion->hHandle != UINT64_MAX)
2749 {
2750 switch (pRegion->fFlags & PDMPCIDEV_IORGN_F_HANDLE_MASK)
2751 {
2752 case PDMPCIDEV_IORGN_F_IOPORT_HANDLE:
2753 rc = PDMDevHlpIoPortMap(pPciDev->Int.s.pDevInsR3, (IOMIOPORTHANDLE)pRegion->hHandle, (RTIOPORT)uNew);
2754 AssertLogRelRC(rc);
2755 break;
2756
2757 case PDMPCIDEV_IORGN_F_MMIO_HANDLE:
2758 rc = PDMDevHlpMmioMap(pPciDev->Int.s.pDevInsR3, (IOMMMIOHANDLE)pRegion->hHandle, uNew);
2759 AssertLogRelRC(rc);
2760 break;
2761
2762 case PDMPCIDEV_IORGN_F_MMIO2_HANDLE:
2763 rc = PDMDevHlpMmio2Map(pPciDev->Int.s.pDevInsR3, (PGMMMIO2HANDLE)pRegion->hHandle, uNew);
2764 AssertRC(rc);
2765 break;
2766
2767 default:
2768 AssertLogRelFailed();
2769 }
2770 }
2771 }
2772 }
2773
2774 if (f64Bit)
2775 iRegion++;
2776 }
2777 /* else: size == 0: unused region */
2778 }
2779
2780 return VINF_SUCCESS;
2781}
2782
2783
2784/**
2785 * Worker for devpciR3CommonDefaultConfigWrite that write a byte to a BAR.
2786 *
2787 * @param pPciDev The PCI device.
2788 * @param iRegion The region.
2789 * @param off The BAR offset.
2790 * @param bVal The byte to write.
2791 */
2792DECLINLINE(void) devpciR3WriteBarByte(PPDMPCIDEV pPciDev, uint32_t iRegion, uint32_t off, uint8_t bVal)
2793{
2794 PCIIOREGION *pRegion = &pPciDev->Int.s.aIORegions[iRegion];
2795 Log3Func(("region=%d off=%d val=%#x size=%#llx\n", iRegion, off, bVal, pRegion->size));
2796 Assert(off <= 3);
2797
2798 /* Check if we're writing to upper part of 64-bit BAR. */
2799 if (pRegion->type == 0xff)
2800 {
2801 AssertLogRelReturnVoid(iRegion > 0 && iRegion < VBOX_PCI_ROM_SLOT);
2802 pRegion--;
2803 iRegion--;
2804 off += 4;
2805 Assert(pRegion->type & PCI_ADDRESS_SPACE_BAR64);
2806 }
2807
2808 /* Ignore zero sized regions (they don't exist). */
2809 if (pRegion->size != 0)
2810 {
2811 uint32_t uAddr = devpciGetRegionReg(iRegion) + off;
2812 Assert((pRegion->size & (pRegion->size - 1)) == 0); /* Region size must be power of two. */
2813 uint8_t bMask = ( (pRegion->size - 1) >> (off * 8) ) & 0xff;
2814 if (off == 0)
2815 bMask |= (pRegion->type & PCI_ADDRESS_SPACE_IO)
2816 ? (1 << 2) - 1 /* 2 lowest bits for IO region */ :
2817 (1 << 4) - 1 /* 4 lowest bits for memory region, also ROM enable bit for ROM region */;
2818
2819 /* safe, only needs to go to the config space array */
2820 uint8_t bOld = PDMPciDevGetByte(pPciDev, uAddr) & bMask;
2821 bVal = (bOld & bMask) | (bVal & ~bMask);
2822
2823 Log3Func(("%x changed to %x\n", bOld, bVal));
2824
2825 /* safe, only needs to go to the config space array */
2826 PDMPciDevSetByte(pPciDev, uAddr, bVal);
2827 }
2828}
2829
2830
2831/**
2832 * Checks if the given configuration byte is writable.
2833 *
2834 * @returns true if writable, false if not
2835 * @param uAddress The config space byte byte.
2836 * @param bHeaderType The device header byte.
2837 */
2838DECLINLINE(bool) devpciR3IsConfigByteWritable(uint32_t uAddress, uint8_t bHeaderType)
2839{
2840 switch (bHeaderType)
2841 {
2842 case 0x00: /* normal device */
2843 case 0x80: /* multi-function device */
2844 switch (uAddress)
2845 {
2846 /* Read-only registers. */
2847 case VBOX_PCI_VENDOR_ID:
2848 case VBOX_PCI_VENDOR_ID+1:
2849 case VBOX_PCI_DEVICE_ID:
2850 case VBOX_PCI_DEVICE_ID+1:
2851 case VBOX_PCI_REVISION_ID:
2852 case VBOX_PCI_CLASS_PROG:
2853 case VBOX_PCI_CLASS_SUB:
2854 case VBOX_PCI_CLASS_BASE:
2855 case VBOX_PCI_HEADER_TYPE:
2856 case VBOX_PCI_SUBSYSTEM_VENDOR_ID:
2857 case VBOX_PCI_SUBSYSTEM_VENDOR_ID+1:
2858 case VBOX_PCI_SUBSYSTEM_ID:
2859 case VBOX_PCI_SUBSYSTEM_ID+1:
2860 case VBOX_PCI_ROM_ADDRESS:
2861 case VBOX_PCI_ROM_ADDRESS+1:
2862 case VBOX_PCI_ROM_ADDRESS+2:
2863 case VBOX_PCI_ROM_ADDRESS+3:
2864 case VBOX_PCI_CAPABILITY_LIST:
2865 case VBOX_PCI_INTERRUPT_PIN:
2866 return false;
2867 /* Other registers can be written. */
2868 default:
2869 return true;
2870 }
2871 break;
2872 case 0x01: /* PCI-PCI bridge */
2873 switch (uAddress)
2874 {
2875 /* Read-only registers. */
2876 case VBOX_PCI_VENDOR_ID:
2877 case VBOX_PCI_VENDOR_ID+1:
2878 case VBOX_PCI_DEVICE_ID:
2879 case VBOX_PCI_DEVICE_ID+1:
2880 case VBOX_PCI_REVISION_ID:
2881 case VBOX_PCI_CLASS_PROG:
2882 case VBOX_PCI_CLASS_SUB:
2883 case VBOX_PCI_CLASS_BASE:
2884 case VBOX_PCI_HEADER_TYPE:
2885 case VBOX_PCI_ROM_ADDRESS_BR:
2886 case VBOX_PCI_ROM_ADDRESS_BR+1:
2887 case VBOX_PCI_ROM_ADDRESS_BR+2:
2888 case VBOX_PCI_ROM_ADDRESS_BR+3:
2889 case VBOX_PCI_INTERRUPT_PIN:
2890 return false;
2891 /* Other registers can be written. */
2892 default:
2893 return true;
2894 }
2895 break;
2896 default:
2897 AssertMsgFailed(("Unknown header type %#x\n", bHeaderType));
2898 return false;
2899 }
2900}
2901
2902
2903/**
2904 * Writes config space for a device, ignoring interceptors.
2905 *
2906 * See paragraph 7.5 of PCI Express specification (p. 349) for
2907 * definition of registers and their writability policy.
2908 */
2909DECLHIDDEN(VBOXSTRICTRC) devpciR3CommonConfigWriteWorker(PPDMDEVINS pDevIns, PDEVPCIBUSCC pBusCC,
2910 PPDMPCIDEV pPciDev, uint32_t uAddress, unsigned cb, uint32_t u32Value)
2911{
2912 Assert(cb <= 4 && cb != 3);
2913 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
2914
2915 if (uAddress + cb <= RT_MIN(pPciDev->cbConfig, sizeof(pPciDev->abConfig)))
2916 {
2917 /*
2918 * MSI and MSI-X capabilites needs to be handled separately.
2919 */
2920 if ( pciDevIsMsiCapable(pPciDev)
2921 && uAddress - (uint32_t)pPciDev->Int.s.u8MsiCapOffset < (uint32_t)pPciDev->Int.s.u8MsiCapSize)
2922 MsiR3PciConfigWrite(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, uAddress, u32Value, cb);
2923 else if ( pciDevIsMsixCapable(pPciDev)
2924 && uAddress - (uint32_t)pPciDev->Int.s.u8MsixCapOffset < (uint32_t)pPciDev->Int.s.u8MsixCapSize)
2925 MsixR3PciConfigWrite(pDevIns, pBusCC->CTX_SUFF(pPciHlp), pPciDev, uAddress, u32Value, cb);
2926 else
2927 {
2928 /*
2929 * Handle the writes byte-by-byte to catch all possible cases.
2930 *
2931 * Note! Real hardware may not necessarily handle non-dword writes like
2932 * we do here and even produce erratic behavior. We don't (yet)
2933 * try emulate that.
2934 */
2935 uint8_t const bHeaderType = devpciR3GetByte(pPciDev, VBOX_PCI_HEADER_TYPE);
2936 bool const fP2PBridge = bHeaderType == 0x01; /* PCI-PCI bridge */
2937 bool fUpdateMappings = false;
2938 while (cb-- > 0)
2939 {
2940 bool fWritable = devpciR3IsConfigByteWritable(uAddress, bHeaderType);
2941 uint8_t bVal = (uint8_t)u32Value;
2942 bool fRom = false;
2943 switch (uAddress)
2944 {
2945 case VBOX_PCI_COMMAND: /* Command register, bits 0-7. */
2946 if (fWritable)
2947 {
2948 /* safe, only needs to go to the config space array */
2949 PDMPciDevSetByte(pPciDev, uAddress, bVal);
2950 fUpdateMappings = true;
2951 }
2952 break;
2953
2954 case VBOX_PCI_COMMAND+1: /* Command register, bits 8-15. */
2955 if (fWritable)
2956 {
2957 /* don't change reserved bits (11-15) */
2958 bVal &= ~UINT8_C(0xf8);
2959 /* safe, only needs to go to the config space array */
2960 PDMPciDevSetByte(pPciDev, uAddress, bVal);
2961 fUpdateMappings = true;
2962 }
2963 break;
2964
2965 case VBOX_PCI_STATUS: /* Status register, bits 0-7. */
2966 /* don't change read-only bits => actually all lower bits are read-only */
2967 bVal &= ~UINT8_C(0xff);
2968 /* status register, low part: clear bits by writing a '1' to the corresponding bit */
2969 pPciDev->abConfig[uAddress] &= ~bVal;
2970 break;
2971
2972 case VBOX_PCI_STATUS+1: /* Status register, bits 8-15. */
2973 /* don't change read-only bits */
2974 bVal &= ~UINT8_C(0x06);
2975 /* status register, high part: clear bits by writing a '1' to the corresponding bit */
2976 pPciDev->abConfig[uAddress] &= ~bVal;
2977 break;
2978
2979 case VBOX_PCI_ROM_ADDRESS: case VBOX_PCI_ROM_ADDRESS +1: case VBOX_PCI_ROM_ADDRESS +2: case VBOX_PCI_ROM_ADDRESS +3:
2980 fRom = true;
2981 RT_FALL_THRU();
2982 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:
2983 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:
2984 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:
2985 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:
2986 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:
2987 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:
2988 /* We check that, as same PCI register numbers as BARs may mean different registers for bridges */
2989 if (!fP2PBridge)
2990 {
2991 uint32_t iRegion = fRom ? VBOX_PCI_ROM_SLOT : (uAddress - VBOX_PCI_BASE_ADDRESS_0) >> 2;
2992 devpciR3WriteBarByte(pPciDev, iRegion, uAddress & 0x3, bVal);
2993 fUpdateMappings = true;
2994 break;
2995 }
2996 if (uAddress < VBOX_PCI_BASE_ADDRESS_2 || uAddress > VBOX_PCI_BASE_ADDRESS_5+3)
2997 {
2998 /* PCI bridges have only BAR0, BAR1 and ROM */
2999 uint32_t iRegion = fRom ? VBOX_PCI_ROM_SLOT : (uAddress - VBOX_PCI_BASE_ADDRESS_0) >> 2;
3000 devpciR3WriteBarByte(pPciDev, iRegion, uAddress & 0x3, bVal);
3001 fUpdateMappings = true;
3002 break;
3003 }
3004 if ( uAddress == VBOX_PCI_IO_BASE
3005 || uAddress == VBOX_PCI_IO_LIMIT
3006 || uAddress == VBOX_PCI_MEMORY_BASE
3007 || uAddress == VBOX_PCI_MEMORY_LIMIT
3008 || uAddress == VBOX_PCI_PREF_MEMORY_BASE
3009 || uAddress == VBOX_PCI_PREF_MEMORY_LIMIT)
3010 {
3011 /* All bridge address decoders have the low 4 bits
3012 * as readonly, and all but the prefetchable ones
3013 * have the low 4 bits as 0 (the prefetchable have
3014 * it as 1 to show the 64-bit decoder support. */
3015 bVal &= 0xf0;
3016 if ( uAddress == VBOX_PCI_PREF_MEMORY_BASE
3017 || uAddress == VBOX_PCI_PREF_MEMORY_LIMIT)
3018 bVal |= 0x01;
3019 }
3020 /* (bridge config space which isn't a BAR) */
3021 RT_FALL_THRU();
3022 default:
3023 if (fWritable)
3024 /* safe, only needs to go to the config space array */
3025 PDMPciDevSetByte(pPciDev, uAddress, bVal);
3026 break;
3027 }
3028 uAddress++;
3029 u32Value >>= 8;
3030 }
3031
3032 /*
3033 * Update the region mappings if anything changed related to them (command, BARs, ROM).
3034 */
3035 if (fUpdateMappings)
3036 rcStrict = devpciR3UpdateMappings(pDevIns, pPciDev, fP2PBridge);
3037 }
3038 }
3039 else
3040 AssertMsgFailed(("Write after end of PCI config space: %#x LB %u\n", uAddress, cb));
3041
3042 return rcStrict;
3043}
3044
3045
3046/**
3047 * @interface_method_impl{PDMPCIBUSREGR3,pfnConfigWrite}
3048 */
3049DECLCALLBACK(VBOXSTRICTRC) devpciR3CommonConfigWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev,
3050 uint32_t uAddress, unsigned cb, uint32_t u32Value)
3051{
3052 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3053 return devpciR3CommonConfigWriteWorker(pDevIns, pBusCC, pPciDev, uAddress, cb, u32Value);
3054}
3055
3056
3057/* -=-=-=-=-=- Debug Info Handlers -=-=-=-=-=- */
3058
3059/**
3060 * Indents an info line.
3061 * @param pHlp The info helper.
3062 * @param iIndentLvl The desired indentation level.
3063 */
3064static void devpciR3InfoIndent(PCDBGFINFOHLP pHlp, unsigned iIndentLvl)
3065{
3066 for (unsigned i = 0; i < iIndentLvl; i++)
3067 pHlp->pfnPrintf(pHlp, " ");
3068}
3069
3070static const char *devpciR3InInfoPciBusClassName(uint8_t iBaseClass)
3071{
3072 static const char *s_szBaseClass[] =
3073 {
3074 /* 00h */ "unknown",
3075 /* 01h */ "mass storage controller",
3076 /* 02h */ "network controller",
3077 /* 03h */ "display controller",
3078 /* 04h */ "multimedia controller",
3079 /* 05h */ "memory controller",
3080 /* 06h */ "bridge device",
3081 /* 07h */ "simple communication controllers",
3082 /* 08h */ "base system peripherals",
3083 /* 09h */ "input devices",
3084 /* 0Ah */ "docking stations",
3085 /* 0Bh */ "processors",
3086 /* 0Ch */ "serial bus controllers",
3087 /* 0Dh */ "wireless controller",
3088 /* 0Eh */ "intelligent I/O controllers",
3089 /* 0Fh */ "satellite communication controllers",
3090 /* 10h */ "encryption/decryption controllers",
3091 /* 11h */ "data acquisition and signal processing controllers"
3092 };
3093 if (iBaseClass < RT_ELEMENTS(s_szBaseClass))
3094 return s_szBaseClass[iBaseClass];
3095 if (iBaseClass < 0xFF)
3096 return "reserved";
3097 return "device does not fit in any defined classes";
3098}
3099
3100
3101/**
3102 * Recursive worker for devpciR3InfoPci.
3103 *
3104 * @param pBus The bus to show info for.
3105 * @param pHlp The info helpers.
3106 * @param iIndentLvl The indentation level.
3107 * @param fRegisters Whether to show device registers or not.
3108 */
3109static void devpciR3InfoPciBus(PDEVPCIBUS pBus, PCDBGFINFOHLP pHlp, unsigned iIndentLvl, bool fRegisters)
3110{
3111 /* This has to use the callbacks for accuracy reasons. Otherwise it can get
3112 * confusing in the passthrough case or when the callbacks for some device
3113 * are doing something non-trivial (like implementing an indirect
3114 * passthrough approach), because then the abConfig array is an imprecise
3115 * cache needed for efficiency (so that certain reads can be done from
3116 * R0/RC), but far from authoritative or what the guest would see. */
3117
3118 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
3119 {
3120 PPDMPCIDEV pPciDev = pBus->apDevices[uDevFn];
3121 if (pPciDev != NULL)
3122 {
3123 devpciR3InfoIndent(pHlp, iIndentLvl);
3124
3125 /*
3126 * For passthrough devices MSI/MSI-X mostly reflects the way interrupts delivered to the guest,
3127 * as host driver handles real devices interrupts.
3128 */
3129 pHlp->pfnPrintf(pHlp, "%02x:%02x.%d %s%s: %04x-%04x %s%s%s",
3130 pBus->iBus, (uDevFn >> 3) & 0xff, uDevFn & 0x7,
3131 pPciDev->pszNameR3,
3132 pciDevIsPassthrough(pPciDev) ? " (PASSTHROUGH)" : "",
3133 devpciR3GetWord(pPciDev, VBOX_PCI_VENDOR_ID), devpciR3GetWord(pPciDev, VBOX_PCI_DEVICE_ID),
3134 pBus->fTypeIch9 ? "ICH9" : pBus->fTypePiix3 ? "PIIX3" : "?type?",
3135 pciDevIsMsiCapable(pPciDev) ? " MSI" : "",
3136 pciDevIsMsixCapable(pPciDev) ? " MSI-X" : ""
3137 );
3138 if (devpciR3GetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN) != 0)
3139 {
3140 pHlp->pfnPrintf(pHlp, " IRQ%d", devpciR3GetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE));
3141 pHlp->pfnPrintf(pHlp, " (INTA#->IRQ%d)", 0x10 + ich9pciSlot2ApicIrq(uDevFn >> 3, 0));
3142 }
3143 pHlp->pfnPrintf(pHlp, "\n");
3144 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3145 uint8_t uClassBase = devpciR3GetByte(pPciDev, VBOX_PCI_CLASS_BASE);
3146 uint8_t uClassSub = devpciR3GetByte(pPciDev, VBOX_PCI_CLASS_SUB);
3147 pHlp->pfnPrintf(pHlp, "Class base/sub: %02x%02x (%s)\n",
3148 uClassBase, uClassSub, devpciR3InInfoPciBusClassName(uClassBase));
3149
3150 if (pciDevIsMsiCapable(pPciDev) || pciDevIsMsixCapable(pPciDev))
3151 {
3152 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3153
3154 if (pciDevIsMsiCapable(pPciDev))
3155 pHlp->pfnPrintf(pHlp, "MSI: %s ", MsiIsEnabled(pPciDev) ? "on" : "off");
3156
3157 if (pciDevIsMsixCapable(pPciDev))
3158 pHlp->pfnPrintf(pHlp, "MSI-X: %s ", MsixIsEnabled(pPciDev) ? "on" : "off");
3159
3160 pHlp->pfnPrintf(pHlp, "\n");
3161 }
3162
3163 for (unsigned iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
3164 {
3165 PCIIOREGION const *pRegion = &pPciDev->Int.s.aIORegions[iRegion];
3166 uint64_t const cbRegion = pRegion->size;
3167
3168 if (cbRegion == 0)
3169 continue;
3170
3171 uint32_t uAddr = devpciR3GetDWord(pPciDev, devpciGetRegionReg(iRegion));
3172 const char * pszDesc;
3173 char szDescBuf[128];
3174
3175 bool f64Bit = (pRegion->type & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
3176 == PCI_ADDRESS_SPACE_BAR64;
3177 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
3178 {
3179 pszDesc = "IO";
3180 uAddr &= ~0x3;
3181 }
3182 else
3183 {
3184 RTStrPrintf(szDescBuf, sizeof(szDescBuf), "MMIO%s%s",
3185 f64Bit ? "64" : "32",
3186 pRegion->type & PCI_ADDRESS_SPACE_MEM_PREFETCH ? " PREFETCH" : "");
3187 pszDesc = szDescBuf;
3188 uAddr &= ~0xf;
3189 }
3190
3191 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3192 pHlp->pfnPrintf(pHlp, "%s region #%u: ", pszDesc, iRegion);
3193 if (f64Bit)
3194 {
3195 uint32_t u32High = devpciR3GetDWord(pPciDev, devpciGetRegionReg(iRegion+1));
3196 uint64_t u64Addr = RT_MAKE_U64(uAddr, u32High);
3197 pHlp->pfnPrintf(pHlp, "%RX64..%RX64\n", u64Addr, u64Addr + cbRegion - 1);
3198 iRegion++;
3199 }
3200 else
3201 pHlp->pfnPrintf(pHlp, "%x..%x\n", uAddr, uAddr + (uint32_t)cbRegion - 1);
3202 }
3203
3204 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3205 uint16_t iCmd = devpciR3GetWord(pPciDev, VBOX_PCI_COMMAND);
3206 uint16_t iStatus = devpciR3GetWord(pPciDev, VBOX_PCI_STATUS);
3207 pHlp->pfnPrintf(pHlp, "Command: %04x, Status: %04x\n", iCmd, iStatus);
3208 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3209 pHlp->pfnPrintf(pHlp, "Bus master: %s\n", iCmd & VBOX_PCI_COMMAND_MASTER ? "Yes" : "No");
3210 if (iCmd != PDMPciDevGetCommand(pPciDev))
3211 {
3212 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3213 pHlp->pfnPrintf(pHlp, "CACHE INCONSISTENCY: Command: %04x\n", PDMPciDevGetCommand(pPciDev));
3214 }
3215
3216 if (fRegisters)
3217 {
3218 devpciR3InfoIndent(pHlp, iIndentLvl + 2);
3219 pHlp->pfnPrintf(pHlp, "PCI registers:\n");
3220 for (unsigned iReg = 0; iReg < 0x100; )
3221 {
3222 unsigned iPerLine = 0x10;
3223 Assert(0x100 % iPerLine == 0);
3224 devpciR3InfoIndent(pHlp, iIndentLvl + 3);
3225
3226 while (iPerLine-- > 0)
3227 pHlp->pfnPrintf(pHlp, "%02x ", devpciR3GetByte(pPciDev, iReg++));
3228 pHlp->pfnPrintf(pHlp, "\n");
3229 }
3230 }
3231 }
3232 }
3233
3234 if (pBus->cBridges > 0)
3235 {
3236 devpciR3InfoIndent(pHlp, iIndentLvl);
3237 pHlp->pfnPrintf(pHlp, "Registered %d bridges, subordinate buses info follows\n", pBus->cBridges);
3238 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
3239 {
3240 PPDMDEVINS pDevInsSub = pBus->papBridgesR3[iBridge]->Int.s.CTX_SUFF(pDevIns);
3241 PPDMPCIDEV pPciDevSub = pDevInsSub->apPciDevs[0];
3242 PDEVPCIBUS pBusSub = PDMINS_2_DATA(pDevInsSub, PDEVPCIBUS);
3243 uint8_t uPrimary = devpciR3GetByte(pPciDevSub, VBOX_PCI_PRIMARY_BUS);
3244 uint8_t uSecondary = devpciR3GetByte(pPciDevSub, VBOX_PCI_SECONDARY_BUS);
3245 uint8_t uSubordinate = devpciR3GetByte(pPciDevSub, VBOX_PCI_SUBORDINATE_BUS);
3246 devpciR3InfoIndent(pHlp, iIndentLvl);
3247 pHlp->pfnPrintf(pHlp, "%02x:%02x.%d: bridge topology: primary=%d secondary=%d subordinate=%d\n",
3248 uPrimary, pPciDevSub->uDevFn >> 3, pPciDevSub->uDevFn & 7,
3249 uPrimary, uSecondary, uSubordinate);
3250 if ( uPrimary != PDMPciDevGetByte(pPciDevSub, VBOX_PCI_PRIMARY_BUS)
3251 || uSecondary != PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SECONDARY_BUS)
3252 || uSubordinate != PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SUBORDINATE_BUS))
3253 {
3254 devpciR3InfoIndent(pHlp, iIndentLvl);
3255 pHlp->pfnPrintf(pHlp, "CACHE INCONSISTENCY: primary=%d secondary=%d subordinate=%d\n",
3256 PDMPciDevGetByte(pPciDevSub, VBOX_PCI_PRIMARY_BUS),
3257 PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SECONDARY_BUS),
3258 PDMPciDevGetByte(pPciDevSub, VBOX_PCI_SUBORDINATE_BUS));
3259 }
3260 devpciR3InfoIndent(pHlp, iIndentLvl);
3261 pHlp->pfnPrintf(pHlp, "behind bridge: ");
3262 uint8_t uIoBase = devpciR3GetByte(pPciDevSub, VBOX_PCI_IO_BASE);
3263 uint8_t uIoLimit = devpciR3GetByte(pPciDevSub, VBOX_PCI_IO_LIMIT);
3264 pHlp->pfnPrintf(pHlp, "I/O %#06x..%#06x",
3265 (uIoBase & 0xf0) << 8,
3266 (uIoLimit & 0xf0) << 8 | 0xfff);
3267 if (uIoBase > uIoLimit)
3268 pHlp->pfnPrintf(pHlp, " (IGNORED)");
3269 pHlp->pfnPrintf(pHlp, "\n");
3270 devpciR3InfoIndent(pHlp, iIndentLvl);
3271 pHlp->pfnPrintf(pHlp, "behind bridge: ");
3272 uint32_t uMemoryBase = devpciR3GetWord(pPciDevSub, VBOX_PCI_MEMORY_BASE);
3273 uint32_t uMemoryLimit = devpciR3GetWord(pPciDevSub, VBOX_PCI_MEMORY_LIMIT);
3274 pHlp->pfnPrintf(pHlp, "memory %#010x..%#010x",
3275 (uMemoryBase & 0xfff0) << 16,
3276 (uMemoryLimit & 0xfff0) << 16 | 0xfffff);
3277 if (uMemoryBase > uMemoryLimit)
3278 pHlp->pfnPrintf(pHlp, " (IGNORED)");
3279 pHlp->pfnPrintf(pHlp, "\n");
3280 devpciR3InfoIndent(pHlp, iIndentLvl);
3281 pHlp->pfnPrintf(pHlp, "behind bridge: ");
3282 uint32_t uPrefMemoryRegBase = devpciR3GetWord(pPciDevSub, VBOX_PCI_PREF_MEMORY_BASE);
3283 uint32_t uPrefMemoryRegLimit = devpciR3GetWord(pPciDevSub, VBOX_PCI_PREF_MEMORY_LIMIT);
3284 uint64_t uPrefMemoryBase = (uPrefMemoryRegBase & 0xfff0) << 16;
3285 uint64_t uPrefMemoryLimit = (uPrefMemoryRegLimit & 0xfff0) << 16 | 0xfffff;
3286 if ( (uPrefMemoryRegBase & 0xf) == 1
3287 && (uPrefMemoryRegLimit & 0xf) == 1)
3288 {
3289 uPrefMemoryBase |= (uint64_t)devpciR3GetDWord(pPciDevSub, VBOX_PCI_PREF_BASE_UPPER32) << 32;
3290 uPrefMemoryLimit |= (uint64_t)devpciR3GetDWord(pPciDevSub, VBOX_PCI_PREF_LIMIT_UPPER32) << 32;
3291 pHlp->pfnPrintf(pHlp, "64-bit ");
3292 }
3293 else
3294 pHlp->pfnPrintf(pHlp, "32-bit ");
3295 pHlp->pfnPrintf(pHlp, "prefetch memory %#018llx..%#018llx", uPrefMemoryBase, uPrefMemoryLimit);
3296 if (uPrefMemoryBase > uPrefMemoryLimit)
3297 pHlp->pfnPrintf(pHlp, " (IGNORED)");
3298 pHlp->pfnPrintf(pHlp, "\n");
3299 devpciR3InfoPciBus(pBusSub, pHlp, iIndentLvl + 1, fRegisters);
3300 }
3301 }
3302}
3303
3304
3305/**
3306 * @callback_method_impl{FNDBGFHANDLERDEV, 'pci'}
3307 */
3308DECLCALLBACK(void) devpciR3InfoPci(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3309{
3310 PDEVPCIBUS pBus = DEVINS_2_DEVPCIBUS(pDevIns);
3311
3312 if (pszArgs == NULL || !*pszArgs || !strcmp(pszArgs, "basic"))
3313 devpciR3InfoPciBus(pBus, pHlp, 0 /*iIndentLvl*/, false /*fRegisters*/);
3314 else if (!strcmp(pszArgs, "verbose"))
3315 devpciR3InfoPciBus(pBus, pHlp, 0 /*iIndentLvl*/, true /*fRegisters*/);
3316 else
3317 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'verbose'.\n");
3318}
3319
3320
3321/**
3322 * @callback_method_impl{FNDBGFHANDLERDEV, 'pciirq'}
3323 */
3324DECLCALLBACK(void) devpciR3InfoPciIrq(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
3325{
3326 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3327 NOREF(pszArgs);
3328
3329 pHlp->pfnPrintf(pHlp, "PCI I/O APIC IRQ levels:\n");
3330 for (int i = 0; i < DEVPCI_APIC_IRQ_PINS; ++i)
3331 pHlp->pfnPrintf(pHlp, " IRQ%02d: %u\n", 0x10 + i, pPciRoot->auPciApicIrqLevels[i]);
3332}
3333
3334
3335/**
3336 * @interface_method_impl{PDMDEVREG,pfnConstruct}
3337 */
3338static DECLCALLBACK(int) ich9pciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
3339{
3340 RT_NOREF1(iInstance);
3341 Assert(iInstance == 0);
3342 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3343
3344 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3345 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3346 PDEVPCIBUS pBus = &pPciRoot->PciBus;
3347 Assert(ASMMemIsZero(pPciRoot, sizeof(*pPciRoot))); /* code used to memset it for some funny reason. just temp insurance. */
3348
3349 /*
3350 * Validate and read configuration.
3351 */
3352 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "IOAPIC|McfgBase|McfgLength", "");
3353
3354 /* query whether we got an IOAPIC */
3355 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &pPciRoot->fUseIoApic, false /** @todo default to true? */);
3356 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to query boolean value \"IOAPIC\"")));
3357
3358 if (!pPciRoot->fUseIoApic)
3359 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Must use IO-APIC with ICH9 chipset"));
3360
3361 rc = CFGMR3QueryU64Def(pCfg, "McfgBase", &pPciRoot->u64PciConfigMMioAddress, 0);
3362 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"McfgBase\"")));
3363
3364 rc = CFGMR3QueryU64Def(pCfg, "McfgLength", &pPciRoot->u64PciConfigMMioLength, 0);
3365 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to read \"McfgLength\"")));
3366
3367 Log(("PCI: fUseIoApic=%RTbool McfgBase=%#RX64 McfgLength=%#RX64 fR0Enabled=%RTbool fRCEnabled=%RTbool\n", pPciRoot->fUseIoApic,
3368 pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength, pDevIns->fR0Enabled, pDevIns->fRCEnabled));
3369
3370 /*
3371 * Init data.
3372 */
3373 /* And fill values */
3374 pBusCC->pDevInsR3 = pDevIns;
3375 pPciRoot->PciBus.fTypePiix3 = false;
3376 pPciRoot->PciBus.fTypeIch9 = true;
3377 pPciRoot->PciBus.fPureBridge = false;
3378 pPciRoot->PciBus.papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pPciRoot->PciBus.apDevices));
3379 AssertLogRelReturn(pPciRoot->PciBus.papBridgesR3, VERR_NO_MEMORY);
3380
3381 /*
3382 * Disable default device locking.
3383 */
3384 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3385 AssertRCReturn(rc, rc);
3386
3387 /*
3388 * Register bus
3389 */
3390 PDMPCIBUSREGCC PciBusReg;
3391 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3392 PciBusReg.pfnRegisterR3 = devpciR3CommonRegisterDevice;
3393 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
3394 PciBusReg.pfnIORegionRegisterR3 = devpciR3CommonIORegionRegister;
3395 PciBusReg.pfnInterceptConfigAccesses = devpciR3CommonInterceptConfigAccesses;
3396 PciBusReg.pfnConfigRead = devpciR3CommonConfigRead;
3397 PciBusReg.pfnConfigWrite = devpciR3CommonConfigWrite;
3398 PciBusReg.pfnSetIrqR3 = ich9pciSetIrq;
3399 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3400 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBusCC->pPciHlpR3, &pBus->iBus);
3401 if (RT_FAILURE(rc))
3402 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as a PCI Bus"));
3403 Assert(pBus->iBus == 0);
3404 if (pBusCC->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
3405 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
3406 N_("PCI helper version mismatch; got %#x expected %#x"),
3407 pBusCC->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
3408
3409 /*
3410 * Fill in PCI configs and add them to the bus.
3411 */
3412 /** @todo Disabled for now because this causes error messages with Linux guests.
3413 * The guest loads the x38_edac device which tries to map a memory region
3414 * using an address given at place 0x48 - 0x4f in the PCI config space.
3415 * This fails. because we don't register such a region.
3416 */
3417#if 0
3418 /* Host bridge device */
3419 PDMPciDevSetVendorId( &pBus->PciDev, 0x8086); /* Intel */
3420 PDMPciDevSetDeviceId( &pBus->PciDev, 0x29e0); /* Desktop */
3421 PDMPciDevSetRevisionId(&pBus->PciDev, 0x01); /* rev. 01 */
3422 PDMPciDevSetClassBase( &pBus->PciDev, 0x06); /* bridge */
3423 PDMPciDevSetClassSub( &pBus->PciDev, 0x00); /* Host/PCI bridge */
3424 PDMPciDevSetClassProg( &pBus->PciDev, 0x00); /* Host/PCI bridge */
3425 PDMPciDevSetHeaderType(&pBus->PciDev, 0x00); /* bridge */
3426 PDMPciDevSetWord(&pBus->PciDev, VBOX_PCI_SEC_STATUS, 0x0280); /* secondary status */
3427
3428 pBus->PciDev.pDevIns = pDevIns;
3429 /* We register Host<->PCI controller on the bus */
3430 ich9pciRegisterInternal(pBus, 0, &pBus->PciDev, "dram");
3431#endif
3432
3433 /*
3434 * Register I/O ports.
3435 */
3436 static const IOMIOPORTDESC s_aAddrDesc[] = { { "PCI address", "PCI address", NULL, NULL }, { NULL, NULL, NULL, NULL } };
3437 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x0cf8, 1, ich9pciIOPortAddressWrite, ich9pciIOPortAddressRead,
3438 "ICH9 (PCI)", s_aAddrDesc, &pPciRoot->hIoPortAddress);
3439 AssertLogRelRCReturn(rc, rc);
3440
3441 static const IOMIOPORTDESC s_aDataDesc[] = { { "PCI data", "PCI data", NULL, NULL }, { NULL, NULL, NULL, NULL } };
3442 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x0cfc, 4, ich9pciIOPortDataWrite, ich9pciIOPortDataRead,
3443 "ICH9 (PCI)", s_aDataDesc, &pPciRoot->hIoPortData);
3444 AssertLogRelRCReturn(rc, rc);
3445
3446 static const IOMIOPORTDESC s_aMagicDesc[] = { { "PCI magic", NULL, NULL, NULL }, { NULL, NULL, NULL, NULL } };
3447 rc = PDMDevHlpIoPortCreateAndMap(pDevIns, 0x0410, 1, ich9pciR3IOPortMagicPCIWrite, ich9pciR3IOPortMagicPCIRead,
3448 "ICH9 (Fake PCI BIOS trigger)", s_aMagicDesc, &pPciRoot->hIoPortMagic);
3449 AssertLogRelRCReturn(rc, rc);
3450
3451 /*
3452 * MMIO handlers.
3453 */
3454 if (pPciRoot->u64PciConfigMMioAddress != 0)
3455 {
3456/** @todo implement new-style MMIO */
3457 rc = PDMDevHlpMMIORegister(pDevIns, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength, NULL /*pvUser*/,
3458 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
3459 ich9pciMcfgMMIOWrite, ich9pciMcfgMMIORead, "MCFG ranges");
3460 AssertMsgRCReturn(rc, ("rc=%Rrc %#llx/%#llx\n", rc, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength), rc);
3461
3462 if (pDevIns->fRCEnabled)
3463 {
3464 rc = PDMDevHlpMMIORegisterRC(pDevIns, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength,
3465 NIL_RTRCPTR /*pvUser*/, "ich9pciMcfgMMIOWrite", "ich9pciMcfgMMIORead");
3466 AssertRCReturn(rc, rc);
3467 }
3468
3469
3470 if (pDevIns->fR0Enabled)
3471 {
3472 rc = PDMDevHlpMMIORegisterR0(pDevIns, pPciRoot->u64PciConfigMMioAddress, pPciRoot->u64PciConfigMMioLength,
3473 NIL_RTR0PTR /*pvUser*/, "ich9pciMcfgMMIOWrite", "ich9pciMcfgMMIORead");
3474 AssertRCReturn(rc, rc);
3475 }
3476 }
3477
3478 /*
3479 * Saved state and info handlers.
3480 */
3481 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION,
3482 sizeof(*pBus) + 16*128, "pgm",
3483 NULL, NULL, NULL,
3484 NULL, ich9pciR3SaveExec, NULL,
3485 NULL, ich9pciR3LoadExec, NULL);
3486 AssertRCReturn(rc, rc);
3487
3488 /** @todo other chipset devices shall be registered too */
3489
3490 PDMDevHlpDBGFInfoRegister(pDevIns, "pci",
3491 "Display PCI bus status. Recognizes 'basic' or 'verbose' as arguments, defaults to 'basic'.",
3492 devpciR3InfoPci);
3493 PDMDevHlpDBGFInfoRegister(pDevIns, "pciirq", "Display PCI IRQ state. (no arguments)", devpciR3InfoPciIrq);
3494
3495 return VINF_SUCCESS;
3496}
3497
3498
3499/**
3500 * @interface_method_impl{PDMDEVREG,pfnDestruct}
3501 */
3502static DECLCALLBACK(int) ich9pciR3Destruct(PPDMDEVINS pDevIns)
3503{
3504 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3505 if (pPciRoot->PciBus.papBridgesR3)
3506 {
3507 PDMDevHlpMMHeapFree(pDevIns, pPciRoot->PciBus.papBridgesR3);
3508 pPciRoot->PciBus.papBridgesR3 = NULL;
3509 }
3510 return VINF_SUCCESS;
3511}
3512
3513
3514/**
3515 * @param pDevIns The PCI bus device instance.
3516 * @param pDev The PCI device to reset.
3517 */
3518void devpciR3ResetDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pDev)
3519{
3520 /* Clear regions */
3521 for (int iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
3522 {
3523 PCIIOREGION *pRegion = &pDev->Int.s.aIORegions[iRegion];
3524 if (pRegion->size == 0)
3525 continue;
3526 bool const f64Bit = (pRegion->type & ((uint8_t)(PCI_ADDRESS_SPACE_BAR64 | PCI_ADDRESS_SPACE_IO)))
3527 == PCI_ADDRESS_SPACE_BAR64;
3528
3529 devpciR3UnmapRegion(pDevIns, pDev, iRegion);
3530
3531 if (f64Bit)
3532 iRegion++;
3533 }
3534
3535 if (pciDevIsPassthrough(pDev))
3536 {
3537 // no reset handler - we can do what we need in PDM reset handler
3538 /// @todo is it correct?
3539 }
3540 else
3541 {
3542 devpciR3SetWord(pDevIns, pDev, VBOX_PCI_COMMAND,
3543 devpciR3GetWord(pDev, VBOX_PCI_COMMAND)
3544 & ~(VBOX_PCI_COMMAND_IO | VBOX_PCI_COMMAND_MEMORY |
3545 VBOX_PCI_COMMAND_MASTER | VBOX_PCI_COMMAND_SPECIAL |
3546 VBOX_PCI_COMMAND_PARITY | VBOX_PCI_COMMAND_SERR |
3547 VBOX_PCI_COMMAND_FAST_BACK | VBOX_PCI_COMMAND_INTX_DISABLE));
3548
3549 /* Bridge device reset handlers processed later */
3550 if (!pciDevIsPci2PciBridge(pDev))
3551 {
3552 devpciR3SetByte(pDevIns, pDev, VBOX_PCI_CACHE_LINE_SIZE, 0x0);
3553 devpciR3SetByte(pDevIns, pDev, VBOX_PCI_INTERRUPT_LINE, 0x0);
3554 }
3555
3556 /* Reset MSI message control. */
3557 if (pciDevIsMsiCapable(pDev))
3558 devpciR3SetWord(pDevIns, pDev, pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL,
3559 devpciR3GetWord(pDev, pDev->Int.s.u8MsiCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL) & 0xff8e);
3560
3561 /* Reset MSI-X message control. */
3562 if (pciDevIsMsixCapable(pDev))
3563 devpciR3SetWord(pDevIns, pDev, pDev->Int.s.u8MsixCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL,
3564 devpciR3GetWord(pDev, pDev->Int.s.u8MsixCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL) & 0x3fff);
3565 }
3566}
3567
3568/**
3569 * Returns the PCI express encoding for the given PCI Express Device/Port type string.
3570 *
3571 * @returns PCI express encoding.
3572 * @param pszExpressPortType The string identifier for the port/device type.
3573 */
3574static uint8_t ich9pcibridgeR3GetExpressPortTypeFromString(const char *pszExpressPortType)
3575{
3576 if (!RTStrCmp(pszExpressPortType, "EndPtDev"))
3577 return VBOX_PCI_EXP_TYPE_ENDPOINT;
3578 if (!RTStrCmp(pszExpressPortType, "LegEndPtDev"))
3579 return VBOX_PCI_EXP_TYPE_LEG_END;
3580 if (!RTStrCmp(pszExpressPortType, "RootCmplxRootPort"))
3581 return VBOX_PCI_EXP_TYPE_ROOT_PORT;
3582 if (!RTStrCmp(pszExpressPortType, "ExpressSwUpstream"))
3583 return VBOX_PCI_EXP_TYPE_UPSTREAM;
3584 if (!RTStrCmp(pszExpressPortType, "ExpressSwDownstream"))
3585 return VBOX_PCI_EXP_TYPE_DOWNSTREAM;
3586 if (!RTStrCmp(pszExpressPortType, "Express2PciBridge"))
3587 return VBOX_PCI_EXP_TYPE_PCI_BRIDGE;
3588 if (!RTStrCmp(pszExpressPortType, "Pci2ExpressBridge"))
3589 return VBOX_PCI_EXP_TYPE_PCIE_BRIDGE;
3590 if (!RTStrCmp(pszExpressPortType, "RootCmplxIntEp"))
3591 return VBOX_PCI_EXP_TYPE_ROOT_INT_EP;
3592 if (!RTStrCmp(pszExpressPortType, "RootCmplxEc"))
3593 return VBOX_PCI_EXP_TYPE_ROOT_EC;
3594
3595 AssertLogRelMsgFailedReturn(("Unknown express port type specified"), VBOX_PCI_EXP_TYPE_ROOT_INT_EP);
3596}
3597
3598/**
3599 * Recursive worker for ich9pciReset.
3600 *
3601 * @param pDevIns ICH9 bridge (root or PCI-to-PCI) instance.
3602 */
3603static void ich9pciResetBridge(PPDMDEVINS pDevIns)
3604{
3605 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3606
3607 /* PCI-specific reset for each device. */
3608 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
3609 {
3610 if (pBus->apDevices[uDevFn])
3611 devpciR3ResetDevice(pDevIns, pBus->apDevices[uDevFn]);
3612 }
3613
3614 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
3615 {
3616 if (pBus->papBridgesR3[iBridge])
3617 ich9pciResetBridge(pBus->papBridgesR3[iBridge]->Int.s.CTX_SUFF(pDevIns));
3618 }
3619
3620 /* Reset topology config for non-root bridge. Last thing to do, otherwise
3621 * the secondary and subordinate are instantly unreachable. */
3622 if (pBus->iBus != 0)
3623 {
3624 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
3625
3626 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_PRIMARY_BUS, 0);
3627 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_SECONDARY_BUS, 0);
3628 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_SUBORDINATE_BUS, 0);
3629 /* Not resetting the address decoders of the bridge to 0, since the
3630 * PCI-to-PCI Bridge spec says that there is no default value. */
3631 }
3632}
3633
3634
3635/**
3636 * @interface_method_impl{PDMDEVREG,pfnReset}
3637 */
3638static DECLCALLBACK(void) ich9pciReset(PPDMDEVINS pDevIns)
3639{
3640 /* Reset everything under the root bridge. */
3641 ich9pciResetBridge(pDevIns);
3642}
3643
3644
3645/**
3646 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
3647 */
3648static DECLCALLBACK(void *) ich9pcibridgeQueryInterface(PPDMIBASE pInterface, const char *pszIID)
3649{
3650 PPDMDEVINS pDevIns = RT_FROM_MEMBER(pInterface, PDMDEVINS, IBase);
3651 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDevIns->IBase);
3652
3653 /* HACK ALERT! Special access to the PDMPCIDEV structure of an ich9pcibridge
3654 instance (see PDMIICH9BRIDGEPDMPCIDEV_IID for details). */
3655 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIICH9BRIDGEPDMPCIDEV, pDevIns->apPciDevs[0]);
3656 return NULL;
3657}
3658
3659
3660/**
3661 * @interface_method_impl{PDMDEVREG,pfnDestruct}
3662 */
3663static DECLCALLBACK(int) ich9pcibridgeR3Destruct(PPDMDEVINS pDevIns)
3664{
3665 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3666 if (pBus->papBridgesR3)
3667 {
3668 PDMDevHlpMMHeapFree(pDevIns, pBus->papBridgesR3);
3669 pBus->papBridgesR3 = NULL;
3670 }
3671 return VINF_SUCCESS;
3672}
3673
3674
3675/**
3676 * @interface_method_impl{PDMDEVREG,pfnConstruct}
3677 */
3678static DECLCALLBACK(int) ich9pcibridgeR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
3679{
3680 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3681
3682 /*
3683 * Validate and read configuration.
3684 */
3685 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "ExpressEnabled|ExpressPortType", "");
3686
3687 /* check if we're supposed to implement a PCIe bridge. */
3688 bool fExpress;
3689 int rc = CFGMR3QueryBoolDef(pCfg, "ExpressEnabled", &fExpress, false);
3690 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to query boolean value \"ExpressEnabled\"")));
3691
3692 char szExpressPortType[80];
3693 rc = CFGMR3QueryStringDef(pCfg, "ExpressPortType", szExpressPortType, sizeof(szExpressPortType), "RootCmplxIntEp");
3694 AssertRCReturn(rc, PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: failed to read \"ExpressPortType\" as string")));
3695
3696 uint8_t const uExpressPortType = ich9pcibridgeR3GetExpressPortTypeFromString(szExpressPortType);
3697 Log(("PCI/bridge#%u: fR0Enabled=%RTbool fRCEnabled=%RTbool fExpress=%RTbool uExpressPortType=%u (%s)\n",
3698 iInstance, pDevIns->fR0Enabled, pDevIns->fRCEnabled, fExpress, uExpressPortType, szExpressPortType));
3699
3700 /*
3701 * Init data and register the PCI bus.
3702 */
3703 pDevIns->IBase.pfnQueryInterface = ich9pcibridgeQueryInterface;
3704
3705 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3706 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3707
3708 pBus->fTypePiix3 = false;
3709 pBus->fTypeIch9 = true;
3710 pBus->fPureBridge = true;
3711 pBusCC->pDevInsR3 = pDevIns;
3712 pBus->papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pBus->apDevices));
3713 AssertLogRelReturn(pBus->papBridgesR3, VERR_NO_MEMORY);
3714
3715 PDMPCIBUSREGCC PciBusReg;
3716 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3717 PciBusReg.pfnRegisterR3 = devpcibridgeR3CommonRegisterDevice;
3718 PciBusReg.pfnRegisterMsiR3 = ich9pciRegisterMsi;
3719 PciBusReg.pfnIORegionRegisterR3 = devpciR3CommonIORegionRegister;
3720 PciBusReg.pfnInterceptConfigAccesses = devpciR3CommonInterceptConfigAccesses;
3721 PciBusReg.pfnConfigWrite = devpciR3CommonConfigWrite;
3722 PciBusReg.pfnConfigRead = devpciR3CommonConfigRead;
3723 PciBusReg.pfnSetIrqR3 = ich9pcibridgeSetIrq;
3724 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3725 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBusCC->pPciHlpR3, &pBus->iBus);
3726 if (RT_FAILURE(rc))
3727 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as a PCI Bus"));
3728 Assert(pBus->iBus == (uint32_t)iInstance + 1); /* Can be removed when adding support for multiple bridge implementations. */
3729 if (pBusCC->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
3730 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
3731 N_("PCI helper version mismatch; got %#x expected %#x"),
3732 pBusCC->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
3733
3734 LogRel(("PCI: Registered bridge instance #%u as PDM bus no %u.\n", iInstance, pBus->iBus));
3735
3736
3737 /* Disable default device locking. */
3738 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3739 AssertRCReturn(rc, rc);
3740
3741 /*
3742 * Fill in PCI configs and add them to the bus.
3743 */
3744 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0];
3745 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev);
3746
3747 PDMPciDevSetVendorId( pPciDev, 0x8086); /* Intel */
3748 if (fExpress)
3749 {
3750 PDMPciDevSetDeviceId(pPciDev, 0x29e1); /* 82X38/X48 Express Host-Primary PCI Express Bridge. */
3751 PDMPciDevSetRevisionId(pPciDev, 0x01);
3752 }
3753 else
3754 {
3755 PDMPciDevSetDeviceId(pPciDev, 0x2448); /* 82801 Mobile PCI bridge. */
3756 PDMPciDevSetRevisionId(pPciDev, 0xf2);
3757 }
3758 PDMPciDevSetClassSub( pPciDev, 0x04); /* pci2pci */
3759 PDMPciDevSetClassBase( pPciDev, 0x06); /* PCI_bridge */
3760 if (fExpress)
3761 PDMPciDevSetClassProg(pPciDev, 0x00); /* Normal decoding. */
3762 else
3763 PDMPciDevSetClassProg(pPciDev, 0x01); /* Supports subtractive decoding. */
3764 PDMPciDevSetHeaderType(pPciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
3765 if (fExpress)
3766 {
3767 PDMPciDevSetCommand(pPciDev, VBOX_PCI_COMMAND_SERR);
3768 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST); /* Has capabilities. */
3769 PDMPciDevSetByte(pPciDev, VBOX_PCI_CACHE_LINE_SIZE, 8); /* 32 bytes */
3770 /* PCI Express */
3771 PDMPciDevSetByte(pPciDev, 0xa0 + 0, VBOX_PCI_CAP_ID_EXP); /* PCI_Express */
3772 PDMPciDevSetByte(pPciDev, 0xa0 + 1, 0); /* next */
3773 PDMPciDevSetWord(pPciDev, 0xa0 + 2,
3774 /* version */ 0x2
3775 | (uExpressPortType << 4));
3776 PDMPciDevSetDWord(pPciDev, 0xa0 + 4, VBOX_PCI_EXP_DEVCAP_RBE); /* Device capabilities. */
3777 PDMPciDevSetWord(pPciDev, 0xa0 + 8, 0x0000); /* Device control. */
3778 PDMPciDevSetWord(pPciDev, 0xa0 + 10, 0x0000); /* Device status. */
3779 PDMPciDevSetDWord(pPciDev, 0xa0 + 12,
3780 /* Max Link Speed */ 2
3781 | /* Maximum Link Width */ (16 << 4)
3782 | /* Active State Power Management (ASPM) Sopport */ (0 << 10)
3783 | VBOX_PCI_EXP_LNKCAP_LBNC
3784 | /* Port Number */ ((2 + iInstance) << 24)); /* Link capabilities. */
3785 PDMPciDevSetWord(pPciDev, 0xa0 + 16, VBOX_PCI_EXP_LNKCTL_CLOCK); /* Link control. */
3786 PDMPciDevSetWord(pPciDev, 0xa0 + 18,
3787 /* Current Link Speed */ 2
3788 | /* Negotiated Link Width */ (16 << 4)
3789 | VBOX_PCI_EXP_LNKSTA_SL_CLK); /* Link status. */
3790 PDMPciDevSetDWord(pPciDev, 0xa0 + 20,
3791 /* Slot Power Limit Value */ (75 << 7)
3792 | /* Physical Slot Number */ (0 << 19)); /* Slot capabilities. */
3793 PDMPciDevSetWord(pPciDev, 0xa0 + 24, 0x0000); /* Slot control. */
3794 PDMPciDevSetWord(pPciDev, 0xa0 + 26, 0x0000); /* Slot status. */
3795 PDMPciDevSetWord(pPciDev, 0xa0 + 28, 0x0000); /* Root control. */
3796 PDMPciDevSetWord(pPciDev, 0xa0 + 30, 0x0000); /* Root capabilities. */
3797 PDMPciDevSetDWord(pPciDev, 0xa0 + 32, 0x00000000); /* Root status. */
3798 PDMPciDevSetDWord(pPciDev, 0xa0 + 36, 0x00000000); /* Device capabilities 2. */
3799 PDMPciDevSetWord(pPciDev, 0xa0 + 40, 0x0000); /* Device control 2. */
3800 PDMPciDevSetWord(pPciDev, 0xa0 + 42, 0x0000); /* Device status 2. */
3801 PDMPciDevSetDWord(pPciDev, 0xa0 + 44,
3802 /* Supported Link Speeds Vector */ (2 << 1)); /* Link capabilities 2. */
3803 PDMPciDevSetWord(pPciDev, 0xa0 + 48,
3804 /* Target Link Speed */ 2); /* Link control 2. */
3805 PDMPciDevSetWord(pPciDev, 0xa0 + 50, 0x0000); /* Link status 2. */
3806 PDMPciDevSetDWord(pPciDev, 0xa0 + 52, 0x00000000); /* Slot capabilities 2. */
3807 PDMPciDevSetWord(pPciDev, 0xa0 + 56, 0x0000); /* Slot control 2. */
3808 PDMPciDevSetWord(pPciDev, 0xa0 + 58, 0x0000); /* Slot status 2. */
3809 PDMPciDevSetCapabilityList(pPciDev, 0xa0);
3810 }
3811 else
3812 {
3813 PDMPciDevSetCommand(pPciDev, 0x00);
3814 PDMPciDevSetStatus(pPciDev, 0x20); /* 66MHz Capable. */
3815 }
3816 PDMPciDevSetInterruptLine(pPciDev, 0x00); /* This device does not assert interrupts. */
3817
3818 /*
3819 * This device does not generate interrupts. Interrupt delivery from
3820 * devices attached to the bus is unaffected.
3821 */
3822 PDMPciDevSetInterruptPin (pPciDev, 0x00);
3823
3824 if (fExpress)
3825 {
3826 /** @todo r=klaus set up the PCIe config space beyond the old 256 byte
3827 * limit, containing additional capability descriptors. */
3828 }
3829
3830 /*
3831 * Register this PCI bridge. The called function will take care on which bus we will get registered.
3832 */
3833 rc = PDMDevHlpPCIRegisterEx(pDevIns, pPciDev, PDMPCIDEVREG_F_PCI_BRIDGE, PDMPCIDEVREG_DEV_NO_FIRST_UNUSED,
3834 PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, "ich9pcibridge");
3835 AssertLogRelRCReturn(rc, rc);
3836
3837 pPciDev->Int.s.pfnBridgeConfigRead = ich9pcibridgeConfigRead;
3838 pPciDev->Int.s.pfnBridgeConfigWrite = ich9pcibridgeConfigWrite;
3839
3840 /*
3841 * Register SSM handlers. We use the same saved state version as for the host bridge
3842 * to make changes easier.
3843 */
3844 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_ICH9PCI_SAVED_STATE_VERSION,
3845 sizeof(*pBus) + 16*128,
3846 "pgm" /* before */,
3847 NULL, NULL, NULL,
3848 NULL, ich9pcibridgeR3SaveExec, NULL,
3849 NULL, ich9pcibridgeR3LoadExec, NULL);
3850 AssertLogRelRCReturn(rc, rc);
3851
3852 return VINF_SUCCESS;
3853}
3854
3855#else /* !IN_RING3 */
3856
3857/**
3858 * @interface_method_impl{PDMDEVREGR0,pfnConstruct}
3859 */
3860DECLCALLBACK(int) ich9pciRZConstruct(PPDMDEVINS pDevIns)
3861{
3862 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3863 PDEVPCIROOT pPciRoot = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
3864 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3865
3866 /* Mirror the ring-3 device lock disabling: */
3867 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3868 AssertRCReturn(rc, rc);
3869
3870 /* Set up the RZ PCI bus callbacks: */
3871 PDMPCIBUSREGCC PciBusReg;
3872 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3873 PciBusReg.iBus = pPciRoot->PciBus.iBus;
3874 PciBusReg.pfnSetIrq = ich9pciSetIrq;
3875 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3876 rc = PDMDevHlpPCIBusSetUpContext(pDevIns, &PciBusReg, &pBusCC->CTX_SUFF(pPciHlp));
3877 AssertRCReturn(rc, rc);
3878
3879 /* Set up I/O port callbacks, except for the magic port: */
3880 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pPciRoot->hIoPortAddress, ich9pciIOPortAddressWrite, ich9pciIOPortAddressRead, NULL);
3881 AssertLogRelRCReturn(rc, rc);
3882
3883 rc = PDMDevHlpIoPortSetUpContext(pDevIns, pPciRoot->hIoPortData, ich9pciIOPortDataWrite, ich9pciIOPortDataRead, NULL);
3884 AssertLogRelRCReturn(rc, rc);
3885
3886 /* Set up MMIO callbacks: */
3887 /** @todo new-style MMIO */
3888
3889 return rc;
3890}
3891
3892
3893/**
3894 * @interface_method_impl{PDMDEVREGR0,pfnConstruct}
3895 */
3896DECLCALLBACK(int) ich9pcibridgeRZConstruct(PPDMDEVINS pDevIns)
3897{
3898 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
3899 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
3900 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
3901
3902 /* Mirror the ring-3 device lock disabling: */
3903 int rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
3904 AssertRCReturn(rc, rc);
3905
3906 /* Set up the RZ PCI bus callbacks: */
3907 PDMPCIBUSREGCC PciBusReg;
3908 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
3909 PciBusReg.iBus = pBus->iBus;
3910 PciBusReg.pfnSetIrq = ich9pcibridgeSetIrq;
3911 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
3912 rc = PDMDevHlpPCIBusSetUpContext(pDevIns, &PciBusReg, &pBusCC->CTX_SUFF(pPciHlp));
3913 AssertRCReturn(rc, rc);
3914
3915 return rc;
3916}
3917
3918#endif /* !IN_RING3 */
3919
3920/**
3921 * The PCI bus device registration structure.
3922 */
3923const PDMDEVREG g_DevicePciIch9 =
3924{
3925 /* .u32Version = */ PDM_DEVREG_VERSION,
3926 /* .uReserved0 = */ 0,
3927 /* .szName = */ "ich9pci",
3928 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
3929 /* .fClass = */ PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
3930 /* .cMaxInstances = */ 1,
3931 /* .uSharedVersion = */ 42,
3932 /* .cbInstanceShared = */ sizeof(DEVPCIROOT),
3933 /* .cbInstanceCC = */ sizeof(CTX_SUFF(DEVPCIBUS)),
3934 /* .cbInstanceRC = */ sizeof(DEVPCIBUSRC),
3935 /* .cMaxPciDevices = */ 1,
3936 /* .cMaxMsixVectors = */ 0,
3937 /* .pszDescription = */ "ICH9 PCI bridge",
3938#if defined(IN_RING3)
3939 /* .pszRCMod = */ "VBoxDDRC.rc",
3940 /* .pszR0Mod = */ "VBoxDDR0.r0",
3941 /* .pfnConstruct = */ ich9pciR3Construct,
3942 /* .pfnDestruct = */ ich9pciR3Destruct,
3943 /* .pfnRelocate = */ NULL,
3944 /* .pfnMemSetup = */ NULL,
3945 /* .pfnPowerOn = */ NULL,
3946 /* .pfnReset = */ ich9pciReset,
3947 /* .pfnSuspend = */ NULL,
3948 /* .pfnResume = */ NULL,
3949 /* .pfnAttach = */ NULL,
3950 /* .pfnDetach = */ NULL,
3951 /* .pfnQueryInterface = */ NULL,
3952 /* .pfnInitComplete = */ NULL,
3953 /* .pfnPowerOff = */ NULL,
3954 /* .pfnSoftReset = */ NULL,
3955 /* .pfnReserved0 = */ NULL,
3956 /* .pfnReserved1 = */ NULL,
3957 /* .pfnReserved2 = */ NULL,
3958 /* .pfnReserved3 = */ NULL,
3959 /* .pfnReserved4 = */ NULL,
3960 /* .pfnReserved5 = */ NULL,
3961 /* .pfnReserved6 = */ NULL,
3962 /* .pfnReserved7 = */ NULL,
3963#elif defined(IN_RING0)
3964 /* .pfnEarlyConstruct = */ NULL,
3965 /* .pfnConstruct = */ ich9pciRZConstruct,
3966 /* .pfnDestruct = */ NULL,
3967 /* .pfnFinalDestruct = */ NULL,
3968 /* .pfnRequest = */ NULL,
3969 /* .pfnReserved0 = */ NULL,
3970 /* .pfnReserved1 = */ NULL,
3971 /* .pfnReserved2 = */ NULL,
3972 /* .pfnReserved3 = */ NULL,
3973 /* .pfnReserved4 = */ NULL,
3974 /* .pfnReserved5 = */ NULL,
3975 /* .pfnReserved6 = */ NULL,
3976 /* .pfnReserved7 = */ NULL,
3977#elif defined(IN_RC)
3978 /* .pfnConstruct = */ ich9pciRZConstruct,
3979 /* .pfnReserved0 = */ NULL,
3980 /* .pfnReserved1 = */ NULL,
3981 /* .pfnReserved2 = */ NULL,
3982 /* .pfnReserved3 = */ NULL,
3983 /* .pfnReserved4 = */ NULL,
3984 /* .pfnReserved5 = */ NULL,
3985 /* .pfnReserved6 = */ NULL,
3986 /* .pfnReserved7 = */ NULL,
3987#else
3988# error "Not in IN_RING3, IN_RING0 or IN_RC!"
3989#endif
3990 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
3991};
3992
3993/**
3994 * The device registration structure
3995 * for the PCI-to-PCI bridge.
3996 */
3997const PDMDEVREG g_DevicePciIch9Bridge =
3998{
3999 /* .u32Version = */ PDM_DEVREG_VERSION,
4000 /* .uReserved0 = */ 0,
4001 /* .szName = */ "ich9pcibridge",
4002 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RZ | PDM_DEVREG_FLAGS_NEW_STYLE,
4003 /* .fClass = */ PDM_DEVREG_CLASS_BUS_PCI,
4004 /* .cMaxInstances = */ ~0U,
4005 /* .uSharedVersion = */ 42,
4006 /* .cbInstanceShared = */ sizeof(DEVPCIBUS),
4007 /* .cbInstanceCC = */ sizeof(CTX_SUFF(DEVPCIBUS)),
4008 /* .cbInstanceRC = */ 0,
4009 /* .cMaxPciDevices = */ 1,
4010 /* .cMaxMsixVectors = */ 0,
4011 /* .pszDescription = */ "ICH9 PCI to PCI bridge",
4012#if defined(IN_RING3)
4013 /* .pszRCMod = */ "VBoxDDRC.rc",
4014 /* .pszR0Mod = */ "VBoxDDR0.r0",
4015 /* .pfnConstruct = */ ich9pcibridgeR3Construct,
4016 /* .pfnDestruct = */ ich9pcibridgeR3Destruct,
4017 /* .pfnRelocate = */ NULL,
4018 /* .pfnMemSetup = */ NULL,
4019 /* .pfnPowerOn = */ NULL,
4020 /* .pfnReset = */ NULL, /* Must be NULL, to make sure only bus driver handles reset */
4021 /* .pfnSuspend = */ NULL,
4022 /* .pfnResume = */ NULL,
4023 /* .pfnAttach = */ NULL,
4024 /* .pfnDetach = */ NULL,
4025 /* .pfnQueryInterface = */ NULL,
4026 /* .pfnInitComplete = */ NULL,
4027 /* .pfnPowerOff = */ NULL,
4028 /* .pfnSoftReset = */ NULL,
4029 /* .pfnReserved0 = */ NULL,
4030 /* .pfnReserved1 = */ NULL,
4031 /* .pfnReserved2 = */ NULL,
4032 /* .pfnReserved3 = */ NULL,
4033 /* .pfnReserved4 = */ NULL,
4034 /* .pfnReserved5 = */ NULL,
4035 /* .pfnReserved6 = */ NULL,
4036 /* .pfnReserved7 = */ NULL,
4037#elif defined(IN_RING0)
4038 /* .pfnEarlyConstruct = */ NULL,
4039 /* .pfnConstruct = */ ich9pcibridgeRZConstruct,
4040 /* .pfnDestruct = */ NULL,
4041 /* .pfnFinalDestruct = */ NULL,
4042 /* .pfnRequest = */ NULL,
4043 /* .pfnReserved0 = */ NULL,
4044 /* .pfnReserved1 = */ NULL,
4045 /* .pfnReserved2 = */ NULL,
4046 /* .pfnReserved3 = */ NULL,
4047 /* .pfnReserved4 = */ NULL,
4048 /* .pfnReserved5 = */ NULL,
4049 /* .pfnReserved6 = */ NULL,
4050 /* .pfnReserved7 = */ NULL,
4051#elif defined(IN_RC)
4052 /* .pfnConstruct = */ ich9pcibridgeRZConstruct,
4053 /* .pfnReserved0 = */ NULL,
4054 /* .pfnReserved1 = */ NULL,
4055 /* .pfnReserved2 = */ NULL,
4056 /* .pfnReserved3 = */ NULL,
4057 /* .pfnReserved4 = */ NULL,
4058 /* .pfnReserved5 = */ NULL,
4059 /* .pfnReserved6 = */ NULL,
4060 /* .pfnReserved7 = */ NULL,
4061#else
4062# error "Not in IN_RING3, IN_RING0 or IN_RC!"
4063#endif
4064 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
4065};
4066
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