VirtualBox

source: vbox/trunk/src/VBox/Devices/Bus/DevPCI.cpp@ 80952

Last change on this file since 80952 was 80944, checked in by vboxsync, 5 years ago

DevPCI: build fix. bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 76.1 KB
Line 
1/* $Id: DevPCI.cpp 80944 2019-09-23 10:39:57Z vboxsync $ */
2/** @file
3 * DevPCI - PCI BUS Device.
4 *
5 * @remarks New code shall be added to DevPciIch9.cpp as that will become
6 * the common PCI bus code soon. Don't fix code in both DevPCI.cpp
7 * and DevPciIch9.cpp when it's possible to just make the latter
8 * version common. Common code uses the 'devpci' prefix, is
9 * prototyped in DevPciInternal.h, and is defined in DevPciIch9.cpp.
10 */
11
12/*
13 * Copyright (C) 2006-2019 Oracle Corporation
14 *
15 * This file is part of VirtualBox Open Source Edition (OSE), as
16 * available from http://www.virtualbox.org. This file is free software;
17 * you can redistribute it and/or modify it under the terms of the GNU
18 * General Public License (GPL) as published by the Free Software
19 * Foundation, in version 2 as it comes in the "COPYING" file of the
20 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
21 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
22 * --------------------------------------------------------------------
23 *
24 * This code is based on:
25 *
26 * QEMU PCI bus manager
27 *
28 * Copyright (c) 2004 Fabrice Bellard
29 *
30 * Permission is hereby granted, free of charge, to any person obtaining a copy
31 * of this software and associated documentation files (the "Software"), to deal
32 * in the Software without restriction, including without limitation the rights
33 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34 * copies of the Software, and to permit persons to whom the Software is
35 * furnished to do so, subject to the following conditions:
36 *
37 * The above copyright notice and this permission notice shall be included in
38 * all copies or substantial portions of the Software.
39 *
40 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
43 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
46 * THE SOFTWARE.
47 */
48
49
50/*********************************************************************************************************************************
51* Header Files *
52*********************************************************************************************************************************/
53#define LOG_GROUP LOG_GROUP_DEV_PCI
54#define PDMPCIDEV_INCLUDE_PRIVATE /* Hack to get pdmpcidevint.h included at the right point. */
55#include <VBox/vmm/pdmpcidev.h>
56#include <VBox/vmm/pdmdev.h>
57#include <VBox/vmm/mm.h>
58#include <iprt/asm.h>
59#include <iprt/assert.h>
60#include <iprt/string.h>
61
62#include "PciInline.h"
63#include "VBoxDD.h"
64#include "DevPciInternal.h"
65
66
67/*********************************************************************************************************************************
68* Defined Constants And Macros *
69*********************************************************************************************************************************/
70/** Saved state version of the PCI bus device. */
71#define VBOX_PCI_SAVED_STATE_VERSION VBOX_PCI_SAVED_STATE_VERSION_REGION_SIZES
72/** Adds I/O region types and sizes for dealing changes in resource regions. */
73#define VBOX_PCI_SAVED_STATE_VERSION_REGION_SIZES 4
74/** Before region sizes, the first named one.
75 * Looking at the code though, we support even older version. */
76#define VBOX_PCI_SAVED_STATE_VERSION_IRQ_STATES 3
77/** Notes whether we use the I/O APIC. */
78#define VBOX_PCI_SAVED_STATE_VERSION_USE_IO_APIC 2
79
80
81/*********************************************************************************************************************************
82* Internal Functions *
83*********************************************************************************************************************************/
84RT_C_DECLS_BEGIN
85
86static DECLCALLBACK(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTag);
87PDMBOTHCBDECL(int) pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
88PDMBOTHCBDECL(int) pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
89PDMBOTHCBDECL(int) pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
90PDMBOTHCBDECL(int) pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
91
92#ifdef IN_RING3
93DECLINLINE(PPDMPCIDEV) pciR3FindBridge(PDEVPCIBUS pBus, uint8_t iBus);
94#endif
95
96RT_C_DECLS_END
97
98#define DEBUG_PCI
99
100#define PCI_VENDOR_ID 0x00 /* 16 bits */
101#define PCI_DEVICE_ID 0x02 /* 16 bits */
102#define PCI_COMMAND 0x04 /* 16 bits */
103#define PCI_COMMAND_IO 0x01 /* Enable response in I/O space */
104#define PCI_COMMAND_MEMORY 0x02 /* Enable response in Memory space */
105#define PCI_CLASS_DEVICE 0x0a /* Device class */
106#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
107#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
108#define PCI_MIN_GNT 0x3e /* 8 bits */
109#define PCI_MAX_LAT 0x3f /* 8 bits */
110
111
112static VBOXSTRICTRC pci_data_write(PPDMDEVINS pDevIns, PDEVPCIROOT pGlobals, uint32_t addr, uint32_t u32Value, int cb)
113{
114 LogFunc(("addr=%08x u32Value=%08x cb=%d\n", pGlobals->uConfigReg, u32Value, cb));
115
116 if (!(pGlobals->uConfigReg & (1 << 31)))
117 return VINF_SUCCESS;
118 if ((pGlobals->uConfigReg & 0x3) != 0)
119 return VINF_SUCCESS;
120
121 uint8_t const iBus = (pGlobals->uConfigReg >> 16) & 0xff;
122 uint8_t const iDevice = (pGlobals->uConfigReg >> 8) & 0xff;
123#ifdef IN_RING3
124 uint32_t const config_addr = (pGlobals->uConfigReg & 0xfc) | (addr & 3);
125#endif
126 RT_UNTRUSTED_VALIDATED_FENCE(); /* paranoia */
127
128 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
129 if (iBus != 0)
130 {
131 if (pGlobals->PciBus.cBridges)
132 {
133#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
134 PPDMPCIDEV pBridgeDevice = pciR3FindBridge(&pGlobals->PciBus, iBus);
135 if (pBridgeDevice)
136 {
137 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
138 rcStrict = pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus,
139 iDevice, config_addr, cb, u32Value);
140 }
141#else
142 RT_NOREF(pDevIns, addr, u32Value, cb);
143 rcStrict = VINF_IOM_R3_IOPORT_WRITE;
144#endif
145 }
146 }
147 else
148 {
149 R3PTRTYPE(PDMPCIDEV *) pPciDev = pGlobals->PciBus.apDevices[iDevice];
150 if (pPciDev)
151 {
152#ifdef IN_RING3
153 LogFunc(("%s: addr=%02x u32Value=%08x cb=%d\n", pPciDev->pszNameR3, config_addr, u32Value, cb));
154 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
155 if (pPciDev->Int.s.pfnConfigWrite)
156 rcStrict = pPciDev->Int.s.pfnConfigWrite(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, config_addr, cb, u32Value);
157 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
158 rcStrict = devpciR3CommonConfigWriteWorker(pDevIns, PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC),
159 pPciDev, config_addr, cb, u32Value);
160#else
161 rcStrict = VINF_IOM_R3_IOPORT_WRITE;
162#endif
163 }
164 }
165 return rcStrict;
166}
167
168static VBOXSTRICTRC pci_data_read(PDEVPCIROOT pGlobals, uint32_t addr, int cb, uint32_t *pu32Value)
169{
170 *pu32Value = UINT32_MAX;
171
172 if (!(pGlobals->uConfigReg & (1 << 31)))
173 return VINF_SUCCESS;
174 if ((pGlobals->uConfigReg & 0x3) != 0)
175 return VINF_SUCCESS;
176 uint8_t const iBus = (pGlobals->uConfigReg >> 16) & 0xff;
177 uint8_t const iDevice = (pGlobals->uConfigReg >> 8) & 0xff;
178#ifdef IN_RING3
179 uint32_t const config_addr = (pGlobals->uConfigReg & 0xfc) | (addr & 3);
180#endif
181 RT_UNTRUSTED_VALIDATED_FENCE();
182
183 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
184 if (iBus != 0)
185 {
186 if (pGlobals->PciBus.cBridges)
187 {
188#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
189 PPDMPCIDEV pBridgeDevice = pciR3FindBridge(&pGlobals->PciBus, iBus);
190 if (pBridgeDevice)
191 {
192 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
193 rcStrict = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->Int.s.CTX_SUFF(pDevIns),
194 iBus, iDevice, config_addr, cb, pu32Value);
195 }
196#else
197 RT_NOREF(addr, cb);
198 rcStrict = VINF_IOM_R3_IOPORT_READ;
199#endif
200 }
201 }
202 else
203 {
204 R3PTRTYPE(PDMPCIDEV *) pPciDev = pGlobals->PciBus.apDevices[iDevice];
205 if (pPciDev)
206 {
207#ifdef IN_RING3
208 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
209 if (pPciDev->Int.s.pfnConfigRead)
210 rcStrict = pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, config_addr, cb, pu32Value);
211 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
212 rcStrict = devpciR3CommonConfigReadWorker(pPciDev, config_addr, cb, pu32Value);
213 LogFunc(("%s: addr=%02x val=%08x cb=%d\n", pPciDev->pszNameR3, config_addr, *pu32Value, cb));
214#else
215 NOREF(cb);
216 rcStrict = VINF_IOM_R3_IOPORT_READ;
217#endif
218 }
219 }
220
221 return rcStrict;
222}
223
224
225
226/* return the global irq number corresponding to a given device irq
227 pin. We could also use the bus number to have a more precise
228 mapping.
229 This is the implementation note described in the PCI spec chapter 2.2.6 */
230static inline int pci_slot_get_pirq(uint8_t uDevFn, int irq_num)
231{
232 int slot_addend;
233 slot_addend = (uDevFn >> 3) - 1;
234 return (irq_num + slot_addend) & 3;
235}
236
237static inline int pci_slot_get_apic_pirq(uint8_t uDevFn, int irq_num)
238{
239 return (irq_num + (uDevFn >> 3)) & 7;
240}
241
242static inline int get_pci_irq_apic_level(PDEVPCIROOT pGlobals, int irq_num)
243{
244 return (pGlobals->auPciApicIrqLevels[irq_num] != 0);
245}
246
247static void apic_set_irq(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PDEVPCIBUSCC pBusCC,
248 uint8_t uDevFn, PDMPCIDEV *pPciDev, int irq_num1, int iLevel, int iAcpiIrq, uint32_t uTagSrc)
249{
250 /* This is only allowed to be called with a pointer to the host bus. */
251 AssertMsg(pBus->iBus == 0, ("iBus=%u\n", pBus->iBus));
252
253 if (iAcpiIrq == -1) {
254 int apic_irq, apic_level;
255 PDEVPCIROOT pGlobals = DEVPCIBUS_2_DEVPCIROOT(pBus);
256 int irq_num = pci_slot_get_apic_pirq(uDevFn, irq_num1);
257
258 if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_HIGH)
259 ASMAtomicIncU32(&pGlobals->auPciApicIrqLevels[irq_num]);
260 else if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_LOW)
261 ASMAtomicDecU32(&pGlobals->auPciApicIrqLevels[irq_num]);
262
263 apic_irq = irq_num + 0x10;
264 apic_level = get_pci_irq_apic_level(pGlobals, irq_num);
265 Log3Func(("%s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d\n",
266 R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, apic_irq, apic_level, irq_num));
267 pBusCC->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pDevIns, apic_irq, apic_level, uTagSrc);
268
269 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) {
270 ASMAtomicDecU32(&pGlobals->auPciApicIrqLevels[irq_num]);
271 pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
272 apic_level = get_pci_irq_apic_level(pGlobals, irq_num);
273 Log3Func(("%s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d (flop)\n",
274 R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, apic_irq, apic_level, irq_num));
275 pBusCC->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pDevIns, apic_irq, apic_level, uTagSrc);
276 }
277 } else {
278 Log3Func(("%s: irq_num1=%d level=%d iAcpiIrq=%d\n",
279 R3STRING(pPciDev->pszNameR3), irq_num1, iLevel, iAcpiIrq));
280 pBusCC->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pDevIns, iAcpiIrq, iLevel, uTagSrc);
281 }
282}
283
284DECLINLINE(int) get_pci_irq_level(PDEVPCIROOT pGlobals, int irq_num)
285{
286 return (pGlobals->Piix3.auPciLegacyIrqLevels[irq_num] != 0);
287}
288
289/**
290 * Set the IRQ for a PCI device on the host bus - shared by host bus and bridge.
291 *
292 * @param pPdmDev The PDM device instance for the PCI bus.
293 * @param pGlobals Device instance of the host PCI bus.
294 * @param pBusCC Context specific data for the PCI bus.
295 * @param uDevFn The device number on the host bus which will raise the IRQ
296 * @param pPciDev The PCI device structure which raised the interrupt.
297 * @param iIrq IRQ number to set.
298 * @param iLevel IRQ level.
299 * @param uTagSrc The IRQ tag and source ID (for tracing).
300 * @remark uDevFn and pPciDev->uDevFn are not the same if the device is behind
301 * a bridge. In that case uDevFn will be the slot of the bridge which
302 * is needed to calculate the PIRQ value.
303 */
304static void pciSetIrqInternal(PPDMDEVINS pDevIns, PDEVPCIROOT pGlobals, PDEVPCIBUSCC pBusCC,
305 uint8_t uDevFn, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
306{
307 PDEVPCIBUS pBus = &pGlobals->PciBus;
308 uint8_t *pbCfg = pGlobals->Piix3.PIIX3State.dev.abConfig;
309 const bool fIsAcpiDevice = pPciDev->abConfig[2] == 0x13 && pPciDev->abConfig[3] == 0x71;
310 /* If the two configuration space bytes at 0xde, 0xad are set to 0xbe, 0xef, a back door
311 * is opened to route PCI interrupts directly to the I/O APIC and bypass the PIC.
312 * See the \_SB_.PCI0._PRT method in vbox.dsl.
313 */
314 const bool fIsApicEnabled = pGlobals->fUseIoApic && pbCfg[0xde] == 0xbe && pbCfg[0xad] == 0xef;
315 int pic_irq, pic_level;
316
317 /* Check if the state changed. */
318 if (pPciDev->Int.s.uIrqPinState != iLevel)
319 {
320 pPciDev->Int.s.uIrqPinState = (iLevel & PDM_IRQ_LEVEL_HIGH);
321
322 /* Send interrupt to I/O APIC only. */
323 if (fIsApicEnabled)
324 {
325 if (fIsAcpiDevice)
326 /*
327 * ACPI needs special treatment since SCI is hardwired and
328 * should not be affected by PCI IRQ routing tables at the
329 * same time SCI IRQ is shared in PCI sense hence this
330 * kludge (i.e. we fetch the hardwired value from ACPIs
331 * PCI device configuration space).
332 */
333 apic_set_irq(pDevIns, pBus, pBusCC, uDevFn, pPciDev, -1, iLevel, pPciDev->abConfig[PCI_INTERRUPT_LINE], uTagSrc);
334 else
335 apic_set_irq(pDevIns, pBus, pBusCC, uDevFn, pPciDev, iIrq, iLevel, -1, uTagSrc);
336 return;
337 }
338
339 if (fIsAcpiDevice)
340 {
341 /* As per above treat ACPI in a special way */
342 pic_irq = pPciDev->abConfig[PCI_INTERRUPT_LINE];
343 pGlobals->Piix3.iAcpiIrq = pic_irq;
344 pGlobals->Piix3.iAcpiIrqLevel = iLevel & PDM_IRQ_LEVEL_HIGH;
345 }
346 else
347 {
348 int irq_num;
349 irq_num = pci_slot_get_pirq(uDevFn, iIrq);
350
351 if (pPciDev->Int.s.uIrqPinState == PDM_IRQ_LEVEL_HIGH)
352 ASMAtomicIncU32(&pGlobals->Piix3.auPciLegacyIrqLevels[irq_num]);
353 else if (pPciDev->Int.s.uIrqPinState == PDM_IRQ_LEVEL_LOW)
354 ASMAtomicDecU32(&pGlobals->Piix3.auPciLegacyIrqLevels[irq_num]);
355
356 /* now we change the pic irq level according to the piix irq mappings */
357 pic_irq = pbCfg[0x60 + irq_num];
358 if (pic_irq >= 16)
359 {
360 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
361 {
362 ASMAtomicDecU32(&pGlobals->Piix3.auPciLegacyIrqLevels[irq_num]);
363 pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
364 }
365
366 return;
367 }
368 }
369
370 /* the pic level is the logical OR of all the PCI irqs mapped to it */
371 pic_level = 0;
372 if (pic_irq == pbCfg[0x60])
373 pic_level |= get_pci_irq_level(pGlobals, 0); /* PIRQA */
374 if (pic_irq == pbCfg[0x61])
375 pic_level |= get_pci_irq_level(pGlobals, 1); /* PIRQB */
376 if (pic_irq == pbCfg[0x62])
377 pic_level |= get_pci_irq_level(pGlobals, 2); /* PIRQC */
378 if (pic_irq == pbCfg[0x63])
379 pic_level |= get_pci_irq_level(pGlobals, 3); /* PIRQD */
380 if (pic_irq == pGlobals->Piix3.iAcpiIrq)
381 pic_level |= pGlobals->Piix3.iAcpiIrqLevel;
382
383 Log3Func(("%s: iLevel=%d iIrq=%d pic_irq=%d pic_level=%d uTagSrc=%#x\n",
384 R3STRING(pPciDev->pszNameR3), iLevel, iIrq, pic_irq, pic_level, uTagSrc));
385 pBusCC->CTX_SUFF(pPciHlp)->pfnIsaSetIrq(pDevIns, pic_irq, pic_level, uTagSrc);
386
387 /** @todo optimize pci irq flip-flop some rainy day. */
388 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
389 pciSetIrqInternal(pDevIns, pGlobals, pBusCC, uDevFn, pPciDev, iIrq, PDM_IRQ_LEVEL_LOW, uTagSrc);
390 }
391}
392
393
394/**
395 * @interface_method_impl{PDMPCIBUSREG,pfnSetIrqR3}
396 */
397static DECLCALLBACK(void) pciSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
398{
399 PDEVPCIROOT pBus = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
400 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
401 LogFlow(("pciSetIrq: %p %u %u %#x\n", pPciDev, iIrq, iLevel, uTagSrc));
402 pciSetIrqInternal(pDevIns, pBus, pBusCC, pPciDev->uDevFn, pPciDev, iIrq, iLevel, uTagSrc);
403}
404
405#ifdef IN_RING3
406
407/**
408 * Finds a bridge on the bus which contains the destination bus.
409 *
410 * @return Pointer to the device instance data of the bus or
411 * NULL if no bridge was found.
412 * @param pBus Pointer to the bus to search on.
413 * @param iBus Destination bus number.
414 */
415DECLINLINE(PPDMPCIDEV) pciR3FindBridge(PDEVPCIBUS pBus, uint8_t iBus)
416{
417 /* Search for a fitting bridge. */
418 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
419 {
420 /*
421 * Examine secondary and subordinate bus number.
422 * If the target bus is in the range we pass the request on to the bridge.
423 */
424 PPDMPCIDEV pBridgeTemp = pBus->papBridgesR3[iBridge];
425 AssertMsg(pBridgeTemp && pciDevIsPci2PciBridge(pBridgeTemp),
426 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
427
428 if ( iBus >= pBridgeTemp->abConfig[VBOX_PCI_SECONDARY_BUS]
429 && iBus <= pBridgeTemp->abConfig[VBOX_PCI_SUBORDINATE_BUS])
430 return pBridgeTemp;
431 }
432
433 /* Nothing found. */
434 return NULL;
435}
436
437static void pciR3Piix3Reset(PIIX3ISABRIDGE *d)
438{
439 uint8_t *pci_conf = d->dev.abConfig;
440
441 pci_conf[0x04] = 0x07; /* master, memory and I/O */
442 pci_conf[0x05] = 0x00;
443 pci_conf[0x06] = 0x00;
444 pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */
445 pci_conf[0x4c] = 0x4d;
446 pci_conf[0x4e] = 0x03;
447 pci_conf[0x4f] = 0x00;
448 pci_conf[0x60] = 0x80;
449 pci_conf[0x69] = 0x02;
450 pci_conf[0x70] = 0x80;
451 pci_conf[0x76] = 0x0c;
452 pci_conf[0x77] = 0x0c;
453 pci_conf[0x78] = 0x02;
454 pci_conf[0x79] = 0x00;
455 pci_conf[0x80] = 0x00;
456 pci_conf[0x82] = 0x02; /* Get rid of the Linux guest "Enabling Passive Release" PCI quirk warning. */
457 pci_conf[0xa0] = 0x08;
458 pci_conf[0xa2] = 0x00;
459 pci_conf[0xa3] = 0x00;
460 pci_conf[0xa4] = 0x00;
461 pci_conf[0xa5] = 0x00;
462 pci_conf[0xa6] = 0x00;
463 pci_conf[0xa7] = 0x00;
464 pci_conf[0xa8] = 0x0f;
465 pci_conf[0xaa] = 0x00;
466 pci_conf[0xab] = 0x00;
467 pci_conf[0xac] = 0x00;
468 pci_conf[0xae] = 0x00;
469}
470
471/* host irqs corresponding to PCI irqs A-D */
472static const uint8_t pci_irqs[4] = { 11, 10, 9, 11 }; /* bird: added const */
473
474static void pci_bios_init_device(PPDMDEVINS pDevIns, PDEVPCIROOT pGlobals, PDEVPCIBUS pBus,
475 PPDMPCIDEV pPciDev, uint8_t cBridgeDepth, uint8_t *paBridgePositions)
476{
477 uint32_t *paddr;
478 int pin, pic_irq;
479 uint16_t devclass, vendor_id, device_id;
480
481 devclass = devpciR3GetWord(pPciDev, PCI_CLASS_DEVICE);
482 vendor_id = devpciR3GetWord(pPciDev, PCI_VENDOR_ID);
483 device_id = devpciR3GetWord(pPciDev, PCI_DEVICE_ID);
484
485 /* Check if device is present. */
486 if (vendor_id != 0xffff)
487 {
488 switch(devclass)
489 {
490 case 0x0101:
491 if ( (vendor_id == 0x8086)
492 && (device_id == 0x7010 || device_id == 0x7111 || device_id == 0x269e))
493 {
494 /* PIIX3, PIIX4 or ICH6 IDE */
495 devpciR3SetWord(pDevIns, pPciDev, 0x40, 0x8011); /* enable IDE0 + fast timing */
496 devpciR3SetWord(pDevIns, pPciDev, 0x42, 0x8011); /* enable IDE1 + fast timing */
497 goto default_map;
498 }
499 else
500 {
501 /* IDE: we map it as in ISA mode */
502 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, 0, 0x1f0);
503 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, 1, 0x3f4);
504 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, 2, 0x170);
505 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, 3, 0x374);
506 devpciR3SetWord(pDevIns, pPciDev, PCI_COMMAND,
507 devpciR3GetWord(pPciDev, PCI_COMMAND)
508 | PCI_COMMAND_IOACCESS);
509 }
510 break;
511 case 0x0300:
512 {
513 if (vendor_id != 0x80ee)
514 goto default_map;
515 /* VGA: map frame buffer to default Bochs VBE address */
516 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, 0, 0xe0000000);
517 /*
518 * Legacy VGA I/O ports are implicitly decoded by a VGA class device. But
519 * only the framebuffer (i.e., a memory region) is explicitly registered via
520 * devpciR3BiosInitSetRegionAddress, so don't forget to enable I/O decoding.
521 */
522 devpciR3SetWord(pDevIns, pPciDev, PCI_COMMAND,
523 devpciR3GetWord(pPciDev, PCI_COMMAND)
524 | PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS);
525 break;
526 }
527 case 0x0800:
528 /* PIC */
529 vendor_id = devpciR3GetWord(pPciDev, PCI_VENDOR_ID);
530 device_id = devpciR3GetWord(pPciDev, PCI_DEVICE_ID);
531 if (vendor_id == 0x1014)
532 {
533 /* IBM */
534 if (device_id == 0x0046 || device_id == 0xFFFF)
535 {
536 /* MPIC & MPIC2 */
537 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, 0, 0x80800000 + 0x00040000);
538 devpciR3SetWord(pDevIns, pPciDev, PCI_COMMAND,
539 devpciR3GetWord(pPciDev, PCI_COMMAND)
540 | PCI_COMMAND_MEMACCESS);
541 }
542 }
543 break;
544 case 0xff00:
545 if ( (vendor_id == 0x0106b)
546 && (device_id == 0x0017 || device_id == 0x0022))
547 {
548 /* macio bridge */
549 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, 0, 0x80800000);
550 devpciR3SetWord(pDevIns, pPciDev, PCI_COMMAND,
551 devpciR3GetWord(pPciDev, PCI_COMMAND)
552 | PCI_COMMAND_MEMACCESS);
553 }
554 break;
555 case 0x0604:
556 {
557 /* Init PCI-to-PCI bridge. */
558 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_PRIMARY_BUS, pBus->iBus);
559
560 AssertMsg(pGlobals->uPciBiosBus < 255, ("Too many bridges on the bus\n"));
561 pGlobals->uPciBiosBus++;
562 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_SECONDARY_BUS, pGlobals->uPciBiosBus);
563 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_SUBORDINATE_BUS, 0xff); /* Temporary until we know how many other bridges are behind this one. */
564
565 /* Add position of this bridge into the array. */
566 paBridgePositions[cBridgeDepth+1] = (pPciDev->uDevFn >> 3);
567
568 /*
569 * The I/O range for the bridge must be aligned to a 4KB boundary.
570 * This does not change anything really as the access to the device is not going
571 * through the bridge but we want to be compliant to the spec.
572 */
573 if ((pGlobals->uPciBiosIo % _4K) != 0)
574 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, _4K);
575 LogFunc(("Aligned I/O start address. New address %#x\n", pGlobals->uPciBiosIo));
576 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_IO_BASE, (pGlobals->uPciBiosIo >> 8) & 0xf0);
577
578 /* The MMIO range for the bridge must be aligned to a 1MB boundary. */
579 if ((pGlobals->uPciBiosMmio % _1M) != 0)
580 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, _1M);
581 LogFunc(("Aligned MMIO start address. New address %#x\n", pGlobals->uPciBiosMmio));
582 devpciR3SetWord(pDevIns, pPciDev, VBOX_PCI_MEMORY_BASE, (pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xffff0));
583
584 /* Save values to compare later to. */
585 uint32_t u32IoAddressBase = pGlobals->uPciBiosIo;
586 uint32_t u32MMIOAddressBase = pGlobals->uPciBiosMmio;
587
588 /* Init devices behind the bridge and possibly other bridges as well. */
589 PDEVPCIBUS pChildBus = PDMINS_2_DATA(pPciDev->Int.s.CTX_SUFF(pDevIns), PDEVPCIBUS);
590 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pChildBus->apDevices); uDevFn++)
591 {
592 PPDMPCIDEV pChildPciDev = pChildBus->apDevices[uDevFn];
593 if (pChildPciDev)
594 pci_bios_init_device(pDevIns, pGlobals, pChildBus, pChildPciDev, cBridgeDepth + 1, paBridgePositions);
595 }
596
597 /* The number of bridges behind the this one is now available. */
598 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_SUBORDINATE_BUS, pGlobals->uPciBiosBus);
599
600 /*
601 * Set I/O limit register. If there is no device with I/O space behind the bridge
602 * we set a lower value than in the base register.
603 * The result with a real bridge is that no I/O transactions are passed to the secondary
604 * interface. Again this doesn't really matter here but we want to be compliant to the spec.
605 */
606 if ((u32IoAddressBase != pGlobals->uPciBiosIo) && ((pGlobals->uPciBiosIo % _4K) != 0))
607 {
608 /* The upper boundary must be one byte less than a 4KB boundary. */
609 pGlobals->uPciBiosIo = RT_ALIGN_32(pGlobals->uPciBiosIo, _4K);
610 }
611 devpciR3SetByte(pDevIns, pPciDev, VBOX_PCI_IO_LIMIT, ((pGlobals->uPciBiosIo >> 8) & 0xf0) - 1);
612
613 /* Same with the MMIO limit register but with 1MB boundary here. */
614 if ((u32MMIOAddressBase != pGlobals->uPciBiosMmio) && ((pGlobals->uPciBiosMmio % _1M) != 0))
615 {
616 /* The upper boundary must be one byte less than a 1MB boundary. */
617 pGlobals->uPciBiosMmio = RT_ALIGN_32(pGlobals->uPciBiosMmio, _1M);
618 }
619 devpciR3SetWord(pDevIns, pPciDev, VBOX_PCI_MEMORY_LIMIT, ((pGlobals->uPciBiosMmio >> 16) & UINT32_C(0xfff0)) - 1);
620
621 /*
622 * Set the prefetch base and limit registers. We currently have no device with a prefetchable region
623 * which may be behind a bridge. That's why it is unconditionally disabled here atm by writing a higher value into
624 * the base register than in the limit register.
625 */
626 devpciR3SetWord(pDevIns, pPciDev, VBOX_PCI_PREF_MEMORY_BASE, 0xfff0);
627 devpciR3SetWord(pDevIns, pPciDev, VBOX_PCI_PREF_MEMORY_LIMIT, 0x0);
628 devpciR3SetDWord(pDevIns, pPciDev, VBOX_PCI_PREF_BASE_UPPER32, 0x00);
629 devpciR3SetDWord(pDevIns, pPciDev, VBOX_PCI_PREF_LIMIT_UPPER32, 0x00);
630 break;
631 }
632 default:
633 default_map:
634 {
635 /* default memory mappings */
636 bool fActiveMemRegion = false;
637 bool fActiveIORegion = false;
638 /*
639 * PCI_NUM_REGIONS is 7 because of the rom region but there are only 6 base address register defined by the PCI spec.
640 * Leaving only PCI_NUM_REGIONS would cause reading another and enabling a memory region which does not exist.
641 */
642 for (unsigned i = 0; i < (PCI_NUM_REGIONS-1); i++)
643 {
644 uint32_t u32Size;
645 uint8_t u8RessourceType;
646 uint32_t u32Address = 0x10 + i * 4;
647
648 /* Calculate size. */
649 u8RessourceType = devpciR3GetByte(pPciDev, u32Address);
650 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0xffffffff));
651 u32Size = devpciR3GetDWord(pPciDev, u32Address);
652 bool fIsPio = ((u8RessourceType & PCI_COMMAND_IOACCESS) == PCI_COMMAND_IOACCESS);
653 /* Clear resource information depending on resource type. */
654 if (fIsPio) /* I/O */
655 u32Size &= ~(0x01);
656 else /* MMIO */
657 u32Size &= ~(0x0f);
658
659 /*
660 * Invert all bits and add 1 to get size of the region.
661 * (From PCI implementation note)
662 */
663 if (fIsPio && (u32Size & UINT32_C(0xffff0000)) == 0)
664 u32Size = (~(u32Size | UINT32_C(0xffff0000))) + 1;
665 else
666 u32Size = (~u32Size) + 1;
667
668 Log2Func(("Size of region %u for device %d on bus %d is %u\n", i, pPciDev->uDevFn, pBus->iBus, u32Size));
669
670 if (u32Size)
671 {
672 if (fIsPio)
673 paddr = &pGlobals->uPciBiosIo;
674 else
675 paddr = &pGlobals->uPciBiosMmio;
676 uint32_t uNew = *paddr;
677 uNew = (uNew + u32Size - 1) & ~(u32Size - 1);
678 if (fIsPio)
679 uNew &= UINT32_C(0xffff);
680 /* Unconditionally exclude I/O-APIC/HPET/ROM. Pessimistic, but better than causing a mess. */
681 if (!uNew || (uNew <= UINT32_C(0xffffffff) && uNew + u32Size - 1 >= UINT32_C(0xfec00000)))
682 {
683 LogRel(("PCI: no space left for BAR%u of device %u/%u/%u (vendor=%#06x device=%#06x)\n",
684 i, pBus->iBus, pPciDev->uDevFn >> 3, pPciDev->uDevFn & 7, vendor_id, device_id)); /** @todo make this a VM start failure later. */
685 /* Undo the mapping mess caused by the size probing. */
686 devpciR3SetDWord(pDevIns, pPciDev, u32Address, UINT32_C(0));
687 }
688 else
689 {
690 LogFunc(("Start address of %s region %u is %#x\n", (fIsPio ? "I/O" : "MMIO"), i, uNew));
691 devpciR3BiosInitSetRegionAddress(pDevIns, pBus, pPciDev, i, uNew);
692 if (fIsPio)
693 fActiveIORegion = true;
694 else
695 fActiveMemRegion = true;
696 *paddr = uNew + u32Size;
697 Log2Func(("New address is %#x\n", *paddr));
698 }
699 }
700 }
701
702 /* Update the command word appropriately. */
703 devpciR3SetWord(pDevIns, pPciDev, PCI_COMMAND,
704 devpciR3GetWord(pPciDev, PCI_COMMAND)
705 | (fActiveMemRegion ? PCI_COMMAND_MEMACCESS : 0)
706 | (fActiveIORegion ? PCI_COMMAND_IOACCESS : 0));
707
708 break;
709 }
710 }
711
712 /* map the interrupt */
713 pin = devpciR3GetByte(pPciDev, PCI_INTERRUPT_PIN);
714 if (pin != 0)
715 {
716 uint8_t uBridgeDevFn = pPciDev->uDevFn;
717 pin--;
718
719 /* We need to go up to the host bus to see which irq this device will assert there. */
720 while (cBridgeDepth != 0)
721 {
722 /* Get the pin the device would assert on the bridge. */
723 pin = ((uBridgeDevFn >> 3) + pin) & 3;
724 uBridgeDevFn = paBridgePositions[cBridgeDepth];
725 cBridgeDepth--;
726 }
727
728 pin = pci_slot_get_pirq(pPciDev->uDevFn, pin);
729 pic_irq = pci_irqs[pin];
730 devpciR3SetByte(pDevIns, pPciDev, PCI_INTERRUPT_LINE, pic_irq);
731 }
732 }
733}
734
735/**
736 * Worker for Fake PCI BIOS config, triggered by magic port access by BIOS.
737 *
738 * @returns VBox status code.
739 *
740 * @param pDevIns i440FX device instance.
741 */
742static int pciR3FakePCIBIOS(PPDMDEVINS pDevIns)
743{
744 uint8_t elcr[2] = {0, 0};
745 PDEVPCIROOT pGlobals = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
746 PVM pVM = PDMDevHlpGetVM(pDevIns); Assert(pVM);
747 PVMCPU pVCpu = PDMDevHlpGetVMCPU(pDevIns); Assert(pVM);
748 uint32_t const cbBelow4GB = MMR3PhysGetRamSizeBelow4GB(pVM);
749 uint64_t const cbAbove4GB = MMR3PhysGetRamSizeAbove4GB(pVM);
750 RT_NOREF(cbBelow4GB, cbAbove4GB);
751
752 LogRel(("PCI: Setting up resources and interrupts\n"));
753
754 /*
755 * Set the start addresses.
756 */
757 pGlobals->uPciBiosBus = 0;
758 pGlobals->uPciBiosIo = 0xd000;
759 pGlobals->uPciBiosMmio = UINT32_C(0xf0000000);
760
761 /*
762 * Activate IRQ mappings.
763 */
764 PPDMPCIDEV pPIIX3 = &pGlobals->Piix3.PIIX3State.dev;
765 for (unsigned i = 0; i < 4; i++)
766 {
767 uint8_t irq = pci_irqs[i];
768 /* Set to trigger level. */
769 elcr[irq >> 3] |= (1 << (irq & 7));
770 /* Activate irq remapping in PIIX3. */
771 devpciR3SetByte(pDevIns, pPIIX3, 0x60 + i, irq);
772 }
773
774 /* Tell to the PIC. */
775 VBOXSTRICTRC rcStrict = IOMIOPortWrite(pVM, pVCpu, 0x4d0, elcr[0], sizeof(uint8_t));
776 if (rcStrict == VINF_SUCCESS)
777 rcStrict = IOMIOPortWrite(pVM, pVCpu, 0x4d1, elcr[1], sizeof(uint8_t));
778 if (rcStrict != VINF_SUCCESS)
779 {
780 AssertMsgFailed(("Writing to PIC failed! rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
781 return RT_SUCCESS(rcStrict) ? VERR_INTERNAL_ERROR : VBOXSTRICTRC_VAL(rcStrict);
782 }
783
784 /*
785 * Init the devices.
786 */
787 PDEVPCIBUS pBus = &pGlobals->PciBus;
788 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
789 {
790 PPDMPCIDEV pPciDev = pBus->apDevices[uDevFn];
791 if (pPciDev)
792 {
793 Log2(("PCI: Initializing device %d (%#x)\n", uDevFn, 0x80000000 | (uDevFn << 8)));
794 uint8_t aBridgePositions[256];
795 RT_ZERO(aBridgePositions);
796 pci_bios_init_device(pDevIns, pGlobals, pBus, pPciDev, 0, aBridgePositions);
797 }
798 }
799
800 return VINF_SUCCESS;
801}
802
803#endif /* IN_RING3 */
804
805
806/* -=-=-=-=-=- I/O ports -=-=-=-=-=- */
807
808/**
809 * @callback_method_impl{FNIOMIOPORTOUT, PCI address}
810 */
811PDMBOTHCBDECL(int) pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
812{
813 LogFunc(("Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
814 RT_NOREF2(Port, pvUser);
815 if (cb == 4)
816 {
817 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
818 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
819 pThis->uConfigReg = u32 & ~3; /* Bits 0-1 are reserved and we silently clear them */
820 PCI_UNLOCK(pDevIns);
821 }
822 /* else: 440FX does "pass through to the bus" for other writes, what ever that means.
823 * Linux probes for cmd640 using byte writes/reads during ide init. We'll just ignore it. */
824 return VINF_SUCCESS;
825}
826
827
828/**
829 * @callback_method_impl{FNIOMIOPORTIN, PCI address}
830 */
831PDMBOTHCBDECL(int) pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
832{
833 RT_NOREF2(Port, pvUser);
834 if (cb == 4)
835 {
836 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
837 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_READ);
838 *pu32 = pThis->uConfigReg;
839 PCI_UNLOCK(pDevIns);
840 LogFunc(("Port=%#x cb=%d -> %#x\n", Port, cb, *pu32));
841 return VINF_SUCCESS;
842 }
843 /* else: 440FX does "pass through to the bus" for other writes, what ever that means.
844 * Linux probes for cmd640 using byte writes/reads during ide init. We'll just ignore it. */
845 LogFunc(("Port=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", Port, cb));
846 return VERR_IOM_IOPORT_UNUSED;
847}
848
849
850/**
851 * @callback_method_impl{FNIOMIOPORTOUT, PCI data}
852 */
853PDMBOTHCBDECL(int) pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
854{
855 LogFunc(("Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
856 NOREF(pvUser);
857 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
858 if (!(Port % cb))
859 {
860 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
861 rcStrict = pci_data_write(pDevIns, PDMINS_2_DATA(pDevIns, PDEVPCIROOT), Port, u32, cb);
862 PCI_UNLOCK(pDevIns);
863 }
864 else
865 AssertMsgFailed(("Write to port %#x u32=%#x cb=%d\n", Port, u32, cb));
866 return VBOXSTRICTRC_TODO(rcStrict);
867}
868
869
870/**
871 * @callback_method_impl{FNIOMIOPORTIN, PCI data}
872 */
873PDMBOTHCBDECL(int) pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
874{
875 NOREF(pvUser);
876 if (!(Port % cb))
877 {
878 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_READ);
879 VBOXSTRICTRC rcStrict = pci_data_read(PDMINS_2_DATA(pDevIns, PDEVPCIROOT), Port, cb, pu32);
880 PCI_UNLOCK(pDevIns);
881 LogFunc(("Port=%#x cb=%#x -> %#x (%Rrc)\n", Port, cb, *pu32, VBOXSTRICTRC_VAL(rcStrict)));
882 return VBOXSTRICTRC_TODO(rcStrict);
883 }
884 AssertMsgFailed(("Read from port %#x cb=%d\n", Port, cb));
885 return VERR_IOM_IOPORT_UNUSED;
886}
887
888#ifdef IN_RING3
889
890/**
891 * @callback_method_impl{FNIOMIOPORTOUT, PCI data}
892 */
893DECLCALLBACK(int) pciR3IOPortMagicPCIWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
894{
895 RT_NOREF2(pvUser, Port);
896 LogFunc(("Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
897 if (cb == 4)
898 {
899 if (u32 == UINT32_C(19200509)) // Richard Adams
900 {
901 int rc = pciR3FakePCIBIOS(pDevIns);
902 AssertRC(rc);
903 }
904 }
905
906 return VINF_SUCCESS;
907}
908
909/**
910 * @callback_method_impl{FNIOMIOPORTIN, PCI data}
911 */
912DECLCALLBACK(int) pciR3IOPortMagicPCIRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
913{
914 RT_NOREF5(pDevIns, pvUser, Port, pu32, cb);
915 LogFunc(("Port=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", Port, cb));
916 return VERR_IOM_IOPORT_UNUSED;
917}
918
919
920/*
921 * Include code we share with the other PCI bus implementation.
922 *
923 * Note! No #ifdefs, use instant data booleans/flags/whatever. Goal is to
924 * completely merge these files! File #1 contains code we write, where
925 * as a possible file #2 contains external code if there's any left.
926 */
927# include "DevPciMerge1.cpp.h"
928
929
930/* -=-=-=-=-=- Saved state -=-=-=-=-=- */
931
932/**
933 * Common worker for pciR3SaveExec and pcibridgeR3SaveExec.
934 *
935 * @returns VBox status code.
936 * @param pBus The bus to save.
937 * @param pSSM The saved state handle.
938 */
939static int pciR3CommonSaveExec(PDEVPCIBUS pBus, PSSMHANDLE pSSM)
940{
941 /*
942 * Iterate thru all the devices.
943 */
944 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
945 {
946 PPDMPCIDEV pDev = pBus->apDevices[uDevFn];
947 if (pDev)
948 {
949 SSMR3PutU32(pSSM, uDevFn);
950 SSMR3PutMem(pSSM, pDev->abConfig, sizeof(pDev->abConfig));
951
952 SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
953
954 /* Save the type an size of all the regions. */
955 for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
956 {
957 SSMR3PutU8(pSSM, pDev->Int.s.aIORegions[iRegion].type);
958 SSMR3PutU64(pSSM, pDev->Int.s.aIORegions[iRegion].size);
959 }
960 }
961 }
962 return SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
963}
964
965
966/**
967 * @callback_method_impl{FNSSMDEVSAVEEXEC}
968 */
969static DECLCALLBACK(int) pciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
970{
971 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
972
973 /*
974 * Bus state data.
975 */
976 SSMR3PutU32(pSSM, pThis->uConfigReg);
977 SSMR3PutBool(pSSM, pThis->fUseIoApic);
978
979 /*
980 * Save IRQ states.
981 */
982 for (unsigned i = 0; i < RT_ELEMENTS(pThis->Piix3.auPciLegacyIrqLevels); i++)
983 SSMR3PutU32(pSSM, pThis->Piix3.auPciLegacyIrqLevels[i]);
984 for (unsigned i = 0; i < RT_ELEMENTS(pThis->auPciApicIrqLevels); i++)
985 SSMR3PutU32(pSSM, pThis->auPciApicIrqLevels[i]);
986
987 SSMR3PutU32(pSSM, pThis->Piix3.iAcpiIrqLevel);
988 SSMR3PutS32(pSSM, pThis->Piix3.iAcpiIrq);
989
990 SSMR3PutU32(pSSM, UINT32_MAX); /* separator */
991
992 /*
993 * Join paths with pcibridgeR3SaveExec.
994 */
995 return pciR3CommonSaveExec(&pThis->PciBus, pSSM);
996}
997
998
999/**
1000 * Common worker for pciR3LoadExec and pcibridgeR3LoadExec.
1001 *
1002 * @returns VBox status code.
1003 * @param pDevIns The device instance.
1004 * @param pBus The bus which data is being loaded.
1005 * @param pSSM The saved state handle.
1006 * @param uVersion The data version.
1007 * @param uPass The pass.
1008 */
1009static int pciR3CommonLoadExec(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1010{
1011 uint32_t u32;
1012 int rc;
1013
1014 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1015
1016 /*
1017 * Iterate thru all the devices and write 0 to the COMMAND register so
1018 * that all the memory is unmapped before we start restoring the saved
1019 * mapping locations.
1020 *
1021 * The register value is restored afterwards so we can do proper
1022 * LogRels in devpciR3CommonRestoreConfig.
1023 */
1024 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
1025 {
1026 PPDMPCIDEV pDev = pBus->apDevices[uDevFn];
1027 if (pDev)
1028 {
1029 uint16_t u16 = PCIDevGetCommand(pDev);
1030 devpciR3SetCfg(pDevIns, pDev, VBOX_PCI_COMMAND, 0 /*u32Value*/, 2 /*cb*/);
1031 PCIDevSetCommand(pDev, u16);
1032 Assert(PCIDevGetCommand(pDev) == u16);
1033 }
1034 }
1035
1036 /*
1037 * Iterate all the devices.
1038 */
1039 for (uint32_t uDevFn = 0;; uDevFn++)
1040 {
1041 /* index / terminator */
1042 rc = SSMR3GetU32(pSSM, &u32);
1043 if (RT_FAILURE(rc))
1044 return rc;
1045 if (u32 == UINT32_MAX)
1046 break;
1047 if ( u32 >= RT_ELEMENTS(pBus->apDevices)
1048 || u32 < uDevFn)
1049 {
1050 AssertMsgFailed(("u32=%#x uDevFn=%#x\n", u32, uDevFn));
1051 return rc;
1052 }
1053
1054 /* skip forward to the device checking that no new devices are present. */
1055 for (; uDevFn < u32; uDevFn++)
1056 {
1057 if (pBus->apDevices[uDevFn])
1058 {
1059 LogRel(("PCI: New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", uDevFn, pBus->apDevices[uDevFn]->pszNameR3,
1060 PCIDevGetVendorId(pBus->apDevices[uDevFn]), PCIDevGetDeviceId(pBus->apDevices[uDevFn])));
1061 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1062 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("New device in slot %#x, %s (vendor=%#06x device=%#06x)"),
1063 uDevFn, pBus->apDevices[uDevFn]->pszNameR3, PCIDevGetVendorId(pBus->apDevices[uDevFn]), PCIDevGetDeviceId(pBus->apDevices[uDevFn]));
1064 }
1065 }
1066
1067 /* get the data */
1068 PDMPCIDEV DevTmp;
1069 RT_ZERO(DevTmp);
1070 DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
1071 SSMR3GetMem(pSSM, DevTmp.abConfig, sizeof(DevTmp.abConfig));
1072 if (uVersion < VBOX_PCI_SAVED_STATE_VERSION_IRQ_STATES)
1073 {
1074 int32_t i32Temp;
1075 /* Irq value not needed anymore. */
1076 rc = SSMR3GetS32(pSSM, &i32Temp);
1077 if (RT_FAILURE(rc))
1078 return rc;
1079 }
1080 else
1081 {
1082 rc = SSMR3GetS32(pSSM, &DevTmp.Int.s.uIrqPinState);
1083 if (RT_FAILURE(rc))
1084 return rc;
1085 }
1086
1087 /* Load the region types and sizes. */
1088 if (uVersion >= VBOX_PCI_SAVED_STATE_VERSION_REGION_SIZES)
1089 {
1090 for (uint32_t iRegion = 0; iRegion < VBOX_PCI_NUM_REGIONS; iRegion++)
1091 {
1092 SSMR3GetU8(pSSM, &DevTmp.Int.s.aIORegions[iRegion].type);
1093 rc = SSMR3GetU64(pSSM, &DevTmp.Int.s.aIORegions[iRegion].size);
1094 AssertLogRelRCReturn(rc, rc);
1095 }
1096 }
1097
1098 /* check that it's still around. */
1099 PPDMPCIDEV pDev = pBus->apDevices[uDevFn];
1100 if (!pDev)
1101 {
1102 LogRel(("PCI: Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", uDevFn,
1103 PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp)));
1104 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1105 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x has been removed! vendor=%#06x device=%#06x"),
1106 uDevFn, PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp));
1107 continue;
1108 }
1109
1110 /* match the vendor id assuming that this will never be changed. */
1111 if ( DevTmp.abConfig[0] != pDev->abConfig[0]
1112 || DevTmp.abConfig[1] != pDev->abConfig[1])
1113 return SSMR3SetCfgError(pSSM, RT_SRC_POS,
1114 N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
1115 uDevFn, pDev->pszNameR3, DevTmp.abConfig, pDev->abConfig);
1116
1117 /* commit the loaded device config. */
1118 rc = devpciR3CommonRestoreRegions(pSSM, pDev, DevTmp.Int.s.aIORegions,
1119 uVersion >= VBOX_PCI_SAVED_STATE_VERSION_REGION_SIZES);
1120 if (RT_FAILURE(rc))
1121 break;
1122 devpciR3CommonRestoreConfig(pDevIns, pDev, &DevTmp.abConfig[0]);
1123
1124 pDev->Int.s.uIrqPinState = DevTmp.Int.s.uIrqPinState;
1125 }
1126
1127 return VINF_SUCCESS;
1128}
1129
1130
1131/**
1132 * @callback_method_impl{FNSSMDEVLOADEXEC}
1133 */
1134static DECLCALLBACK(int) pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1135{
1136 PDEVPCIROOT pThis = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
1137 PDEVPCIBUS pBus = &pThis->PciBus;
1138 uint32_t u32;
1139 int rc;
1140
1141 /*
1142 * Check the version.
1143 */
1144 if (uVersion > VBOX_PCI_SAVED_STATE_VERSION)
1145 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1146 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1147
1148 /*
1149 * Bus state data.
1150 */
1151 SSMR3GetU32(pSSM, &pThis->uConfigReg);
1152 if (uVersion >= VBOX_PCI_SAVED_STATE_VERSION_USE_IO_APIC)
1153 SSMR3GetBool(pSSM, &pThis->fUseIoApic);
1154
1155 /* Load IRQ states. */
1156 if (uVersion >= VBOX_PCI_SAVED_STATE_VERSION_IRQ_STATES)
1157 {
1158 for (uint8_t i = 0; i < RT_ELEMENTS(pThis->Piix3.auPciLegacyIrqLevels); i++)
1159 SSMR3GetU32(pSSM, (uint32_t *)&pThis->Piix3.auPciLegacyIrqLevels[i]);
1160 for (uint8_t i = 0; i < RT_ELEMENTS(pThis->auPciApicIrqLevels); i++)
1161 SSMR3GetU32(pSSM, (uint32_t *)&pThis->auPciApicIrqLevels[i]);
1162
1163 SSMR3GetU32(pSSM, &pThis->Piix3.iAcpiIrqLevel);
1164 SSMR3GetS32(pSSM, &pThis->Piix3.iAcpiIrq);
1165 }
1166
1167 /* separator */
1168 rc = SSMR3GetU32(pSSM, &u32);
1169 if (RT_FAILURE(rc))
1170 return rc;
1171 if (u32 != UINT32_MAX)
1172 AssertMsgFailedReturn(("u32=%#x\n", u32), rc);
1173
1174 /*
1175 * The devices.
1176 */
1177 return pciR3CommonLoadExec(pDevIns, pBus, pSSM, uVersion, uPass);
1178}
1179
1180
1181/* -=-=-=-=-=- PCI Bus Interface Methods (PDMPCIBUSREG) -=-=-=-=-=- */
1182
1183
1184/* -=-=-=-=-=- Debug Info Handlers -=-=-=-=-=- */
1185
1186/**
1187 * @callback_method_impl{FNDBGFHANDLERDEV}
1188 */
1189static DECLCALLBACK(void) pciR3IrqRouteInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
1190{
1191 PDEVPCIROOT pGlobals = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
1192 PPDMPCIDEV pPIIX3 = &pGlobals->Piix3.PIIX3State.dev;
1193 NOREF(pszArgs);
1194
1195 uint16_t router = pPIIX3->uDevFn;
1196 pHlp->pfnPrintf(pHlp, "PCI interrupt router at: %02X:%02X:%X\n",
1197 router >> 8, (router >> 3) & 0x1f, router & 0x7);
1198
1199 for (int i = 0; i < 4; ++i)
1200 {
1201 uint8_t irq_map = devpciR3GetByte(pPIIX3, 0x60 + i);
1202 if (irq_map & 0x80)
1203 pHlp->pfnPrintf(pHlp, "PIRQ%c disabled\n", 'A' + i);
1204 else
1205 pHlp->pfnPrintf(pHlp, "PIRQ%c -> IRQ%d\n", 'A' + i, irq_map & 0xf);
1206 }
1207}
1208
1209/**
1210 * @callback_method_impl{FNDBGFHANDLERDEV, 'pirq'}
1211 */
1212DECLCALLBACK(void) devpciR3InfoPIRQ(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
1213{
1214 PDEVPCIROOT pGlobals = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
1215 NOREF(pszArgs);
1216
1217 pHlp->pfnPrintf(pHlp, "PCI IRQ levels:\n");
1218 for (int i = 0; i < DEVPCI_LEGACY_IRQ_PINS; ++i)
1219 pHlp->pfnPrintf(pHlp, " IRQ%c: %u\n", 'A' + i, pGlobals->Piix3.auPciLegacyIrqLevels[i]);
1220}
1221
1222
1223/* -=-=-=-=-=- PDMDEVREG -=-=-=-=-=- */
1224
1225/**
1226 * @interface_method_impl{PDMDEVREG,pfnReset}
1227 */
1228static DECLCALLBACK(void) pciR3Reset(PPDMDEVINS pDevIns)
1229{
1230 PDEVPCIROOT pGlobals = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
1231 PDEVPCIBUS pBus = &pGlobals->PciBus;
1232
1233 /* PCI-specific reset for each device. */
1234 for (uint32_t uDevFn = 0; uDevFn < RT_ELEMENTS(pBus->apDevices); uDevFn++)
1235 {
1236 if (pBus->apDevices[uDevFn])
1237 devpciR3ResetDevice(pDevIns, pBus->apDevices[uDevFn]);
1238 }
1239
1240 pciR3Piix3Reset(&pGlobals->Piix3.PIIX3State);
1241}
1242
1243
1244/**
1245 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1246 */
1247static DECLCALLBACK(int) pciR3Destruct(PPDMDEVINS pDevIns)
1248{
1249 PDEVPCIROOT pGlobals = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
1250 if (pGlobals->PciBus.papBridgesR3)
1251 {
1252 PDMDevHlpMMHeapFree(pDevIns, pGlobals->PciBus.papBridgesR3);
1253 pGlobals->PciBus.papBridgesR3 = NULL;
1254 }
1255 return VINF_SUCCESS;
1256}
1257
1258
1259/**
1260 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1261 */
1262static DECLCALLBACK(int) pciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1263{
1264 RT_NOREF1(iInstance);
1265 Assert(iInstance == 0);
1266 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1267
1268 /*
1269 * Validate and read configuration.
1270 */
1271 if (!CFGMR3AreValuesValid(pCfg, "IOAPIC\0" "GCEnabled\0" "R0Enabled\0"))
1272 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1273
1274 /* query whether we got an IOAPIC */
1275 bool fUseIoApic;
1276 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fUseIoApic, false);
1277 if (RT_FAILURE(rc))
1278 return PDMDEV_SET_ERROR(pDevIns, rc,
1279 N_("Configuration error: Failed to query boolean value \"IOAPIC\""));
1280
1281 /* check if RC code is enabled. */
1282 bool fGCEnabled;
1283 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
1284 if (RT_FAILURE(rc))
1285 return PDMDEV_SET_ERROR(pDevIns, rc,
1286 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
1287
1288 /* check if R0 code is enabled. */
1289 bool fR0Enabled;
1290 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
1291 if (RT_FAILURE(rc))
1292 return PDMDEV_SET_ERROR(pDevIns, rc,
1293 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
1294 Log(("PCI: fUseIoApic=%RTbool fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fUseIoApic, fGCEnabled, fR0Enabled));
1295
1296 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
1297 PDEVPCIROOT pGlobals = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
1298
1299 /*
1300 * Init data and register the PCI bus.
1301 */
1302 pGlobals->uPciBiosIo = 0xc000;
1303 pGlobals->uPciBiosMmio = 0xf0000000;
1304 memset((void *)&pGlobals->Piix3.auPciLegacyIrqLevels, 0, sizeof(pGlobals->Piix3.auPciLegacyIrqLevels));
1305 pGlobals->fUseIoApic = fUseIoApic;
1306 memset((void *)&pGlobals->auPciApicIrqLevels, 0, sizeof(pGlobals->auPciApicIrqLevels));
1307
1308 pGlobals->PciBus.fTypePiix3 = true;
1309 pGlobals->PciBus.fTypeIch9 = false;
1310 pGlobals->PciBus.fPureBridge = false;
1311 pGlobals->PciBus.papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns,
1312 sizeof(PPDMPCIDEV)
1313 * RT_ELEMENTS(pGlobals->PciBus.apDevices));
1314 AssertLogRelReturn(pGlobals->PciBus.papBridgesR3, VERR_NO_MEMORY);
1315
1316 PDEVPCIBUS pBus = &pGlobals->PciBus;
1317 PDMPCIBUSREGCC PciBusReg;
1318 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
1319 PciBusReg.pfnRegisterR3 = pciR3MergedRegister;
1320 PciBusReg.pfnRegisterMsiR3 = NULL;
1321 PciBusReg.pfnIORegionRegisterR3 = devpciR3CommonIORegionRegister;
1322 PciBusReg.pfnInterceptConfigAccesses = devpciR3CommonInterceptConfigAccesses;
1323 PciBusReg.pfnConfigRead = devpciR3CommonConfigRead;
1324 PciBusReg.pfnConfigWrite = devpciR3CommonConfigWrite;
1325 PciBusReg.pfnSetIrqR3 = pciSetIrq;
1326 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
1327 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBusCC->pPciHlpR3, &pBus->iBus);
1328 if (RT_FAILURE(rc))
1329 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as a PCI Bus"));
1330 Assert(pBus->iBus == 0);
1331 if (pBusCC->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
1332 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
1333 N_("PCI helper version mismatch; got %#x expected %#x"),
1334 pBusCC->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
1335
1336 /* Disable default device locking. */
1337 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
1338 AssertRCReturn(rc, rc);
1339
1340 /*
1341 * Fill in PCI configs and add them to the bus.
1342 */
1343 /* i440FX */
1344 PCIDevSetVendorId( &pBus->PciDev, 0x8086); /* Intel */
1345 PCIDevSetDeviceId( &pBus->PciDev, 0x1237);
1346 PCIDevSetRevisionId(&pBus->PciDev, 0x02);
1347 PCIDevSetClassSub( &pBus->PciDev, 0x00); /* host2pci */
1348 PCIDevSetClassBase( &pBus->PciDev, 0x06); /* PCI_bridge */
1349 PCIDevSetHeaderType(&pBus->PciDev, 0x00);
1350 rc = PDMDevHlpPCIRegisterEx(pDevIns, &pBus->PciDev, PDMPCIDEVREG_CFG_PRIMARY, 0 /*fFlags*/,
1351 0 /*uPciDevNo*/, 0 /*uPciFunNo*/, "i440FX");
1352 AssertLogRelRCReturn(rc, rc);
1353
1354 /* PIIX3 */
1355 PCIDevSetVendorId( &pGlobals->Piix3.PIIX3State.dev, 0x8086); /* Intel */
1356 PCIDevSetDeviceId( &pGlobals->Piix3.PIIX3State.dev, 0x7000); /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
1357 PCIDevSetClassSub( &pGlobals->Piix3.PIIX3State.dev, 0x01); /* PCI_ISA */
1358 PCIDevSetClassBase( &pGlobals->Piix3.PIIX3State.dev, 0x06); /* PCI_bridge */
1359 PCIDevSetHeaderType(&pGlobals->Piix3.PIIX3State.dev, 0x80); /* PCI_multifunction, generic */
1360 rc = PDMDevHlpPCIRegisterEx(pDevIns, &pGlobals->Piix3.PIIX3State.dev, PDMPCIDEVREG_CFG_NEXT, 0 /*fFlags*/,
1361 1 /*uPciDevNo*/, 0 /*uPciFunNo*/, "PIIX3");
1362 AssertLogRelRCReturn(rc, rc);
1363 pciR3Piix3Reset(&pGlobals->Piix3.PIIX3State);
1364
1365 pBus->iDevSearch = 16;
1366
1367 /*
1368 * Register I/O ports and save state.
1369 */
1370 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cf8, 1, NULL, pciIOPortAddressWrite, pciIOPortAddressRead, NULL, NULL, "i440FX (PCI)");
1371 if (RT_FAILURE(rc))
1372 return rc;
1373 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cfc, 4, NULL, pciIOPortDataWrite, pciIOPortDataRead, NULL, NULL, "i440FX (PCI)");
1374 if (RT_FAILURE(rc))
1375 return rc;
1376 if (fGCEnabled)
1377 {
1378 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cf8, 1, NIL_RTGCPTR, "pciIOPortAddressWrite", "pciIOPortAddressRead", NULL, NULL, "i440FX (PCI)");
1379 if (RT_FAILURE(rc))
1380 return rc;
1381 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cfc, 4, NIL_RTGCPTR, "pciIOPortDataWrite", "pciIOPortDataRead", NULL, NULL, "i440FX (PCI)");
1382 if (RT_FAILURE(rc))
1383 return rc;
1384 }
1385 if (fR0Enabled)
1386 {
1387 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cf8, 1, NIL_RTR0PTR, "pciIOPortAddressWrite", "pciIOPortAddressRead", NULL, NULL, "i440FX (PCI)");
1388 if (RT_FAILURE(rc))
1389 return rc;
1390 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cfc, 4, NIL_RTR0PTR, "pciIOPortDataWrite", "pciIOPortDataRead", NULL, NULL, "i440FX (PCI)");
1391 if (RT_FAILURE(rc))
1392 return rc;
1393 }
1394
1395 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0410, 1, NULL, pciR3IOPortMagicPCIWrite, pciR3IOPortMagicPCIRead, NULL, NULL, "i440FX (Fake PCI BIOS trigger)");
1396 if (RT_FAILURE(rc))
1397 return rc;
1398
1399
1400 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_PCI_SAVED_STATE_VERSION, sizeof(*pBus) + 16*128, "pgm",
1401 NULL, NULL, NULL,
1402 NULL, pciR3SaveExec, NULL,
1403 NULL, pciR3LoadExec, NULL);
1404 if (RT_FAILURE(rc))
1405 return rc;
1406
1407 PDMDevHlpDBGFInfoRegister(pDevIns, "pci",
1408 "Display PCI bus status. Recognizes 'basic' or 'verbose' as arguments, defaults to 'basic'.",
1409 devpciR3InfoPci);
1410 PDMDevHlpDBGFInfoRegister(pDevIns, "pciirq", "Display PCI IRQ state. (no arguments)", devpciR3InfoPciIrq);
1411 PDMDevHlpDBGFInfoRegister(pDevIns, "pirq", "Display PIRQ state. (no arguments)", devpciR3InfoPIRQ);
1412 PDMDevHlpDBGFInfoRegister(pDevIns, "irqroute", "Display PCI IRQ routing. (no arguments)", pciR3IrqRouteInfo);
1413
1414 return VINF_SUCCESS;
1415}
1416
1417#else /* !IN_RING3 */
1418
1419/**
1420 * @interface_method_impl{PDMDEVREGR0,pfnConstruct}
1421 */
1422static DECLCALLBACK(int) pciRZRootConstruct(PPDMDEVINS pDevIns)
1423{
1424 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1425 PDEVPCIROOT pGlobals = PDMINS_2_DATA(pDevIns, PDEVPCIROOT);
1426 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
1427
1428 PDMPCIBUSREGCC PciBusReg;
1429 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
1430 PciBusReg.iBus = pGlobals->PciBus.iBus;
1431 PciBusReg.pfnSetIrq = pciSetIrq;
1432 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
1433 int rc = PDMDevHlpPCIBusSetUpContext(pDevIns, &PciBusReg, &pBusCC->CTX_SUFF(pPciHlp));
1434 AssertRC(rc);
1435
1436 return rc;
1437}
1438
1439#endif /* !IN_RING3 */
1440
1441/**
1442 * The device registration structure.
1443 */
1444const PDMDEVREG g_DevicePCI =
1445{
1446 /* .u32Version = */ PDM_DEVREG_VERSION,
1447 /* .uReserved0 = */ 0,
1448 /* .szName = */ "pci",
1449 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1450 /* .fClass = */ PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
1451 /* .cMaxInstances = */ 1,
1452 /* .uSharedVersion = */ 42,
1453 /* .cbInstanceShared = */ sizeof(DEVPCIROOT),
1454 /* .cbInstanceCC = */ sizeof(CTX_SUFF(DEVPCIBUS)),
1455 /* .cbInstanceRC = */ sizeof(DEVPCIBUSRC),
1456 /* .cMaxPciDevices = */ 2,
1457 /* .cMaxMsixVectors = */ 0,
1458 /* .pszDescription = */ "i440FX PCI bridge and PIIX3 ISA bridge.",
1459#if defined(IN_RING3)
1460 /* .pszRCMod = */ "VBoxDDRC.rc",
1461 /* .pszR0Mod = */ "VBoxDDR0.r0",
1462 /* .pfnConstruct = */ pciR3Construct,
1463 /* .pfnDestruct = */ pciR3Destruct,
1464 /* .pfnRelocate = */ devpciR3RootRelocate,
1465 /* .pfnMemSetup = */ NULL,
1466 /* .pfnPowerOn = */ NULL,
1467 /* .pfnReset = */ pciR3Reset,
1468 /* .pfnSuspend = */ NULL,
1469 /* .pfnResume = */ NULL,
1470 /* .pfnAttach = */ NULL,
1471 /* .pfnDetach = */ NULL,
1472 /* .pfnQueryInterface = */ NULL,
1473 /* .pfnInitComplete = */ NULL,
1474 /* .pfnPowerOff = */ NULL,
1475 /* .pfnSoftReset = */ NULL,
1476 /* .pfnReserved0 = */ NULL,
1477 /* .pfnReserved1 = */ NULL,
1478 /* .pfnReserved2 = */ NULL,
1479 /* .pfnReserved3 = */ NULL,
1480 /* .pfnReserved4 = */ NULL,
1481 /* .pfnReserved5 = */ NULL,
1482 /* .pfnReserved6 = */ NULL,
1483 /* .pfnReserved7 = */ NULL,
1484#elif defined(IN_RING0)
1485 /* .pfnEarlyConstruct = */ NULL,
1486 /* .pfnConstruct = */ pciRZRootConstruct,
1487 /* .pfnDestruct = */ NULL,
1488 /* .pfnFinalDestruct = */ NULL,
1489 /* .pfnRequest = */ NULL,
1490 /* .pfnReserved0 = */ NULL,
1491 /* .pfnReserved1 = */ NULL,
1492 /* .pfnReserved2 = */ NULL,
1493 /* .pfnReserved3 = */ NULL,
1494 /* .pfnReserved4 = */ NULL,
1495 /* .pfnReserved5 = */ NULL,
1496 /* .pfnReserved6 = */ NULL,
1497 /* .pfnReserved7 = */ NULL,
1498#elif defined(IN_RC)
1499 /* .pfnConstruct = */ pciRZRootConstruct,
1500 /* .pfnReserved0 = */ NULL,
1501 /* .pfnReserved1 = */ NULL,
1502 /* .pfnReserved2 = */ NULL,
1503 /* .pfnReserved3 = */ NULL,
1504 /* .pfnReserved4 = */ NULL,
1505 /* .pfnReserved5 = */ NULL,
1506 /* .pfnReserved6 = */ NULL,
1507 /* .pfnReserved7 = */ NULL,
1508#else
1509# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1510#endif
1511 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1512
1513};
1514
1515
1516
1517/* -=-=-=-=-=- The PCI bridge specific bits -=-=-=-=-=- */
1518
1519/**
1520 * @interface_method_impl{PDMPCIBUSREG,pfnSetIrqR3}
1521 */
1522static DECLCALLBACK(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
1523{
1524 LogFlow(("pcibridgeSetIrq: %p %u %u %#x\n", pPciDev, iIrq, iLevel, uTagSrc));
1525
1526 /*
1527 * The PCI-to-PCI bridge specification defines how the interrupt pins
1528 * are routed from the secondary to the primary bus (see chapter 9).
1529 * iIrq gives the interrupt pin the pci device asserted.
1530 * We change iIrq here according to the spec and call the SetIrq function
1531 * of our parent passing the device which asserted the interrupt instead of the device of the bridge.
1532 */
1533 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1534 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
1535 PPDMPCIDEV pPciDevBus = pPciDev;
1536 int iIrqPinBridge = iIrq;
1537 uint8_t uDevFnBridge = 0;
1538
1539 /* Walk the chain until we reach the host bus. */
1540 do
1541 {
1542 uDevFnBridge = pBus->PciDev.uDevFn;
1543 iIrqPinBridge = ((pPciDevBus->uDevFn >> 3) + iIrqPinBridge) & 3;
1544
1545 /* Get the parent. */
1546 pBus = pBus->PciDev.Int.s.CTX_SUFF(pBus);
1547 pPciDevBus = &pBus->PciDev;
1548 } while (pBus->iBus != 0);
1549
1550 AssertMsg(pBus->iBus == 0, ("This is not the host pci bus iBus=%d\n", pBus->iBus));
1551 pciSetIrqInternal(pDevIns, DEVPCIBUS_2_DEVPCIROOT(pBus), pBusCC, uDevFnBridge, pPciDev, iIrqPinBridge, iLevel, uTagSrc);
1552}
1553
1554#ifdef IN_RING3
1555
1556/**
1557 * @callback_method_impl{FNPCIBRIDGECONFIGWRITE}
1558 */
1559static DECLCALLBACK(VBOXSTRICTRC) pcibridgeR3ConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice,
1560 uint32_t u32Address, unsigned cb, uint32_t u32Value)
1561{
1562 LogFlowFunc(("pDevIns=%p iBus=%d iDevice=%d u32Address=%u cb=%d u32Value=%u\n", pDevIns, iBus, iDevice, u32Address, cb, u32Value));
1563 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1564 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1565
1566 /* If the current bus is not the target bus search for the bus which contains the device. */
1567 if (iBus != pBus->PciDev.abConfig[VBOX_PCI_SECONDARY_BUS])
1568 {
1569 PPDMPCIDEV pBridgeDevice = pciR3FindBridge(pBus, iBus);
1570 if (pBridgeDevice)
1571 {
1572 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
1573 rcStrict = pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->Int.s.CTX_SUFF(pDevIns), iBus, iDevice,
1574 u32Address, cb, u32Value);
1575 }
1576 }
1577 else
1578 {
1579 /* This is the target bus, pass the write to the device. */
1580 PPDMPCIDEV pPciDev = pBus->apDevices[iDevice];
1581 if (pPciDev)
1582 {
1583 LogFunc(("%s: addr=%02x val=%08x len=%d\n", pPciDev->pszNameR3, u32Address, u32Value, cb));
1584 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
1585 if (pPciDev->Int.s.pfnConfigWrite)
1586 rcStrict = pPciDev->Int.s.pfnConfigWrite(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, u32Address, cb, u32Value);
1587 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
1588 rcStrict = devpciR3CommonConfigWriteWorker(pDevIns, PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC),
1589 pPciDev, u32Address, cb, u32Value);
1590 }
1591 }
1592 return rcStrict;
1593}
1594
1595
1596/**
1597 * @callback_method_impl{FNPCIBRIDGECONFIGREAD}
1598 */
1599static DECLCALLBACK(VBOXSTRICTRC) pcibridgeR3ConfigRead(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice,
1600 uint32_t u32Address, unsigned cb, uint32_t *pu32Value)
1601{
1602 LogFlowFunc(("pDevIns=%p iBus=%d iDevice=%d u32Address=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, cb));
1603 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1604 VBOXSTRICTRC rcStrict = VINF_SUCCESS;
1605
1606 /* If the current bus is not the target bus search for the bus which contains the device. */
1607 if (iBus != pBus->PciDev.abConfig[VBOX_PCI_SECONDARY_BUS])
1608 {
1609 PPDMPCIDEV pBridgeDevice = pciR3FindBridge(pBus, iBus);
1610 if (pBridgeDevice)
1611 {
1612 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
1613 rcStrict = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->Int.s.CTX_SUFF(pDevIns),
1614 iBus, iDevice, u32Address, cb, pu32Value);
1615 }
1616 else
1617 *pu32Value = UINT32_MAX;
1618 }
1619 else
1620 {
1621 /* This is the target bus, pass the read to the device. */
1622 PPDMPCIDEV pPciDev = pBus->apDevices[iDevice];
1623 if (pPciDev)
1624 {
1625 rcStrict = VINF_PDM_PCI_DO_DEFAULT;
1626 if (pPciDev->Int.s.pfnConfigRead)
1627 rcStrict = pPciDev->Int.s.pfnConfigRead(pPciDev->Int.s.CTX_SUFF(pDevIns), pPciDev, u32Address, cb, pu32Value);
1628 if (rcStrict == VINF_PDM_PCI_DO_DEFAULT)
1629 rcStrict = devpciR3CommonConfigReadWorker(pPciDev, u32Address, cb, pu32Value);
1630
1631 LogFunc(("%s: u32Address=%02x u32Value=%08x cb=%d\n", pPciDev->pszNameR3, u32Address, *pu32Value, cb));
1632 }
1633 else
1634 *pu32Value = UINT32_MAX;
1635 }
1636
1637 return rcStrict;
1638}
1639
1640
1641/**
1642 * @callback_method_impl{FNSSMDEVSAVEEXEC}
1643 */
1644static DECLCALLBACK(int) pcibridgeR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1645{
1646 PDEVPCIBUS pThis = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1647 return pciR3CommonSaveExec(pThis, pSSM);
1648}
1649
1650
1651/**
1652 * @callback_method_impl{FNSSMDEVLOADEXEC}
1653 */
1654static DECLCALLBACK(int) pcibridgeR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1655{
1656 PDEVPCIBUS pThis = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1657 if (uVersion > VBOX_PCI_SAVED_STATE_VERSION)
1658 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1659 return pciR3CommonLoadExec(pDevIns, pThis, pSSM, uVersion, uPass);
1660}
1661
1662
1663/**
1664 * @interface_method_impl{PDMDEVREG,pfnReset}
1665 */
1666static DECLCALLBACK(void) pcibridgeR3Reset(PPDMDEVINS pDevIns)
1667{
1668 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1669
1670 /* Reset config space to default values. */
1671 pBus->PciDev.abConfig[VBOX_PCI_PRIMARY_BUS] = 0;
1672 pBus->PciDev.abConfig[VBOX_PCI_SECONDARY_BUS] = 0;
1673 pBus->PciDev.abConfig[VBOX_PCI_SUBORDINATE_BUS] = 0;
1674}
1675
1676
1677/**
1678 * @interface_method_impl{PDMDEVREG,pfnDestruct}
1679 */
1680static DECLCALLBACK(int) pcibridgeR3Destruct(PPDMDEVINS pDevIns)
1681{
1682 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1683 if (pBus->papBridgesR3)
1684 {
1685 PDMDevHlpMMHeapFree(pDevIns, pBus->papBridgesR3);
1686 pBus->papBridgesR3 = NULL;
1687 }
1688 return VINF_SUCCESS;
1689}
1690
1691
1692/**
1693 * @interface_method_impl{PDMDEVREG,pfnConstruct}
1694 */
1695static DECLCALLBACK(int) pcibridgeR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
1696{
1697 RT_NOREF(iInstance);
1698 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1699
1700 /*
1701 * Validate and read configuration.
1702 */
1703 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
1704 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1705
1706 /* check if RC code is enabled. */
1707 bool fGCEnabled;
1708 int rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
1709 if (RT_FAILURE(rc))
1710 return PDMDEV_SET_ERROR(pDevIns, rc,
1711 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
1712
1713 /* check if R0 code is enabled. */
1714 bool fR0Enabled;
1715 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
1716 if (RT_FAILURE(rc))
1717 return PDMDEV_SET_ERROR(pDevIns, rc,
1718 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
1719 Log(("PCI: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
1720
1721 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1722 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
1723
1724 /*
1725 * Init data and register the PCI bus.
1726 */
1727 pBus->fTypePiix3 = true;
1728 pBus->fTypeIch9 = false;
1729 pBus->fPureBridge = true;
1730 pBus->papBridgesR3 = (PPDMPCIDEV *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPDMPCIDEV) * RT_ELEMENTS(pBus->apDevices));
1731 AssertLogRelReturn(pBus->papBridgesR3, VERR_NO_MEMORY);
1732
1733 PDMPCIBUSREGCC PciBusReg;
1734 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
1735 PciBusReg.pfnRegisterR3 = pcibridgeR3MergedRegisterDevice;
1736 PciBusReg.pfnRegisterMsiR3 = NULL;
1737 PciBusReg.pfnIORegionRegisterR3 = devpciR3CommonIORegionRegister;
1738 PciBusReg.pfnInterceptConfigAccesses = devpciR3CommonInterceptConfigAccesses;
1739 PciBusReg.pfnConfigWrite = devpciR3CommonConfigWrite;
1740 PciBusReg.pfnConfigRead = devpciR3CommonConfigRead;
1741 PciBusReg.pfnSetIrqR3 = pcibridgeSetIrq;
1742 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
1743 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBusCC->pPciHlpR3, &pBus->iBus);
1744 if (RT_FAILURE(rc))
1745 return PDMDEV_SET_ERROR(pDevIns, rc,
1746 N_("Failed to register ourselves as a PCI Bus"));
1747 Assert(pBus->iBus == (uint32_t)iInstance + 1); /* Can be removed when adding support for multiple bridge implementations. */
1748 if (pBusCC->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
1749 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
1750 N_("PCI helper version mismatch; got %#x expected %#x"),
1751 pBusCC->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
1752
1753 /*
1754 * Fill in PCI configs and add them to the bus.
1755 */
1756 PCIDevSetVendorId( &pBus->PciDev, 0x8086); /* Intel */
1757 PCIDevSetDeviceId( &pBus->PciDev, 0x2448); /* 82801 Mobile PCI bridge. */
1758 PCIDevSetRevisionId(&pBus->PciDev, 0xf2);
1759 PCIDevSetClassSub( &pBus->PciDev, 0x04); /* pci2pci */
1760 PCIDevSetClassBase( &pBus->PciDev, 0x06); /* PCI_bridge */
1761 PCIDevSetClassProg( &pBus->PciDev, 0x01); /* Supports subtractive decoding. */
1762 PCIDevSetHeaderType(&pBus->PciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
1763 PCIDevSetCommand( &pBus->PciDev, 0x0000);
1764 PCIDevSetStatus( &pBus->PciDev, 0x0020); /* 66MHz Capable. */
1765 PCIDevSetInterruptLine(&pBus->PciDev, 0x00); /* This device does not assert interrupts. */
1766
1767 /*
1768 * This device does not generate interrupts. Interrupt delivery from
1769 * devices attached to the bus is unaffected.
1770 */
1771 PCIDevSetInterruptPin(&pBus->PciDev, 0x00);
1772
1773 /*
1774 * Register this PCI bridge. The called function will take care on which bus we will get registered.
1775 */
1776 rc = PDMDevHlpPCIRegisterEx(pDevIns, &pBus->PciDev, PDMPCIDEVREG_CFG_PRIMARY, PDMPCIDEVREG_F_PCI_BRIDGE,
1777 PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, "pcibridge");
1778 if (RT_FAILURE(rc))
1779 return rc;
1780 pBus->PciDev.Int.s.pfnBridgeConfigRead = pcibridgeR3ConfigRead;
1781 pBus->PciDev.Int.s.pfnBridgeConfigWrite = pcibridgeR3ConfigWrite;
1782
1783 pBus->iDevSearch = 0;
1784
1785 /*
1786 * Register SSM handlers. We use the same saved state version as for the host bridge
1787 * to make changes easier.
1788 */
1789 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_PCI_SAVED_STATE_VERSION, sizeof(*pBus) + 16*128, "pgm",
1790 NULL, NULL, NULL,
1791 NULL, pcibridgeR3SaveExec, NULL,
1792 NULL, pcibridgeR3LoadExec, NULL);
1793 if (RT_FAILURE(rc))
1794 return rc;
1795
1796 return VINF_SUCCESS;
1797}
1798
1799#else /* !IN_RING3 */
1800
1801/**
1802 * @interface_method_impl{PDMDEVREGR0,pfnConstruct}
1803 */
1804static DECLCALLBACK(int) pcibridgeRZConstruct(PPDMDEVINS pDevIns)
1805{
1806 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
1807 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
1808 PDEVPCIBUSCC pBusCC = PDMINS_2_DATA_CC(pDevIns, PDEVPCIBUSCC);
1809
1810 PDMPCIBUSREGCC PciBusReg;
1811 PciBusReg.u32Version = PDM_PCIBUSREGCC_VERSION;
1812 PciBusReg.iBus = pBus->iBus;
1813 PciBusReg.pfnSetIrq = pcibridgeSetIrq;
1814 PciBusReg.u32EndVersion = PDM_PCIBUSREGCC_VERSION;
1815 int rc = PDMDevHlpPCIBusSetUpContext(pDevIns, &PciBusReg, &pBusCC->CTX_SUFF(pPciHlp));
1816 AssertRC(rc);
1817
1818 return rc;
1819}
1820
1821#endif /* !IN_RING3 */
1822
1823/**
1824 * The device registration structure
1825 * for the PCI-to-PCI bridge.
1826 */
1827const PDMDEVREG g_DevicePCIBridge =
1828{
1829 /* .u32Version = */ PDM_DEVREG_VERSION,
1830 /* .uReserved0 = */ 0,
1831 /* .szName = */ "pcibridge",
1832 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
1833 /* .fClass = */ PDM_DEVREG_CLASS_BUS_PCI,
1834 /* .cMaxInstances = */ ~0U,
1835 /* .uSharedVersion = */ 42,
1836 /* .cbInstanceShared = */ sizeof(DEVPCIBUS),
1837 /* .cbInstanceCC = */ sizeof(CTX_SUFF(DEVPCIBUS)),
1838 /* .cbInstanceRC = */ 0,
1839 /* .cMaxPciDevices = */ 1,
1840 /* .cMaxMsixVectors = */ 0,
1841 /* .pszDescription = */ "82801 Mobile PCI to PCI bridge",
1842#if defined(IN_RING3)
1843 /* .pszRCMod = */ "VBoxDDRC.rc",
1844 /* .pszR0Mod = */ "VBoxDDR0.r0",
1845 /* .pfnConstruct = */ pcibridgeR3Construct,
1846 /* .pfnDestruct = */ pcibridgeR3Destruct,
1847 /* .pfnRelocate = */ devpciR3BusRelocate,
1848 /* .pfnMemSetup = */ NULL,
1849 /* .pfnPowerOn = */ NULL,
1850 /* .pfnReset = */ pcibridgeR3Reset,
1851 /* .pfnSuspend = */ NULL,
1852 /* .pfnResume = */ NULL,
1853 /* .pfnAttach = */ NULL,
1854 /* .pfnDetach = */ NULL,
1855 /* .pfnQueryInterface = */ NULL,
1856 /* .pfnInitComplete = */ NULL,
1857 /* .pfnPowerOff = */ NULL,
1858 /* .pfnSoftReset = */ NULL,
1859 /* .pfnReserved0 = */ NULL,
1860 /* .pfnReserved1 = */ NULL,
1861 /* .pfnReserved2 = */ NULL,
1862 /* .pfnReserved3 = */ NULL,
1863 /* .pfnReserved4 = */ NULL,
1864 /* .pfnReserved5 = */ NULL,
1865 /* .pfnReserved6 = */ NULL,
1866 /* .pfnReserved7 = */ NULL,
1867#elif defined(IN_RING0)
1868 /* .pfnEarlyConstruct = */ NULL,
1869 /* .pfnConstruct = */ pcibridgeRZConstruct,
1870 /* .pfnDestruct = */ NULL,
1871 /* .pfnFinalDestruct = */ NULL,
1872 /* .pfnRequest = */ NULL,
1873 /* .pfnReserved0 = */ NULL,
1874 /* .pfnReserved1 = */ NULL,
1875 /* .pfnReserved2 = */ NULL,
1876 /* .pfnReserved3 = */ NULL,
1877 /* .pfnReserved4 = */ NULL,
1878 /* .pfnReserved5 = */ NULL,
1879 /* .pfnReserved6 = */ NULL,
1880 /* .pfnReserved7 = */ NULL,
1881#elif defined(IN_RC)
1882 /* .pfnConstruct = */ pcibridgeRZConstruct,
1883 /* .pfnReserved0 = */ NULL,
1884 /* .pfnReserved1 = */ NULL,
1885 /* .pfnReserved2 = */ NULL,
1886 /* .pfnReserved3 = */ NULL,
1887 /* .pfnReserved4 = */ NULL,
1888 /* .pfnReserved5 = */ NULL,
1889 /* .pfnReserved6 = */ NULL,
1890 /* .pfnReserved7 = */ NULL,
1891#else
1892# error "Not in IN_RING3, IN_RING0 or IN_RC!"
1893#endif
1894 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
1895};
1896
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