VirtualBox

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

Last change on this file since 68594 was 68594, checked in by vboxsync, 7 years ago

PDM: Address the todos for cleaning up the PDMDEVHLP structure, bring the reserved slots back to the nominal numver and bump the major version (20 ended up being used by 5.1). Eliminate redundant PDMDEVHLP version dependent conditional compilation

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