VirtualBox

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

Last change on this file since 44536 was 44508, checked in by vboxsync, 12 years ago

Drop the pfnSaveExecR3 and pfnLoadExecR3 interfaces of the PCI buses (never used). Synced pciR3CommonRestoreConfig between the two PCI buses, dropping the constants in the table as they make double checking sizes and offsets harder. Also removing the pfnIOCtl device registration structure member, putting a pfnReserved in it's place.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 100.7 KB
Line 
1/* $Id: DevPCI.cpp 44508 2013-02-01 12:46:33Z vboxsync $ */
2/** @file
3 * DevPCI - PCI BUS Device.
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 * --------------------------------------------------------------------
17 *
18 * This code is based on:
19 *
20 * QEMU PCI bus manager
21 *
22 * Copyright (c) 2004 Fabrice Bellard
23 *
24 * Permission is hereby granted, free of charge, to any person obtaining a copy
25 * of this software and associated documentation files (the "Software"), to deal
26 * in the Software without restriction, including without limitation the rights
27 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28 * copies of the Software, and to permit persons to whom the Software is
29 * furnished to do so, subject to the following conditions:
30 *
31 * The above copyright notice and this permission notice shall be included in
32 * all copies or substantial portions of the Software.
33 *
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
37 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
40 * THE SOFTWARE.
41 */
42
43/*******************************************************************************
44* Header Files *
45*******************************************************************************/
46#define LOG_GROUP LOG_GROUP_DEV_PCI
47/* Hack to get PCIDEVICEINT declared at the right point - include "PCIInternal.h". */
48#define PCI_INCLUDE_PRIVATE
49#include <VBox/pci.h>
50#include <VBox/vmm/pdmdev.h>
51#include <iprt/asm.h>
52#include <iprt/assert.h>
53#include <iprt/string.h>
54
55#include "VBoxDD.h"
56
57
58/*******************************************************************************
59* Structures and Typedefs *
60*******************************************************************************/
61/**
62 * PIIX3 ISA Bridge state.
63 */
64typedef struct PIIX3State
65{
66 /** The PCI device of the bridge. */
67 PCIDEVICE dev;
68} PIIX3State, PIIX3, *PPIIX3;
69
70/**
71 * PCI Bus instance.
72 */
73typedef struct PCIBus
74{
75 /** Bus number. */
76 int32_t iBus;
77 /** Start device number. */
78 int32_t iDevSearch;
79 /** Number of bridges attached to the bus. */
80 uint32_t cBridges;
81
82 uint32_t Alignment0;
83
84 /** Array of PCI devices. */
85 R3PTRTYPE(PPCIDEVICE) devices[256];
86 /** Array of bridges attached to the bus. */
87 R3PTRTYPE(PPCIDEVICE *) papBridgesR3;
88
89 /** R3 pointer to the device instance. */
90 PPDMDEVINSR3 pDevInsR3;
91 /** Pointer to the PCI R3 helpers. */
92 PCPDMPCIHLPR3 pPciHlpR3;
93
94 /** R0 pointer to the device instance. */
95 PPDMDEVINSR0 pDevInsR0;
96 /** Pointer to the PCI R0 helpers. */
97 PCPDMPCIHLPR0 pPciHlpR0;
98
99 /** RC pointer to the device instance. */
100 PPDMDEVINSRC pDevInsRC;
101 /** Pointer to the PCI RC helpers. */
102 PCPDMPCIHLPRC pPciHlpRC;
103
104 /** The PCI device for the PCI bridge. */
105 PCIDEVICE PciDev;
106
107} PCIBUS;
108/** Pointer to a PCIBUS instance. */
109typedef PCIBUS *PPCIBUS;
110typedef PCIBUS PCIBus;
111
112/** @def PCI_IRQ_PINS
113 * Number of pins for interrupts (PIRQ#0...PIRQ#3)
114 */
115#define PCI_IRQ_PINS 4
116
117/** @def PCI_APIC_IRQ_PINS
118 * Number of pins for interrupts if the APIC is used.
119 */
120#define PCI_APIC_IRQ_PINS 8
121
122/**
123 * PCI Globals - This is the host-to-pci bridge and the root bus.
124 */
125typedef struct PCIGLOBALS
126{
127 /** Irq levels for the four PCI Irqs.
128 * These count how many devices asserted
129 * the IRQ line. If greater 0 an IRQ is sent to the guest.
130 * If it drops to 0 the IRQ is deasserted.
131 */
132 volatile uint32_t pci_irq_levels[PCI_IRQ_PINS];
133
134#if 1 /* Will be moved into the BIOS soon. */
135 /** The next I/O port address which the PCI BIOS will use. */
136 uint32_t pci_bios_io_addr;
137 /** The next MMIO address which the PCI BIOS will use. */
138 uint32_t pci_bios_mem_addr;
139 /** Actual bus number. */
140 uint8_t uBus;
141#endif
142
143 /** I/O APIC usage flag */
144 bool fUseIoApic;
145 /** I/O APIC irq levels */
146 volatile uint32_t pci_apic_irq_levels[PCI_APIC_IRQ_PINS];
147 /** ACPI IRQ level */
148 uint32_t acpi_irq_level;
149 /** ACPI PIC IRQ */
150 int acpi_irq;
151 /** Config register. */
152 uint32_t uConfigReg;
153
154 /** R3 pointer to the device instance. */
155 PPDMDEVINSR3 pDevInsR3;
156 /** R0 pointer to the device instance. */
157 PPDMDEVINSR0 pDevInsR0;
158 /** RC pointer to the device instance. */
159 PPDMDEVINSRC pDevInsRC;
160
161#if HC_ARCH_BITS == 64
162 uint32_t Alignment0;
163#endif
164
165 /** ISA bridge state. */
166 PIIX3 PIIX3State;
167 /** PCI bus which is attached to the host-to-PCI bridge. */
168 PCIBUS PciBus;
169
170} PCIGLOBALS;
171/** Pointer to per VM data. */
172typedef PCIGLOBALS *PPCIGLOBALS;
173
174
175/*******************************************************************************
176* Defined Constants And Macros *
177*******************************************************************************/
178
179/** Converts a bus instance pointer to a device instance pointer. */
180#define PCIBUS_2_DEVINS(pPciBus) ((pPciBus)->CTX_SUFF(pDevIns))
181/** Converts a device instance pointer to a PCIGLOBALS pointer. */
182#define DEVINS_2_PCIGLOBALS(pDevIns) ((PPCIGLOBALS)(PDMINS_2_DATA(pDevIns, PPCIGLOBALS)))
183/** Converts a device instance pointer to a PCIBUS pointer. */
184#define DEVINS_2_PCIBUS(pDevIns) ((PPCIBUS)(&PDMINS_2_DATA(pDevIns, PPCIGLOBALS)->PciBus))
185
186/** Converts a pointer to a PCI bus instance to a PCIGLOBALS pointer.
187 * @note This works only if the bus number is 0!!!
188 */
189#define PCIBUS_2_PCIGLOBALS(pPciBus) ( (PPCIGLOBALS)((uintptr_t)(pPciBus) - RT_OFFSETOF(PCIGLOBALS, PciBus)) )
190
191/** @def PCI_LOCK
192 * Acquires the PDM lock. This is a NOP if locking is disabled. */
193/** @def PCI_UNLOCK
194 * Releases the PDM lock. This is a NOP if locking is disabled. */
195#define PCI_LOCK(pDevIns, rc) \
196 do { \
197 int rc2 = DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnLock((pDevIns), rc); \
198 if (rc2 != VINF_SUCCESS) \
199 return rc2; \
200 } while (0)
201#define PCI_UNLOCK(pDevIns) \
202 DEVINS_2_PCIBUS(pDevIns)->CTX_SUFF(pPciHlp)->pfnUnlock(pDevIns)
203
204/** @def VBOX_PCI_SAVED_STATE_VERSION
205 * Saved state version of the PCI bus device.
206 */
207#define VBOX_PCI_SAVED_STATE_VERSION 3
208
209
210#ifndef VBOX_DEVICE_STRUCT_TESTCASE
211/*******************************************************************************
212* Internal Functions *
213*******************************************************************************/
214RT_C_DECLS_BEGIN
215
216PDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTag);
217PDMBOTHCBDECL(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTag);
218PDMBOTHCBDECL(int) pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
219PDMBOTHCBDECL(int) pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
220PDMBOTHCBDECL(int) pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb);
221PDMBOTHCBDECL(int) pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb);
222
223#ifdef IN_RING3
224DECLINLINE(PPCIDEVICE) pciR3FindBridge(PPCIBUS pBus, uint8_t iBus);
225#endif
226
227RT_C_DECLS_END
228
229#define DEBUG_PCI
230
231#define PCI_VENDOR_ID 0x00 /* 16 bits */
232#define PCI_DEVICE_ID 0x02 /* 16 bits */
233#define PCI_COMMAND 0x04 /* 16 bits */
234#define PCI_COMMAND_IO 0x01 /* Enable response in I/O space */
235#define PCI_COMMAND_MEMORY 0x02 /* Enable response in Memory space */
236#define PCI_CLASS_DEVICE 0x0a /* Device class */
237#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
238#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
239#define PCI_MIN_GNT 0x3e /* 8 bits */
240#define PCI_MAX_LAT 0x3f /* 8 bits */
241
242
243#ifdef IN_RING3
244
245static void pci_update_mappings(PCIDevice *d)
246{
247 PPCIBUS pBus = d->Int.s.CTX_SUFF(pBus);
248 PCIIORegion *r;
249 int cmd, i;
250 uint32_t last_addr, new_addr, config_ofs;
251
252 cmd = RT_LE2H_U16(*(uint16_t *)(d->config + PCI_COMMAND));
253 for(i = 0; i < PCI_NUM_REGIONS; i++) {
254 r = &d->Int.s.aIORegions[i];
255 if (i == PCI_ROM_SLOT) {
256 config_ofs = 0x30;
257 } else {
258 config_ofs = 0x10 + i * 4;
259 }
260 if (r->size != 0) {
261 if (r->type & PCI_ADDRESS_SPACE_IO) {
262 if (cmd & PCI_COMMAND_IO) {
263 new_addr = RT_LE2H_U32(*(uint32_t *)(d->config +
264 config_ofs));
265 new_addr = new_addr & ~(r->size - 1);
266 last_addr = new_addr + r->size - 1;
267 /* NOTE: we have only 64K ioports on PC */
268 if (last_addr <= new_addr || new_addr == 0 ||
269 last_addr >= 0x10000) {
270 new_addr = ~0U;
271 }
272 } else {
273 new_addr = ~0U;
274 }
275 } else {
276 if (cmd & PCI_COMMAND_MEMORY) {
277 new_addr = RT_LE2H_U32(*(uint32_t *)(d->config +
278 config_ofs));
279 /* the ROM slot has a specific enable bit */
280 if (i == PCI_ROM_SLOT && !(new_addr & 1))
281 goto no_mem_map;
282 new_addr = new_addr & ~(r->size - 1);
283 last_addr = new_addr + r->size - 1;
284 /* NOTE: we do not support wrapping */
285 /* XXX: as we cannot support really dynamic
286 mappings, we handle specific values as invalid
287 mappings. */
288 if (last_addr <= new_addr || new_addr == 0 ||
289 last_addr == ~0U) {
290 new_addr = ~0U;
291 }
292 } else {
293 no_mem_map:
294 new_addr = ~0U;
295 }
296 }
297 /* now do the real mapping */
298 if (new_addr != r->addr) {
299 if (r->addr != ~0U) {
300 if (r->type & PCI_ADDRESS_SPACE_IO) {
301 int devclass;
302 /* NOTE: specific hack for IDE in PC case:
303 only one byte must be mapped. */
304 devclass = d->config[0x0a] | (d->config[0x0b] << 8);
305 if (devclass == 0x0101 && r->size == 4) {
306 int rc = PDMDevHlpIOPortDeregister(d->pDevIns, r->addr + 2, 1);
307 AssertRC(rc);
308 } else {
309 int rc = PDMDevHlpIOPortDeregister(d->pDevIns, r->addr, r->size);
310 AssertRC(rc);
311 }
312 } else {
313 RTGCPHYS GCPhysBase = r->addr;
314 int rc;
315 if (pBus->pPciHlpR3->pfnIsMMIO2Base(pBus->pDevInsR3, d->pDevIns, GCPhysBase))
316 {
317 /* unmap it. */
318 rc = r->map_func(d, i, NIL_RTGCPHYS, r->size, (PCIADDRESSSPACE)(r->type));
319 AssertRC(rc);
320 rc = PDMDevHlpMMIO2Unmap(d->pDevIns, i, GCPhysBase);
321 }
322 else
323 rc = PDMDevHlpMMIODeregister(d->pDevIns, GCPhysBase, r->size);
324 AssertMsgRC(rc, ("rc=%Rrc d=%s i=%d GCPhysBase=%RGp size=%#x\n", rc, d->name, i, GCPhysBase, r->size));
325 }
326 }
327 r->addr = new_addr;
328 if (r->addr != ~0U) {
329 int rc = r->map_func(d, i,
330 r->addr + (r->type & PCI_ADDRESS_SPACE_IO ? 0 : 0),
331 r->size, (PCIADDRESSSPACE)(r->type));
332 AssertRC(rc);
333 }
334 }
335 }
336 }
337}
338
339
340static DECLCALLBACK(uint32_t) pci_default_read_config(PCIDevice *d, uint32_t address, unsigned len)
341{
342 uint32_t val;
343 switch(len) {
344 case 1:
345 val = d->config[address];
346 break;
347 case 2:
348 val = RT_LE2H_U16(*(uint16_t *)(d->config + address));
349 break;
350 default:
351 case 4:
352 val = RT_LE2H_U32(*(uint32_t *)(d->config + address));
353 break;
354 }
355 return val;
356}
357
358static DECLCALLBACK(void) pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, unsigned len)
359{
360 int can_write;
361 unsigned i;
362 uint32_t end, addr;
363
364 if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
365 (address >= 0x30 && address < 0x34))) {
366 PCIIORegion *r;
367 int reg;
368
369 if ( address >= 0x30 ) {
370 reg = PCI_ROM_SLOT;
371 }else{
372 reg = (address - 0x10) >> 2;
373 }
374 r = &d->Int.s.aIORegions[reg];
375 if (r->size == 0)
376 goto default_config;
377 /* compute the stored value */
378 if (reg == PCI_ROM_SLOT) {
379 /* keep ROM enable bit */
380 val &= (~(r->size - 1)) | 1;
381 } else {
382 val &= ~(r->size - 1);
383 val |= r->type;
384 }
385 *(uint32_t *)(d->config + address) = RT_H2LE_U32(val);
386 pci_update_mappings(d);
387 return;
388 }
389 default_config:
390 /* not efficient, but simple */
391 addr = address;
392 for(i = 0; i < len; i++) {
393 /* default read/write accesses */
394 switch(d->config[0x0e]) {
395 case 0x00: /* normal device */
396 case 0x80: /* multi-function device */
397 switch(addr) {
398 case 0x00:
399 case 0x01:
400 case 0x02:
401 case 0x03:
402 case 0x08:
403 case 0x09:
404 case 0x0a:
405 case 0x0b:
406 case 0x0e:
407 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: /* base */
408 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
409 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
410 case 0x2c: case 0x2d: /* subsystem ID */
411 case 0x2e: case 0x2f: /* vendor ID */
412 case 0x30: case 0x31: case 0x32: case 0x33: /* rom */
413 case 0x34: /* Capabilities pointer. */
414 case 0x3d: /* Interrupt pin. */
415 can_write = 0;
416 break;
417 default:
418 can_write = 1;
419 break;
420 }
421 break;
422 default:
423 case 0x01: /* bridge */
424 switch(addr) {
425 case 0x00:
426 case 0x01:
427 case 0x02:
428 case 0x03:
429 case 0x08:
430 case 0x09:
431 case 0x0a:
432 case 0x0b:
433 case 0x0e:
434 case 0x38: case 0x39: case 0x3a: case 0x3b: /* rom */
435 case 0x3d:
436 can_write = 0;
437 break;
438 default:
439 can_write = 1;
440 break;
441 }
442 break;
443 }
444#ifdef VBOX
445 if (addr == 0x05) /* Command register, bits 8-15. */
446 {
447 /* don't change reserved bits (11-15) */
448 val &= UINT32_C(~0xf8);
449 d->config[addr] = val;
450 }
451 else if (addr == 0x06) /* Status register, bits 0-7. */
452 {
453 /* don't change read-only bits => actually all lower bits are read-only */
454 val &= UINT32_C(~0xff);
455 /* status register, low part: clear bits by writing a '1' to the corresponding bit */
456 d->config[addr] &= ~val;
457 }
458 else if (addr == 0x07) /* Status register, bits 8-15. */
459 {
460 /* don't change read-only bits */
461 val &= UINT32_C(~0x06);
462 /* status register, high part: clear bits by writing a '1' to the corresponding bit */
463 d->config[addr] &= ~val;
464 }
465 else
466#endif
467 if (can_write) {
468 d->config[addr] = val;
469 }
470 addr++;
471 val >>= 8;
472 }
473
474 end = address + len;
475 if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) {
476 /* if the command register is modified, we must modify the mappings */
477 pci_update_mappings(d);
478 }
479}
480
481#endif /* IN_RING3 */
482
483static int pci_data_write(PPCIGLOBALS pGlobals, uint32_t addr, uint32_t val, int len)
484{
485 uint8_t iBus, iDevice;
486 uint32_t config_addr;
487
488 Log(("pci_data_write: addr=%08x val=%08x len=%d\n", pGlobals->uConfigReg, val, len));
489
490 if (!(pGlobals->uConfigReg & (1 << 31))) {
491 return VINF_SUCCESS;
492 }
493 if ((pGlobals->uConfigReg & 0x3) != 0) {
494 return VINF_SUCCESS;
495 }
496 iBus = (pGlobals->uConfigReg >> 16) & 0xff;
497 iDevice = (pGlobals->uConfigReg >> 8) & 0xff;
498 config_addr = (pGlobals->uConfigReg & 0xfc) | (addr & 3);
499 if (iBus != 0)
500 {
501 if (pGlobals->PciBus.cBridges)
502 {
503#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
504 PPCIDEVICE pBridgeDevice = pciR3FindBridge(&pGlobals->PciBus, iBus);
505 if (pBridgeDevice)
506 {
507 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
508 pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, config_addr, val, len);
509 }
510#else
511 return VINF_IOM_R3_IOPORT_WRITE;
512#endif
513 }
514 }
515 else
516 {
517 R3PTRTYPE(PCIDevice *) pci_dev = pGlobals->PciBus.devices[iDevice];
518 if (pci_dev)
519 {
520#ifdef IN_RING3
521 Log(("pci_config_write: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, val, len));
522 pci_dev->Int.s.pfnConfigWrite(pci_dev, config_addr, val, len);
523#else
524 return VINF_IOM_R3_IOPORT_WRITE;
525#endif
526 }
527 }
528 return VINF_SUCCESS;
529}
530
531static int pci_data_read(PPCIGLOBALS pGlobals, uint32_t addr, int len, uint32_t *pu32)
532{
533 uint8_t iBus, iDevice;
534 uint32_t config_addr;
535
536 *pu32 = 0xffffffff;
537
538 if (!(pGlobals->uConfigReg & (1 << 31)))
539 return VINF_SUCCESS;
540 if ((pGlobals->uConfigReg & 0x3) != 0)
541 return VINF_SUCCESS;
542 iBus = (pGlobals->uConfigReg >> 16) & 0xff;
543 iDevice = (pGlobals->uConfigReg >> 8) & 0xff;
544 config_addr = (pGlobals->uConfigReg & 0xfc) | (addr & 3);
545 if (iBus != 0)
546 {
547 if (pGlobals->PciBus.cBridges)
548 {
549#ifdef IN_RING3 /** @todo do lookup in R0/RC too! */
550 PPCIDEVICE pBridgeDevice = pciR3FindBridge(&pGlobals->PciBus, iBus);
551 if (pBridgeDevice)
552 {
553 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigRead);
554 *pu32 = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, config_addr, len);
555 }
556#else
557 NOREF(len);
558 return VINF_IOM_R3_IOPORT_READ;
559#endif
560 }
561 }
562 else
563 {
564 R3PTRTYPE(PCIDevice *) pci_dev = pGlobals->PciBus.devices[iDevice];
565 if (pci_dev)
566 {
567#ifdef IN_RING3
568 *pu32 = pci_dev->Int.s.pfnConfigRead(pci_dev, config_addr, len);
569 Log(("pci_config_read: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, *pu32, len));
570#else
571 NOREF(len);
572 return VINF_IOM_R3_IOPORT_READ;
573#endif
574 }
575 }
576
577 return VINF_SUCCESS;
578}
579
580
581
582/* return the global irq number corresponding to a given device irq
583 pin. We could also use the bus number to have a more precise
584 mapping.
585 This is the implementation note described in the PCI spec chapter 2.2.6 */
586static inline int pci_slot_get_pirq(uint8_t uDevFn, int irq_num)
587{
588 int slot_addend;
589 slot_addend = (uDevFn >> 3) - 1;
590 return (irq_num + slot_addend) & 3;
591}
592
593static inline int pci_slot_get_apic_pirq(uint8_t uDevFn, int irq_num)
594{
595 return (irq_num + (uDevFn >> 3)) & 7;
596}
597
598static inline int get_pci_irq_apic_level(PPCIGLOBALS pGlobals, int irq_num)
599{
600 return (pGlobals->pci_apic_irq_levels[irq_num] != 0);
601}
602
603static void apic_set_irq(PPCIBUS pBus, uint8_t uDevFn, PCIDevice *pPciDev, int irq_num1, int iLevel, int acpi_irq, uint32_t uTagSrc)
604{
605 /* This is only allowed to be called with a pointer to the host bus. */
606 AssertMsg(pBus->iBus == 0, ("iBus=%u\n", pBus->iBus));
607
608 if (acpi_irq == -1) {
609 int apic_irq, apic_level;
610 PPCIGLOBALS pGlobals = PCIBUS_2_PCIGLOBALS(pBus);
611 int irq_num = pci_slot_get_apic_pirq(uDevFn, irq_num1);
612
613 if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_HIGH)
614 ASMAtomicIncU32(&pGlobals->pci_apic_irq_levels[irq_num]);
615 else if ((iLevel & PDM_IRQ_LEVEL_HIGH) == PDM_IRQ_LEVEL_LOW)
616 ASMAtomicDecU32(&pGlobals->pci_apic_irq_levels[irq_num]);
617
618 apic_irq = irq_num + 0x10;
619 apic_level = get_pci_irq_apic_level(pGlobals, irq_num);
620 Log3(("apic_set_irq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d\n",
621 R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num));
622 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level, uTagSrc);
623
624 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) {
625 ASMAtomicDecU32(&pGlobals->pci_apic_irq_levels[irq_num]);
626 pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
627 apic_level = get_pci_irq_apic_level(pGlobals, irq_num);
628 Log3(("apic_set_irq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d (flop)\n",
629 R3STRING(pPciDev->name), irq_num1, iLevel, apic_irq, apic_level, irq_num));
630 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), apic_irq, apic_level, uTagSrc);
631 }
632 } else {
633 Log3(("apic_set_irq: %s: irq_num1=%d level=%d acpi_irq=%d\n",
634 R3STRING(pPciDev->name), irq_num1, iLevel, acpi_irq));
635 pBus->CTX_SUFF(pPciHlp)->pfnIoApicSetIrq(pBus->CTX_SUFF(pDevIns), acpi_irq, iLevel, uTagSrc);
636 }
637}
638
639DECLINLINE(int) get_pci_irq_level(PPCIGLOBALS pGlobals, int irq_num)
640{
641 return (pGlobals->pci_irq_levels[irq_num] != 0);
642}
643
644/**
645 * Set the IRQ for a PCI device on the host bus - shared by host bus and bridge.
646 *
647 * @param pDevIns Device instance of the host PCI Bus.
648 * @param uDevFn The device number on the host bus which will raise the IRQ
649 * @param pPciDev The PCI device structure which raised the interrupt.
650 * @param iIrq IRQ number to set.
651 * @param iLevel IRQ level.
652 * @param uTagSrc The IRQ tag and source ID (for tracing).
653 * @remark uDevFn and pPciDev->devfn are not the same if the device is behind a bridge.
654 * In that case uDevFn will be the slot of the bridge which is needed to calculate the
655 * PIRQ value.
656 */
657static void pciSetIrqInternal(PPCIGLOBALS pGlobals, uint8_t uDevFn, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
658{
659 PPCIBUS pBus = &pGlobals->PciBus;
660 uint8_t *pbCfg = pGlobals->PIIX3State.dev.config;
661 const bool fIsAcpiDevice = pPciDev->config[2] == 0x13 && pPciDev->config[3] == 0x71;
662 /* If the two configuration space bytes at 0xde, 0xad are set to 0xbe, 0xef, a back door
663 * is opened to route PCI interrupts directly to the I/O APIC and bypass the PIC.
664 * See the \_SB_.PCI0._PRT method in vbox.dsl.
665 */
666 const bool fIsApicEnabled = pGlobals->fUseIoApic && pbCfg[0xde] == 0xbe && pbCfg[0xad] == 0xef;
667 int pic_irq, pic_level;
668
669 /* Check if the state changed. */
670 if (pPciDev->Int.s.uIrqPinState != iLevel)
671 {
672 pPciDev->Int.s.uIrqPinState = (iLevel & PDM_IRQ_LEVEL_HIGH);
673
674 /* Send interrupt to I/O APIC only. */
675 if (fIsApicEnabled)
676 {
677 if (fIsAcpiDevice)
678 /*
679 * ACPI needs special treatment since SCI is hardwired and
680 * should not be affected by PCI IRQ routing tables at the
681 * same time SCI IRQ is shared in PCI sense hence this
682 * kludge (i.e. we fetch the hardwired value from ACPIs
683 * PCI device configuration space).
684 */
685 apic_set_irq(pBus, uDevFn, pPciDev, -1, iLevel, pPciDev->config[PCI_INTERRUPT_LINE], uTagSrc);
686 else
687 apic_set_irq(pBus, uDevFn, pPciDev, iIrq, iLevel, -1, uTagSrc);
688 return;
689 }
690
691 if (fIsAcpiDevice)
692 {
693 /* As per above treat ACPI in a special way */
694 pic_irq = pPciDev->config[PCI_INTERRUPT_LINE];
695 pGlobals->acpi_irq = pic_irq;
696 pGlobals->acpi_irq_level = iLevel & PDM_IRQ_LEVEL_HIGH;
697 }
698 else
699 {
700 int irq_num;
701 irq_num = pci_slot_get_pirq(uDevFn, iIrq);
702
703 if (pPciDev->Int.s.uIrqPinState == PDM_IRQ_LEVEL_HIGH)
704 ASMAtomicIncU32(&pGlobals->pci_irq_levels[irq_num]);
705 else if (pPciDev->Int.s.uIrqPinState == PDM_IRQ_LEVEL_LOW)
706 ASMAtomicDecU32(&pGlobals->pci_irq_levels[irq_num]);
707
708 /* now we change the pic irq level according to the piix irq mappings */
709 pic_irq = pbCfg[0x60 + irq_num];
710 if (pic_irq >= 16)
711 {
712 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
713 {
714 ASMAtomicDecU32(&pGlobals->pci_irq_levels[irq_num]);
715 pPciDev->Int.s.uIrqPinState = PDM_IRQ_LEVEL_LOW;
716 }
717
718 return;
719 }
720 }
721
722 /* the pic level is the logical OR of all the PCI irqs mapped to it */
723 pic_level = 0;
724 if (pic_irq == pbCfg[0x60])
725 pic_level |= get_pci_irq_level(pGlobals, 0);
726 if (pic_irq == pbCfg[0x61])
727 pic_level |= get_pci_irq_level(pGlobals, 1);
728 if (pic_irq == pbCfg[0x62])
729 pic_level |= get_pci_irq_level(pGlobals, 2);
730 if (pic_irq == pbCfg[0x63])
731 pic_level |= get_pci_irq_level(pGlobals, 3);
732 if (pic_irq == pGlobals->acpi_irq)
733 pic_level |= pGlobals->acpi_irq_level;
734
735 Log3(("pciSetIrq: %s: iLevel=%d iIrq=%d pic_irq=%d pic_level=%d uTagSrc=%#x\n",
736 R3STRING(pPciDev->name), iLevel, iIrq, pic_irq, pic_level, uTagSrc));
737 pBus->CTX_SUFF(pPciHlp)->pfnIsaSetIrq(pBus->CTX_SUFF(pDevIns), pic_irq, pic_level, uTagSrc);
738
739 /** @todo optimize pci irq flip-flop some rainy day. */
740 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
741 pciSetIrqInternal(pGlobals, uDevFn, pPciDev, iIrq, PDM_IRQ_LEVEL_LOW, uTagSrc);
742 }
743}
744
745/**
746 * Set the IRQ for a PCI device on the host bus.
747 *
748 * @param pDevIns Device instance of the PCI Bus.
749 * @param pPciDev The PCI device structure.
750 * @param iIrq IRQ number to set.
751 * @param iLevel IRQ level.
752 * @param uTagSrc The IRQ tag and source ID (for tracing).
753 */
754PDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
755{
756 pciSetIrqInternal(PDMINS_2_DATA(pDevIns, PPCIGLOBALS), pPciDev->devfn, pPciDev, iIrq, iLevel, uTagSrc);
757}
758
759#ifdef IN_RING3
760
761/**
762 * Finds a bridge on the bus which contains the destination bus.
763 *
764 * @return Pointer to the device instance data of the bus or
765 * NULL if no bridge was found.
766 * @param pBus Pointer to the bus to search on.
767 * @param iBus Destination bus number.
768 */
769DECLINLINE(PPCIDEVICE) pciR3FindBridge(PPCIBUS pBus, uint8_t iBus)
770{
771 /* Search for a fitting bridge. */
772 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
773 {
774 /*
775 * Examine secondary and subordinate bus number.
776 * If the target bus is in the range we pass the request on to the bridge.
777 */
778 PPCIDEVICE pBridgeTemp = pBus->papBridgesR3[iBridge];
779 AssertMsg(pBridgeTemp && pciDevIsPci2PciBridge(pBridgeTemp),
780 ("Device is not a PCI bridge but on the list of PCI bridges\n"));
781
782 if ( iBus >= pBridgeTemp->config[VBOX_PCI_SECONDARY_BUS]
783 && iBus <= pBridgeTemp->config[VBOX_PCI_SUBORDINATE_BUS])
784 return pBridgeTemp;
785 }
786
787 /* Nothing found. */
788 return NULL;
789}
790
791static void pciR3Piix3Reset(PIIX3State *d)
792{
793 uint8_t *pci_conf = d->dev.config;
794
795 pci_conf[0x04] = 0x07; /* master, memory and I/O */
796 pci_conf[0x05] = 0x00;
797 pci_conf[0x06] = 0x00;
798 pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */
799 pci_conf[0x4c] = 0x4d;
800 pci_conf[0x4e] = 0x03;
801 pci_conf[0x4f] = 0x00;
802 pci_conf[0x60] = 0x80;
803 pci_conf[0x69] = 0x02;
804 pci_conf[0x70] = 0x80;
805 pci_conf[0x76] = 0x0c;
806 pci_conf[0x77] = 0x0c;
807 pci_conf[0x78] = 0x02;
808 pci_conf[0x79] = 0x00;
809 pci_conf[0x80] = 0x00;
810 pci_conf[0x82] = 0x02; /* Get rid of the Linux guest "Enabling Passive Release" PCI quirk warning. */
811 pci_conf[0xa0] = 0x08;
812 pci_conf[0xa0] = 0x08;
813 pci_conf[0xa2] = 0x00;
814 pci_conf[0xa3] = 0x00;
815 pci_conf[0xa4] = 0x00;
816 pci_conf[0xa5] = 0x00;
817 pci_conf[0xa6] = 0x00;
818 pci_conf[0xa7] = 0x00;
819 pci_conf[0xa8] = 0x0f;
820 pci_conf[0xaa] = 0x00;
821 pci_conf[0xab] = 0x00;
822 pci_conf[0xac] = 0x00;
823 pci_conf[0xae] = 0x00;
824}
825
826static void pci_config_writel(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t val)
827{
828 pGlobals->uConfigReg = 0x80000000 | (uBus << 16) |
829 (uDevFn << 8) | addr;
830 pci_data_write(pGlobals, 0, val, 4);
831}
832
833static void pci_config_writew(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t val)
834{
835 pGlobals->uConfigReg = 0x80000000 | (uBus << 16) |
836 (uDevFn << 8) | (addr & ~3);
837 pci_data_write(pGlobals, addr & 3, val, 2);
838}
839
840static void pci_config_writeb(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr, uint32_t val)
841{
842 pGlobals->uConfigReg = 0x80000000 | (uBus << 16) |
843 (uDevFn << 8) | (addr & ~3);
844 pci_data_write(pGlobals, addr & 3, val, 1);
845}
846
847static uint32_t pci_config_readl(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr)
848{
849 pGlobals->uConfigReg = 0x80000000 | (uBus << 16) |
850 (uDevFn << 8) | addr;
851 uint32_t u32Val;
852 int rc = pci_data_read(pGlobals, 0, 4, &u32Val);
853 AssertRC(rc);
854 return u32Val;
855}
856
857static uint32_t pci_config_readw(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr)
858{
859 pGlobals->uConfigReg = 0x80000000 | (uBus << 16) |
860 (uDevFn << 8) | (addr & ~3);
861 uint32_t u32Val;
862 int rc = pci_data_read(pGlobals, addr & 3, 2, &u32Val);
863 AssertRC(rc);
864 return u32Val;
865}
866
867static uint32_t pci_config_readb(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint32_t addr)
868{
869 pGlobals->uConfigReg = 0x80000000 | (uBus << 16) |
870 (uDevFn << 8) | (addr & ~3);
871 uint32_t u32Val;
872 int rc = pci_data_read(pGlobals, addr & 3, 1, &u32Val);
873 AssertRC(rc);
874 return u32Val;
875}
876
877/* host irqs corresponding to PCI irqs A-D */
878static const uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; /* bird: added const */
879
880static void pci_set_io_region_addr(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, int region_num, uint32_t addr)
881{
882 uint16_t cmd;
883 uint32_t ofs;
884
885 if ( region_num == PCI_ROM_SLOT )
886 ofs = 0x30;
887 else
888 ofs = 0x10 + region_num * 4;
889
890 /* Read memory type first. */
891 uint8_t uRessourceType = pci_config_readb(pGlobals, uBus, uDevFn, ofs);
892
893 /* Read command register. */
894 cmd = pci_config_readw(pGlobals, uBus, uDevFn, PCI_COMMAND);
895 if ( region_num == PCI_ROM_SLOT )
896 cmd |= 2;
897 else if ((uRessourceType & 0x01) == 1) /* Test if region is I/O space. */
898 cmd |= 1; /* Enable I/O space access. */
899 else /* The region is MMIO. */
900 cmd |= 2; /* Enable MMIO access. */
901
902 /* Write address of the device. */
903 pci_config_writel(pGlobals, uBus, uDevFn, ofs, addr);
904
905 /* enable memory mappings */
906 pci_config_writew(pGlobals, uBus, uDevFn, PCI_COMMAND, cmd);
907}
908
909static void pci_bios_init_device(PPCIGLOBALS pGlobals, uint8_t uBus, uint8_t uDevFn, uint8_t cBridgeDepth, uint8_t *paBridgePositions)
910{
911 uint32_t *paddr;
912 int i, pin, pic_irq;
913 uint16_t devclass, vendor_id, device_id;
914
915 devclass = pci_config_readw(pGlobals, uBus, uDevFn, PCI_CLASS_DEVICE);
916 vendor_id = pci_config_readw(pGlobals, uBus, uDevFn, PCI_VENDOR_ID);
917 device_id = pci_config_readw(pGlobals, uBus, uDevFn, PCI_DEVICE_ID);
918
919 /* Check if device is present. */
920 if (vendor_id != 0xffff)
921 {
922 switch(devclass)
923 {
924 case 0x0101:
925 if ( (vendor_id == 0x8086)
926 && (device_id == 0x7010 || device_id == 0x7111 || device_id == 0x269e))
927 {
928 /* PIIX3, PIIX4 or ICH6 IDE */
929 pci_config_writew(pGlobals, uBus, uDevFn, 0x40, 0x8000); /* enable IDE0 */
930 pci_config_writew(pGlobals, uBus, uDevFn, 0x42, 0x8000); /* enable IDE1 */
931 goto default_map;
932 }
933 else
934 {
935 /* IDE: we map it as in ISA mode */
936 pci_set_io_region_addr(pGlobals, uBus, uDevFn, 0, 0x1f0);
937 pci_set_io_region_addr(pGlobals, uBus, uDevFn, 1, 0x3f4);
938 pci_set_io_region_addr(pGlobals, uBus, uDevFn, 2, 0x170);
939 pci_set_io_region_addr(pGlobals, uBus, uDevFn, 3, 0x374);
940 }
941 break;
942 case 0x0300:
943 if (vendor_id != 0x80ee)
944 goto default_map;
945 /* VGA: map frame buffer to default Bochs VBE address */
946 pci_set_io_region_addr(pGlobals, uBus, uDevFn, 0, 0xE0000000);
947 /*
948 * Legacy VGA I/O ports are implicitly decoded by a VGA class device. But
949 * only the framebuffer (i.e., a memory region) is explicitly registered via
950 * pci_set_io_region_addr, so I/O decoding must be enabled manually.
951 */
952 pci_config_writeb(pGlobals, uBus, uDevFn, PCI_COMMAND,
953 pci_config_readb(pGlobals, uBus, uDevFn, PCI_COMMAND)
954 | 1 /* Enable I/O space access. */);
955 break;
956 case 0x0800:
957 /* PIC */
958 vendor_id = pci_config_readw(pGlobals, uBus, uDevFn, PCI_VENDOR_ID);
959 device_id = pci_config_readw(pGlobals, uBus, uDevFn, PCI_DEVICE_ID);
960 if (vendor_id == 0x1014)
961 {
962 /* IBM */
963 if (device_id == 0x0046 || device_id == 0xFFFF)
964 {
965 /* MPIC & MPIC2 */
966 pci_set_io_region_addr(pGlobals, uBus, uDevFn, 0, 0x80800000 + 0x00040000);
967 }
968 }
969 break;
970 case 0xff00:
971 if ( (vendor_id == 0x0106b)
972 && (device_id == 0x0017 || device_id == 0x0022))
973 {
974 /* macio bridge */
975 pci_set_io_region_addr(pGlobals, uBus, uDevFn, 0, 0x80800000);
976 }
977 break;
978 case 0x0604:
979 {
980 /* Init PCI-to-PCI bridge. */
981 pci_config_writeb(pGlobals, uBus, uDevFn, VBOX_PCI_PRIMARY_BUS, uBus);
982
983 AssertMsg(pGlobals->uBus < 255, ("Too many bridges on the bus\n"));
984 pGlobals->uBus++;
985 pci_config_writeb(pGlobals, uBus, uDevFn, VBOX_PCI_SECONDARY_BUS, pGlobals->uBus);
986 pci_config_writeb(pGlobals, uBus, uDevFn, VBOX_PCI_SUBORDINATE_BUS, 0xff); /* Temporary until we know how many other bridges are behind this one. */
987
988 /* Add position of this bridge into the array. */
989 paBridgePositions[cBridgeDepth+1] = (uDevFn >> 3);
990
991 /*
992 * The I/O range for the bridge must be aligned to a 4KB boundary.
993 * This does not change anything really as the access to the device is not going
994 * through the bridge but we want to be compliant to the spec.
995 */
996 if ((pGlobals->pci_bios_io_addr % 4096) != 0)
997 pGlobals->pci_bios_io_addr = RT_ALIGN_32(pGlobals->pci_bios_io_addr, 4*1024);
998 Log(("%s: Aligned I/O start address. New address %#x\n", __FUNCTION__, pGlobals->pci_bios_io_addr));
999 pci_config_writeb(pGlobals, uBus, uDevFn, VBOX_PCI_IO_BASE, (pGlobals->pci_bios_io_addr >> 8) & 0xf0);
1000
1001 /* The MMIO range for the bridge must be aligned to a 1MB boundary. */
1002 if ((pGlobals->pci_bios_mem_addr % (1024 * 1024)) != 0)
1003 pGlobals->pci_bios_mem_addr = RT_ALIGN_32(pGlobals->pci_bios_mem_addr, 1024*1024);
1004 Log(("%s: Aligned MMIO start address. New address %#x\n", __FUNCTION__, pGlobals->pci_bios_mem_addr));
1005 pci_config_writew(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_BASE, (pGlobals->pci_bios_mem_addr >> 16) & UINT32_C(0xffff0));
1006
1007 /* Save values to compare later to. */
1008 uint32_t u32IoAddressBase = pGlobals->pci_bios_io_addr;
1009 uint32_t u32MMIOAddressBase = pGlobals->pci_bios_mem_addr;
1010
1011 /* Init devices behind the bridge and possibly other bridges as well. */
1012 for (int iDev = 0; iDev <= 255; iDev++)
1013 pci_bios_init_device(pGlobals, uBus + 1, iDev, cBridgeDepth + 1, paBridgePositions);
1014
1015 /* The number of bridges behind the this one is now available. */
1016 pci_config_writeb(pGlobals, uBus, uDevFn, VBOX_PCI_SUBORDINATE_BUS, pGlobals->uBus);
1017
1018 /*
1019 * Set I/O limit register. If there is no device with I/O space behind the bridge
1020 * we set a lower value than in the base register.
1021 * The result with a real bridge is that no I/O transactions are passed to the secondary
1022 * interface. Again this doesn't really matter here but we want to be compliant to the spec.
1023 */
1024 if ((u32IoAddressBase != pGlobals->pci_bios_io_addr) && ((pGlobals->pci_bios_io_addr % 4096) != 0))
1025 {
1026 /* The upper boundary must be one byte less than a 4KB boundary. */
1027 pGlobals->pci_bios_io_addr = RT_ALIGN_32(pGlobals->pci_bios_io_addr, 4*1024);
1028 }
1029 pci_config_writeb(pGlobals, uBus, uDevFn, VBOX_PCI_IO_LIMIT, ((pGlobals->pci_bios_io_addr >> 8) & 0xf0) - 1);
1030
1031 /* Same with the MMIO limit register but with 1MB boundary here. */
1032 if ((u32MMIOAddressBase != pGlobals->pci_bios_mem_addr) && ((pGlobals->pci_bios_mem_addr % (1024 * 1024)) != 0))
1033 {
1034 /* The upper boundary must be one byte less than a 1MB boundary. */
1035 pGlobals->pci_bios_mem_addr = RT_ALIGN_32(pGlobals->pci_bios_mem_addr, 1024*1024);
1036 }
1037 pci_config_writew(pGlobals, uBus, uDevFn, VBOX_PCI_MEMORY_LIMIT, ((pGlobals->pci_bios_mem_addr >> 16) & UINT32_C(0xfff0)) - 1);
1038
1039 /*
1040 * Set the prefetch base and limit registers. We currently have no device with a prefetchable region
1041 * which may be behind a bridge. That's why it is unconditionally disabled here atm by writing a higher value into
1042 * the base register than in the limit register.
1043 */
1044 pci_config_writew(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_BASE, 0xfff0);
1045 pci_config_writew(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_MEMORY_LIMIT, 0x0);
1046 pci_config_writel(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_BASE_UPPER32, 0x00);
1047 pci_config_writel(pGlobals, uBus, uDevFn, VBOX_PCI_PREF_LIMIT_UPPER32, 0x00);
1048 break;
1049 }
1050 default:
1051 default_map:
1052 {
1053 /* default memory mappings */
1054 /*
1055 * PCI_NUM_REGIONS is 7 because of the rom region but there are only 6 base address register defined by the PCI spec.
1056 * Leaving only PCI_NUM_REGIONS would cause reading another and enabling a memory region which does not exist.
1057 */
1058 for(i = 0; i < (PCI_NUM_REGIONS-1); i++)
1059 {
1060 uint32_t u32Size;
1061 uint8_t u8RessourceType;
1062 uint32_t u32Address = 0x10 + i * 4;
1063
1064 /* Calculate size. */
1065 u8RessourceType = pci_config_readb(pGlobals, uBus, uDevFn, u32Address);
1066 pci_config_writel(pGlobals, uBus, uDevFn, u32Address, UINT32_C(0xffffffff));
1067 u32Size = pci_config_readl(pGlobals, uBus, uDevFn, u32Address);
1068 /* Clear resource information depending on resource type. */
1069 if ((u8RessourceType & 0x01) == 1) /* I/O */
1070 u32Size &= ~(0x01);
1071 else /* MMIO */
1072 u32Size &= ~(0x0f);
1073
1074 /*
1075 * Invert all bits and add 1 to get size of the region.
1076 * (From PCI implementation note)
1077 */
1078 if (((u8RessourceType & 0x01) == 1) && (u32Size & UINT32_C(0xffff0000)) == 0)
1079 u32Size = (~(u32Size | UINT32_C(0xffff0000))) + 1;
1080 else
1081 u32Size = (~u32Size) + 1;
1082
1083 Log(("%s: Size of region %u for device %d on bus %d is %u\n", __FUNCTION__, i, uDevFn, uBus, u32Size));
1084
1085 if (u32Size)
1086 {
1087 if ((u8RessourceType & 0x01) == 1)
1088 paddr = &pGlobals->pci_bios_io_addr;
1089 else
1090 paddr = &pGlobals->pci_bios_mem_addr;
1091 *paddr = (*paddr + u32Size - 1) & ~(u32Size - 1);
1092 Log(("%s: Start address of %s region %u is %#x\n", __FUNCTION__, ((u8RessourceType & 0x01) == 1 ? "I/O" : "MMIO"), i, *paddr));
1093 pci_set_io_region_addr(pGlobals, uBus, uDevFn, i, *paddr);
1094 *paddr += u32Size;
1095 Log(("%s: New address is %#x\n", __FUNCTION__, *paddr));
1096 }
1097 }
1098 break;
1099 }
1100 }
1101
1102 /* map the interrupt */
1103 pin = pci_config_readb(pGlobals, uBus, uDevFn, PCI_INTERRUPT_PIN);
1104 if (pin != 0)
1105 {
1106 uint8_t uBridgeDevFn = uDevFn;
1107 pin--;
1108
1109 /* We need to go up to the host bus to see which irq this device will assert there. */
1110 while (cBridgeDepth != 0)
1111 {
1112 /* Get the pin the device would assert on the bridge. */
1113 pin = ((uBridgeDevFn >> 3) + pin) & 3;
1114 uBridgeDevFn = paBridgePositions[cBridgeDepth];
1115 cBridgeDepth--;
1116 }
1117
1118 pin = pci_slot_get_pirq(uDevFn, pin);
1119 pic_irq = pci_irqs[pin];
1120 pci_config_writeb(pGlobals, uBus, uDevFn, PCI_INTERRUPT_LINE, pic_irq);
1121 }
1122 }
1123}
1124
1125#endif /* IN_RING3 */
1126
1127/* -=-=-=-=-=- wrappers -=-=-=-=-=- */
1128
1129/**
1130 * Port I/O Handler for PCI address OUT operations.
1131 *
1132 * @returns VBox status code.
1133 *
1134 * @param pDevIns The device instance.
1135 * @param pvUser User argument - ignored.
1136 * @param uPort Port number used for the IN operation.
1137 * @param u32 The value to output.
1138 * @param cb The value size in bytes.
1139 */
1140PDMBOTHCBDECL(int) pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1141{
1142 Log(("pciIOPortAddressWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
1143 NOREF(pvUser);
1144 if (cb == 4)
1145 {
1146 PPCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
1147 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
1148 pThis->uConfigReg = u32 & ~3; /* Bits 0-1 are reserved and we silently clear them */
1149 PCI_UNLOCK(pDevIns);
1150 }
1151 /* else: 440FX does "pass through to the bus" for other writes, what ever that means.
1152 * Linux probes for cmd640 using byte writes/reads during ide init. We'll just ignore it. */
1153 return VINF_SUCCESS;
1154}
1155
1156
1157/**
1158 * Port I/O Handler for PCI address IN operations.
1159 *
1160 * @returns VBox status code.
1161 *
1162 * @param pDevIns The device instance.
1163 * @param pvUser User argument - ignored.
1164 * @param uPort Port number used for the IN operation.
1165 * @param pu32 Where to store the result.
1166 * @param cb Number of bytes read.
1167 */
1168PDMBOTHCBDECL(int) pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1169{
1170 NOREF(pvUser);
1171 if (cb == 4)
1172 {
1173 PPCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
1174 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_READ);
1175 *pu32 = pThis->uConfigReg;
1176 PCI_UNLOCK(pDevIns);
1177 Log(("pciIOPortAddressRead: Port=%#x cb=%d -> %#x\n", Port, cb, *pu32));
1178 return VINF_SUCCESS;
1179 }
1180 /* else: 440FX does "pass through to the bus" for other writes, what ever that means.
1181 * Linux probes for cmd640 using byte writes/reads during ide init. We'll just ignore it. */
1182 Log(("pciIOPortAddressRead: Port=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", Port, cb));
1183 return VERR_IOM_IOPORT_UNUSED;
1184}
1185
1186
1187/**
1188 * Port I/O Handler for PCI data OUT operations.
1189 *
1190 * @returns VBox status code.
1191 *
1192 * @param pDevIns The device instance.
1193 * @param pvUser User argument - ignored.
1194 * @param uPort Port number used for the IN operation.
1195 * @param u32 The value to output.
1196 * @param cb The value size in bytes.
1197 */
1198PDMBOTHCBDECL(int) pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
1199{
1200 Log(("pciIOPortDataWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
1201 NOREF(pvUser);
1202 int rc = VINF_SUCCESS;
1203 if (!(Port % cb))
1204 {
1205 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_WRITE);
1206 rc = pci_data_write(PDMINS_2_DATA(pDevIns, PPCIGLOBALS), Port, u32, cb);
1207 PCI_UNLOCK(pDevIns);
1208 }
1209 else
1210 AssertMsgFailed(("Write to port %#x u32=%#x cb=%d\n", Port, u32, cb));
1211 return rc;
1212}
1213
1214
1215/**
1216 * Port I/O Handler for PCI data IN operations.
1217 *
1218 * @returns VBox status code.
1219 *
1220 * @param pDevIns The device instance.
1221 * @param pvUser User argument - ignored.
1222 * @param uPort Port number used for the IN operation.
1223 * @param pu32 Where to store the result.
1224 * @param cb Number of bytes read.
1225 */
1226PDMBOTHCBDECL(int) pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
1227{
1228 NOREF(pvUser);
1229 if (!(Port % cb))
1230 {
1231 PCI_LOCK(pDevIns, VINF_IOM_R3_IOPORT_READ);
1232 int rc = pci_data_read(PDMINS_2_DATA(pDevIns, PPCIGLOBALS), Port, cb, pu32);
1233 PCI_UNLOCK(pDevIns);
1234 Log(("pciIOPortDataRead: Port=%#x cb=%#x -> %#x (%Rrc)\n", Port, cb, *pu32, rc));
1235 return rc;
1236 }
1237 AssertMsgFailed(("Read from port %#x cb=%d\n", Port, cb));
1238 return VERR_IOM_IOPORT_UNUSED;
1239}
1240
1241#ifdef IN_RING3
1242
1243/**
1244 * Common worker for pciR3SaveExec and pcibridgeR3SaveExec.
1245 *
1246 * @returns VBox status code.
1247 * @param pBus The bus to save.
1248 * @param pSSM The saved state handle.
1249 */
1250static int pciR3CommonSaveExec(PPCIBUS pBus, PSSMHANDLE pSSM)
1251{
1252 /*
1253 * Iterate thru all the devices.
1254 */
1255 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->devices); i++)
1256 {
1257 PPCIDEVICE pDev = pBus->devices[i];
1258 if (pDev)
1259 {
1260 SSMR3PutU32(pSSM, i);
1261 SSMR3PutMem(pSSM, pDev->config, sizeof(pDev->config));
1262
1263 int rc = SSMR3PutS32(pSSM, pDev->Int.s.uIrqPinState);
1264 if (RT_FAILURE(rc))
1265 return rc;
1266 }
1267 }
1268 return SSMR3PutU32(pSSM, UINT32_MAX); /* terminator */
1269}
1270
1271
1272/**
1273 * Saves a state of the PCI device.
1274 *
1275 * @returns VBox status code.
1276 * @param pDevIns The device instance.
1277 * @param pPciDev Pointer to PCI device.
1278 * @param pSSM The handle to save the state to.
1279 */
1280static DECLCALLBACK(int) pciR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
1281{
1282 uint32_t i;
1283 PPCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
1284
1285 /*
1286 * Bus state data.
1287 */
1288 SSMR3PutU32(pSSM, pThis->uConfigReg);
1289 SSMR3PutBool(pSSM, pThis->fUseIoApic);
1290
1291 /*
1292 * Save IRQ states.
1293 */
1294 for (i = 0; i < PCI_IRQ_PINS; i++)
1295 SSMR3PutU32(pSSM, pThis->pci_irq_levels[i]);
1296 for (i = 0; i < PCI_APIC_IRQ_PINS; i++)
1297 SSMR3PutU32(pSSM, pThis->pci_apic_irq_levels[i]);
1298
1299 SSMR3PutU32(pSSM, pThis->acpi_irq_level);
1300 SSMR3PutS32(pSSM, pThis->acpi_irq);
1301
1302 SSMR3PutU32(pSSM, ~0); /* separator */
1303
1304 /*
1305 * Join paths with pcibridgeR3SaveExec.
1306 */
1307 return pciR3CommonSaveExec(&pThis->PciBus, pSSM);
1308}
1309
1310
1311/**
1312 * Common routine for restoring the config registers of a PCI device.
1313 *
1314 * @param pDev The PCI device.
1315 * @param pbSrcConfig The configuration register values to be loaded.
1316 * @param fIsBridge Whether this is a bridge device or not.
1317 */
1318static void pciR3CommonRestoreConfig(PPCIDEVICE pDev, uint8_t const *pbSrcConfig, bool fIsBridge)
1319{
1320 /*
1321 * This table defines the fields for normal devices and bridge devices, and
1322 * the order in which they need to be restored.
1323 */
1324 static const struct PciField
1325 {
1326 uint8_t off;
1327 uint8_t cb;
1328 uint8_t fWritable;
1329 uint8_t fBridge;
1330 const char *pszName;
1331 } s_aFields[] =
1332 {
1333 /* off,cb,fW,fB, pszName */
1334 { 0x00, 2, 0, 3, "VENDOR_ID" },
1335 { 0x02, 2, 0, 3, "DEVICE_ID" },
1336 { 0x06, 2, 1, 3, "STATUS" },
1337 { 0x08, 1, 0, 3, "REVISION_ID" },
1338 { 0x09, 1, 0, 3, "CLASS_PROG" },
1339 { 0x0a, 1, 0, 3, "CLASS_SUB" },
1340 { 0x0b, 1, 0, 3, "CLASS_BASE" },
1341 { 0x0c, 1, 1, 3, "CACHE_LINE_SIZE" },
1342 { 0x0d, 1, 1, 3, "LATENCY_TIMER" },
1343 { 0x0e, 1, 0, 3, "HEADER_TYPE" },
1344 { 0x0f, 1, 1, 3, "BIST" },
1345 { 0x10, 4, 1, 3, "BASE_ADDRESS_0" },
1346 { 0x14, 4, 1, 3, "BASE_ADDRESS_1" },
1347 { 0x18, 4, 1, 1, "BASE_ADDRESS_2" },
1348 { 0x18, 1, 1, 2, "PRIMARY_BUS" }, // fWritable = ??
1349 { 0x19, 1, 1, 2, "SECONDARY_BUS" }, // fWritable = ??
1350 { 0x1a, 1, 1, 2, "SUBORDINATE_BUS" }, // fWritable = ??
1351 { 0x1b, 1, 1, 2, "SEC_LATENCY_TIMER" }, // fWritable = ??
1352 { 0x1c, 4, 1, 1, "BASE_ADDRESS_3" },
1353 { 0x1c, 1, 1, 2, "IO_BASE" }, // fWritable = ??
1354 { 0x1d, 1, 1, 2, "IO_LIMIT" }, // fWritable = ??
1355 { 0x1e, 2, 1, 2, "SEC_STATUS" }, // fWritable = ??
1356 { 0x20, 4, 1, 1, "BASE_ADDRESS_4" },
1357 { 0x20, 2, 1, 2, "MEMORY_BASE" }, // fWritable = ??
1358 { 0x22, 2, 1, 2, "MEMORY_LIMIT" }, // fWritable = ??
1359 { 0x24, 4, 1, 1, "BASE_ADDRESS_5" },
1360 { 0x24, 2, 1, 2, "PREF_MEMORY_BASE" }, // fWritable = ??
1361 { 0x26, 2, 1, 2, "PREF_MEMORY_LIMIT" }, // fWritable = ??
1362 { 0x28, 4, 1, 1, "CARDBUS_CIS" }, // fWritable = ??
1363 { 0x28, 4, 1, 2, "PREF_BASE_UPPER32" }, // fWritable = ??
1364 { 0x2c, 2, 0, 1, "SUBSYSTEM_VENDOR_ID" },// fWritable = !?
1365 { 0x2c, 4, 1, 2, "PREF_LIMIT_UPPER32" },// fWritable = ??
1366 { 0x2e, 2, 0, 1, "SUBSYSTEM_ID" }, // fWritable = !?
1367 { 0x30, 4, 1, 1, "ROM_ADDRESS" }, // fWritable = ?!
1368 { 0x30, 2, 1, 2, "IO_BASE_UPPER16" }, // fWritable = ?!
1369 { 0x32, 2, 1, 2, "IO_LIMIT_UPPER16" }, // fWritable = ?!
1370 { 0x34, 4, 0, 3, "CAPABILITY_LIST" }, // fWritable = !? cb=!?
1371 { 0x38, 4, 1, 1, "RESERVED_38" }, // ???
1372 { 0x38, 4, 1, 2, "ROM_ADDRESS_BR" }, // fWritable = !? cb=!? fBridge=!?
1373 { 0x3c, 1, 1, 3, "INTERRUPT_LINE" }, // fBridge=??
1374 { 0x3d, 1, 0, 3, "INTERRUPT_PIN" }, // fBridge=??
1375 { 0x3e, 1, 0, 1, "MIN_GNT" },
1376 { 0x3e, 2, 1, 2, "BRIDGE_CONTROL" }, // fWritable = !?
1377 { 0x3f, 1, 0, 1, "MAX_LAT" },
1378 /* The COMMAND register must come last as it requires the *ADDRESS*
1379 registers to be restored before we pretent to change it from 0 to
1380 whatever value the guest assigned it. */
1381 { 0x04, 2, 1, 3, "COMMAND" },
1382 };
1383
1384#ifdef RT_STRICT
1385 /* Check that we've got full register coverage. */
1386 uint32_t bmDevice[0x40 / 32];
1387 uint32_t bmBridge[0x40 / 32];
1388 RT_ZERO(bmDevice);
1389 RT_ZERO(bmBridge);
1390 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1391 {
1392 uint8_t off = s_aFields[i].off;
1393 uint8_t cb = s_aFields[i].cb;
1394 uint8_t f = s_aFields[i].fBridge;
1395 while (cb-- > 0)
1396 {
1397 if (f & 1) AssertMsg(!ASMBitTest(bmDevice, off), ("%#x\n", off));
1398 if (f & 2) AssertMsg(!ASMBitTest(bmBridge, off), ("%#x\n", off));
1399 if (f & 1) ASMBitSet(bmDevice, off);
1400 if (f & 2) ASMBitSet(bmBridge, off);
1401 off++;
1402 }
1403 }
1404 for (uint32_t off = 0; off < 0x40; off++)
1405 {
1406 AssertMsg(ASMBitTest(bmDevice, off), ("%#x\n", off));
1407 AssertMsg(ASMBitTest(bmBridge, off), ("%#x\n", off));
1408 }
1409#endif
1410
1411 /*
1412 * Loop thru the fields covering the 64 bytes of standard registers.
1413 */
1414 uint8_t const fBridge = fIsBridge ? 2 : 1;
1415 uint8_t *pbDstConfig = &pDev->config[0];
1416 for (uint32_t i = 0; i < RT_ELEMENTS(s_aFields); i++)
1417 if (s_aFields[i].fBridge & fBridge)
1418 {
1419 uint8_t const off = s_aFields[i].off;
1420 uint8_t const cb = s_aFields[i].cb;
1421 uint32_t u32Src;
1422 uint32_t u32Dst;
1423 switch (cb)
1424 {
1425 case 1:
1426 u32Src = pbSrcConfig[off];
1427 u32Dst = pbDstConfig[off];
1428 break;
1429 case 2:
1430 u32Src = *(uint16_t const *)&pbSrcConfig[off];
1431 u32Dst = *(uint16_t const *)&pbDstConfig[off];
1432 break;
1433 case 4:
1434 u32Src = *(uint32_t const *)&pbSrcConfig[off];
1435 u32Dst = *(uint32_t const *)&pbDstConfig[off];
1436 break;
1437 default:
1438 AssertFailed();
1439 continue;
1440 }
1441
1442 if ( u32Src != u32Dst
1443 || off == VBOX_PCI_COMMAND)
1444 {
1445 if (u32Src != u32Dst)
1446 {
1447 if (!s_aFields[i].fWritable)
1448 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x - !READ ONLY!\n",
1449 pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1450 else
1451 LogRel(("PCI: %8s/%u: %2u-bit field %s: %x -> %x\n",
1452 pDev->name, pDev->pDevIns->iInstance, cb*8, s_aFields[i].pszName, u32Dst, u32Src));
1453 }
1454 if (off == VBOX_PCI_COMMAND)
1455 PCIDevSetCommand(pDev, 0); /* For remapping, see pciR3CommonLoadExec. */
1456 pDev->Int.s.pfnConfigWrite(pDev, off, u32Src, cb);
1457 }
1458 }
1459
1460 /*
1461 * The device dependent registers.
1462 *
1463 * We will not use ConfigWrite here as we have no clue about the size
1464 * of the registers, so the device is responsible for correctly
1465 * restoring functionality governed by these registers.
1466 */
1467 for (uint32_t off = 0x40; off < sizeof(pDev->config); off++)
1468 if (pbDstConfig[off] != pbSrcConfig[off])
1469 {
1470 LogRel(("PCI: %8s/%u: register %02x: %02x -> %02x\n",
1471 pDev->name, pDev->pDevIns->iInstance, off, pbDstConfig[off], pbSrcConfig[off])); /** @todo make this Log() later. */
1472 pbDstConfig[off] = pbSrcConfig[off];
1473 }
1474}
1475
1476
1477/**
1478 * Common worker for pciR3LoadExec and pcibridgeR3LoadExec.
1479 *
1480 * @returns VBox status code.
1481 * @param pBus The bus which data is being loaded.
1482 * @param pSSM The saved state handle.
1483 * @param uVersion The data version.
1484 * @param uPass The pass.
1485 */
1486static DECLCALLBACK(int) pciR3CommonLoadExec(PPCIBUS pBus, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1487{
1488 uint32_t u32;
1489 uint32_t i;
1490 int rc;
1491
1492 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1493
1494 /*
1495 * Iterate thru all the devices and write 0 to the COMMAND register so
1496 * that all the memory is unmapped before we start restoring the saved
1497 * mapping locations.
1498 *
1499 * The register value is restored afterwards so we can do proper
1500 * LogRels in pciR3CommonRestoreConfig.
1501 */
1502 for (i = 0; i < RT_ELEMENTS(pBus->devices); i++)
1503 {
1504 PPCIDEVICE pDev = pBus->devices[i];
1505 if (pDev)
1506 {
1507 uint16_t u16 = PCIDevGetCommand(pDev);
1508 pDev->Int.s.pfnConfigWrite(pDev, VBOX_PCI_COMMAND, 0, 2);
1509 PCIDevSetCommand(pDev, u16);
1510 Assert(PCIDevGetCommand(pDev) == u16);
1511 }
1512 }
1513
1514 /*
1515 * Iterate all the devices.
1516 */
1517 for (i = 0;; i++)
1518 {
1519 PCIDEVICE DevTmp;
1520 PPCIDEVICE pDev;
1521
1522 /* index / terminator */
1523 rc = SSMR3GetU32(pSSM, &u32);
1524 if (RT_FAILURE(rc))
1525 return rc;
1526 if (u32 == (uint32_t)~0)
1527 break;
1528 if ( u32 >= RT_ELEMENTS(pBus->devices)
1529 || u32 < i)
1530 {
1531 AssertMsgFailed(("u32=%#x i=%#x\n", u32, i));
1532 return rc;
1533 }
1534
1535 /* skip forward to the device checking that no new devices are present. */
1536 for (; i < u32; i++)
1537 {
1538 if (pBus->devices[i])
1539 {
1540 LogRel(("New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pBus->devices[i]->name,
1541 PCIDevGetVendorId(pBus->devices[i]), PCIDevGetDeviceId(pBus->devices[i])));
1542 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1543 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("New device in slot %#x, %s (vendor=%#06x device=%#06x)"),
1544 i, pBus->devices[i]->name, PCIDevGetVendorId(pBus->devices[i]), PCIDevGetDeviceId(pBus->devices[i]));
1545 }
1546 }
1547
1548 /* get the data */
1549 DevTmp.Int.s.uIrqPinState = ~0; /* Invalid value in case we have an older saved state to force a state change in pciSetIrq. */
1550 SSMR3GetMem(pSSM, DevTmp.config, sizeof(DevTmp.config));
1551 if (uVersion < 3)
1552 {
1553 int32_t i32Temp;
1554 /* Irq value not needed anymore. */
1555 rc = SSMR3GetS32(pSSM, &i32Temp);
1556 if (RT_FAILURE(rc))
1557 return rc;
1558 }
1559 else
1560 {
1561 rc = SSMR3GetS32(pSSM, &DevTmp.Int.s.uIrqPinState);
1562 if (RT_FAILURE(rc))
1563 return rc;
1564 }
1565
1566 /* check that it's still around. */
1567 pDev = pBus->devices[i];
1568 if (!pDev)
1569 {
1570 LogRel(("Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", i,
1571 PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp)));
1572 if (SSMR3HandleGetAfter(pSSM) != SSMAFTER_DEBUG_IT)
1573 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x has been removed! vendor=%#06x device=%#06x"),
1574 i, PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp));
1575 continue;
1576 }
1577
1578 /* match the vendor id assuming that this will never be changed. */
1579 if ( DevTmp.config[0] != pDev->config[0]
1580 || DevTmp.config[1] != pDev->config[1])
1581 return SSMR3SetCfgError(pSSM, RT_SRC_POS, N_("Device in slot %#x (%s) vendor id mismatch! saved=%.4Rhxs current=%.4Rhxs"),
1582 i, pDev->name, DevTmp.config, pDev->config);
1583
1584 /* commit the loaded device config. */
1585 pciR3CommonRestoreConfig(pDev, &DevTmp.config[0], false ); /** @todo fix bridge fun! */
1586
1587 pDev->Int.s.uIrqPinState = DevTmp.Int.s.uIrqPinState;
1588 }
1589
1590 return VINF_SUCCESS;
1591}
1592
1593
1594/**
1595 * Loads a saved PCI device state.
1596 *
1597 * @returns VBox status code.
1598 * @param pDevIns The device instance.
1599 * @param pSSM The handle to the saved state.
1600 * @param uVersion The data unit version number.
1601 * @param uPass The data pass.
1602 */
1603static DECLCALLBACK(int) pciR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
1604{
1605 PPCIGLOBALS pThis = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
1606 PPCIBUS pBus = &pThis->PciBus;
1607 uint32_t u32;
1608 int rc;
1609
1610 /*
1611 * Check the version.
1612 */
1613 if (uVersion > VBOX_PCI_SAVED_STATE_VERSION)
1614 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1615 Assert(uPass == SSM_PASS_FINAL); NOREF(uPass);
1616
1617 /*
1618 * Bus state data.
1619 */
1620 SSMR3GetU32(pSSM, &pThis->uConfigReg);
1621 if (uVersion > 1)
1622 SSMR3GetBool(pSSM, &pThis->fUseIoApic);
1623
1624 /* Load IRQ states. */
1625 if (uVersion > 2)
1626 {
1627 for (uint8_t i = 0; i < PCI_IRQ_PINS; i++)
1628 SSMR3GetU32(pSSM, (uint32_t *)&pThis->pci_irq_levels[i]);
1629 for (uint8_t i = 0; i < PCI_APIC_IRQ_PINS; i++)
1630 SSMR3GetU32(pSSM, (uint32_t *)&pThis->pci_apic_irq_levels[i]);
1631
1632 SSMR3GetU32(pSSM, &pThis->acpi_irq_level);
1633 SSMR3GetS32(pSSM, &pThis->acpi_irq);
1634 }
1635
1636 /* separator */
1637 rc = SSMR3GetU32(pSSM, &u32);
1638 if (RT_FAILURE(rc))
1639 return rc;
1640 if (u32 != (uint32_t)~0)
1641 AssertMsgFailedReturn(("u32=%#x\n", u32), rc);
1642
1643 /*
1644 * The devices.
1645 */
1646 return pciR3CommonLoadExec(pBus, pSSM, uVersion, uPass);
1647}
1648
1649
1650/* -=-=-=-=-=- real code -=-=-=-=-=- */
1651
1652/**
1653 * Registers the device with the specified PCI bus.
1654 *
1655 * @returns VBox status code.
1656 * @param pBus The bus to register with.
1657 * @param iDev The PCI device ordinal.
1658 * @param pPciDev The PCI device structure.
1659 * @param pszName Pointer to device name (permanent, readonly). For debugging, not unique.
1660 */
1661static int pciR3RegisterDeviceInternal(PPCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName)
1662{
1663 /*
1664 * Find device slot.
1665 */
1666 if (iDev < 0)
1667 {
1668 /*
1669 * Special check for the IDE controller which is our function 1 device
1670 * before searching.
1671 */
1672 if ( !strcmp(pszName, "piix3ide")
1673 && !pBus->devices[9])
1674 iDev = 9;
1675 /* LPC bus expected to be there by some guests, better make an additional argument to PDM
1676 device helpers, but requires significant rewrite */
1677 else if (!strcmp(pszName, "lpc")
1678 && !pBus->devices[0xf8])
1679 iDev = 0xf8;
1680 else
1681 {
1682 Assert(!(pBus->iDevSearch % 8));
1683 for (iDev = pBus->iDevSearch; iDev < (int)RT_ELEMENTS(pBus->devices); iDev += 8)
1684 if ( !pBus->devices[iDev]
1685 && !pBus->devices[iDev + 1]
1686 && !pBus->devices[iDev + 2]
1687 && !pBus->devices[iDev + 3]
1688 && !pBus->devices[iDev + 4]
1689 && !pBus->devices[iDev + 5]
1690 && !pBus->devices[iDev + 6]
1691 && !pBus->devices[iDev + 7])
1692 break;
1693 if (iDev >= (int)RT_ELEMENTS(pBus->devices))
1694 {
1695 AssertMsgFailed(("Couldn't find free spot!\n"));
1696 return VERR_PDM_TOO_PCI_MANY_DEVICES;
1697 }
1698 }
1699 pciDevClearRequestedDevfunc(pPciDev);
1700 }
1701 else
1702 {
1703 /*
1704 * An explicit request.
1705 *
1706 * If the slot is occupied we'll have to relocate the device
1707 * currently occupying it first. This can only be done if the
1708 * existing device wasn't explicitly assigned. Also we limit
1709 * ourselves to function 0 devices.
1710 *
1711 * If you start setting devices + function in the
1712 * config, do it for all pci devices!
1713 */
1714 //AssertReleaseMsg(iDev > 8 || pBus->iBus != 0, ("iDev=%d pszName=%s\n", iDev, pszName));
1715 if (pBus->devices[iDev])
1716 {
1717 int iDevRel;
1718 AssertReleaseMsg(!(iDev % 8), ("PCI Configuration Conflict! iDev=%d pszName=%s clashes with %s\n",
1719 iDev, pszName, pBus->devices[iDev]->name));
1720 if ( pciDevIsRequestedDevfunc(pBus->devices[iDev])
1721 || (pBus->devices[iDev + 1] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 1]))
1722 || (pBus->devices[iDev + 2] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 2]))
1723 || (pBus->devices[iDev + 3] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 3]))
1724 || (pBus->devices[iDev + 4] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 4]))
1725 || (pBus->devices[iDev + 5] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 5]))
1726 || (pBus->devices[iDev + 6] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 6]))
1727 || (pBus->devices[iDev + 7] && pciDevIsRequestedDevfunc(pBus->devices[iDev + 7])))
1728 {
1729 AssertReleaseMsgFailed(("Configuration error:'%s' and '%s' are both configured as device %d\n",
1730 pszName, pBus->devices[iDev]->name, iDev));
1731 return VERR_INTERNAL_ERROR;
1732 }
1733
1734 /* Find free slot for the device(s) we're moving and move them. */
1735 for (iDevRel = pBus->iDevSearch; iDevRel < (int)RT_ELEMENTS(pBus->devices); iDevRel += 8)
1736 {
1737 if ( !pBus->devices[iDevRel]
1738 && !pBus->devices[iDevRel + 1]
1739 && !pBus->devices[iDevRel + 2]
1740 && !pBus->devices[iDevRel + 3]
1741 && !pBus->devices[iDevRel + 4]
1742 && !pBus->devices[iDevRel + 5]
1743 && !pBus->devices[iDevRel + 6]
1744 && !pBus->devices[iDevRel + 7])
1745 {
1746 int i = 0;
1747 for (i = 0; i < 8; i++)
1748 {
1749 if (!pBus->devices[iDev + i])
1750 continue;
1751 Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->devices[iDev + i]->name, iDev + i, iDevRel + i));
1752 pBus->devices[iDevRel + i] = pBus->devices[iDev + i];
1753 pBus->devices[iDevRel + i]->devfn = iDevRel + i;
1754 pBus->devices[iDev + i] = NULL;
1755 }
1756 }
1757 }
1758 if (pBus->devices[iDev])
1759 {
1760 AssertMsgFailed(("Couldn't find free spot!\n"));
1761 return VERR_PDM_TOO_PCI_MANY_DEVICES;
1762 }
1763 } /* if conflict */
1764 pciDevSetRequestedDevfunc(pPciDev);
1765 }
1766
1767 Assert(!pBus->devices[iDev]);
1768 pPciDev->devfn = iDev;
1769 pPciDev->name = pszName;
1770 pPciDev->Int.s.pBusR3 = pBus;
1771 pPciDev->Int.s.pBusR0 = MMHyperR3ToR0(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
1772 pPciDev->Int.s.pBusRC = MMHyperR3ToRC(PDMDevHlpGetVM(pBus->CTX_SUFF(pDevIns)), pBus);
1773 pPciDev->Int.s.pfnConfigRead = pci_default_read_config;
1774 pPciDev->Int.s.pfnConfigWrite = pci_default_write_config;
1775 pBus->devices[iDev] = pPciDev;
1776 if (pciDevIsPci2PciBridge(pPciDev))
1777 {
1778 AssertMsg(pBus->cBridges < RT_ELEMENTS(pBus->devices), ("Number of bridges exceeds the number of possible devices on the bus\n"));
1779 AssertMsg(pPciDev->Int.s.pfnBridgeConfigRead && pPciDev->Int.s.pfnBridgeConfigWrite,
1780 ("device is a bridge but does not implement read/write functions\n"));
1781 pBus->papBridgesR3[pBus->cBridges] = pPciDev;
1782 pBus->cBridges++;
1783 }
1784
1785 Log(("PCI: Registered device %d function %d (%#x) '%s'.\n",
1786 iDev >> 3, iDev & 7, 0x80000000 | (iDev << 8), pszName));
1787
1788 return VINF_SUCCESS;
1789}
1790
1791
1792/**
1793 * Registers the device with the default PCI bus.
1794 *
1795 * @returns VBox status code.
1796 * @param pDevIns Device instance of the PCI Bus.
1797 * @param pPciDev The PCI device structure.
1798 * Any PCI enabled device must keep this in it's instance data!
1799 * Fill in the PCI data config before registration, please.
1800 * @param pszName Pointer to device name (permanent, readonly). For debugging, not unique.
1801 * @param iDev The PCI device number. Use a negative value for auto assigning one.
1802 */
1803static DECLCALLBACK(int) pciR3Register(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
1804{
1805 PPCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
1806
1807 /*
1808 * Check input.
1809 */
1810 if ( !pszName
1811 || !pPciDev
1812 || iDev >= (int)RT_ELEMENTS(pBus->devices)
1813 || (iDev >= 0 && iDev <= 8))
1814 {
1815 AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
1816 return VERR_INVALID_PARAMETER;
1817 }
1818
1819 /*
1820 * Register the device.
1821 */
1822 return pciR3RegisterDeviceInternal(pBus, iDev, pPciDev, pszName);
1823}
1824
1825
1826static DECLCALLBACK(int) pciR3CommonIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, uint32_t cbRegion,
1827 PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
1828{
1829 NOREF(pDevIns);
1830
1831 /*
1832 * Validate.
1833 */
1834 AssertMsgReturn( enmType == PCI_ADDRESS_SPACE_MEM
1835 || enmType == PCI_ADDRESS_SPACE_IO
1836 || enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH,
1837 ("Invalid enmType=%#x? Or was this a bitmask after all...\n", enmType),
1838 VERR_INVALID_PARAMETER);
1839 AssertMsgReturn((unsigned)iRegion < PCI_NUM_REGIONS,
1840 ("Invalid iRegion=%d PCI_NUM_REGIONS=%d\n", iRegion, PCI_NUM_REGIONS),
1841 VERR_INVALID_PARAMETER);
1842 int iLastSet = ASMBitLastSetU32(cbRegion);
1843 AssertMsgReturn( iLastSet != 0
1844 && RT_BIT_32(iLastSet - 1) == cbRegion,
1845 ("Invalid cbRegion=%#x iLastSet=%#x (not a power of 2 or 0)\n", cbRegion, iLastSet),
1846 VERR_INVALID_PARAMETER);
1847
1848 /*
1849 * Register the I/O region.
1850 */
1851 PPCIIOREGION pRegion = &pPciDev->Int.s.aIORegions[iRegion];
1852 pRegion->addr = ~0U;
1853 pRegion->size = cbRegion;
1854 pRegion->type = enmType;
1855 pRegion->map_func = pfnCallback;
1856
1857 /* Set type in the config space. */
1858 uint32_t u32Address = 0x10 + iRegion * 4;
1859 uint32_t u32Value = (enmType == PCI_ADDRESS_SPACE_MEM_PREFETCH ? (1 << 3) : 0)
1860 | (enmType == PCI_ADDRESS_SPACE_IO ? 1 : 0);
1861 *(uint32_t *)(pPciDev->config + u32Address) = RT_H2LE_U32(u32Value);
1862
1863 return VINF_SUCCESS;
1864}
1865
1866
1867/**
1868 * @copydoc PDMPCIBUSREG::pfnSetConfigCallbacksR3
1869 */
1870static DECLCALLBACK(void) pciR3CommonSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
1871 PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
1872{
1873 NOREF(pDevIns);
1874
1875 if (ppfnReadOld)
1876 *ppfnReadOld = pPciDev->Int.s.pfnConfigRead;
1877 pPciDev->Int.s.pfnConfigRead = pfnRead;
1878
1879 if (ppfnWriteOld)
1880 *ppfnWriteOld = pPciDev->Int.s.pfnConfigWrite;
1881 pPciDev->Int.s.pfnConfigWrite = pfnWrite;
1882}
1883
1884
1885/**
1886 * Called to perform the job of the bios.
1887 *
1888 * @returns VBox status.
1889 * @param pDevIns Device instance of the first bus.
1890 */
1891static DECLCALLBACK(int) pciR3FakePCIBIOS(PPDMDEVINS pDevIns)
1892{
1893 unsigned i;
1894 uint8_t elcr[2] = {0, 0};
1895 PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
1896 PVM pVM = PDMDevHlpGetVM(pDevIns);
1897 Assert(pVM);
1898
1899 /*
1900 * Set the start addresses.
1901 */
1902 pGlobals->pci_bios_io_addr = 0xd000;
1903 pGlobals->pci_bios_mem_addr = UINT32_C(0xf0000000);
1904 pGlobals->uBus = 0;
1905
1906 /*
1907 * Activate IRQ mappings.
1908 */
1909 for (i = 0; i < 4; i++)
1910 {
1911 uint8_t irq = pci_irqs[i];
1912 /* Set to trigger level. */
1913 elcr[irq >> 3] |= (1 << (irq & 7));
1914 /* Activate irq remapping in PIIX3. */
1915 pci_config_writeb(pGlobals, 0, pGlobals->PIIX3State.dev.devfn, 0x60 + i, irq);
1916 }
1917
1918 /* Tell to the PIC. */
1919 VBOXSTRICTRC rcStrict = IOMIOPortWrite(pVM, 0x4d0, elcr[0], sizeof(uint8_t));
1920 if (rcStrict == VINF_SUCCESS)
1921 rcStrict = IOMIOPortWrite(pVM, 0x4d1, elcr[1], sizeof(uint8_t));
1922 if (rcStrict != VINF_SUCCESS)
1923 {
1924 AssertMsgFailed(("Writing to PIC failed! rcStrict=%Rrc\n", VBOXSTRICTRC_VAL(rcStrict)));
1925 return RT_SUCCESS(rcStrict) ? VERR_INTERNAL_ERROR : VBOXSTRICTRC_VAL(rcStrict);
1926 }
1927
1928 /*
1929 * Init the devices.
1930 */
1931 for (i = 0; i < 256; i++)
1932 {
1933 uint8_t aBridgePositions[256];
1934
1935 memset(aBridgePositions, 0, sizeof(aBridgePositions));
1936 Log2(("PCI: Initializing device %d (%#x)\n",
1937 i, 0x80000000 | (i << 8)));
1938 pci_bios_init_device(pGlobals, 0, i, 0, aBridgePositions);
1939 }
1940
1941 return VINF_SUCCESS;
1942}
1943
1944/**
1945 * Info handler, device version.
1946 *
1947 * @param pDevIns Device instance which registered the info.
1948 * @param pHlp Callback functions for doing output.
1949 * @param pszArgs Argument string. Optional and specific to the handler.
1950 */
1951static DECLCALLBACK(void) pciR3IrqInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
1952{
1953 PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
1954 uint16_t router;
1955 uint8_t irq_map;
1956 int i;
1957 NOREF(pszArgs);
1958
1959 router = pGlobals->PIIX3State.dev.devfn;
1960 pHlp->pfnPrintf(pHlp, "PCI interrupt router at: %02X:%02X:%X\n",
1961 router >> 8, (router >> 3) & 0x1f, router & 0x7);
1962
1963 for (i = 0; i < 4; ++i)
1964 {
1965 irq_map = pci_config_readb(pGlobals, 0, router, 0x60 + i);
1966 if (irq_map & 0x80)
1967 pHlp->pfnPrintf(pHlp, "PIRQ%c disabled\n", 'A' + i);
1968 else
1969 pHlp->pfnPrintf(pHlp, "PIRQ%c -> IRQ%d\n", 'A' + i, irq_map & 0xf);
1970 }
1971}
1972
1973static void pciR3PrintIndent(PCDBGFINFOHLP pHlp, int iIndent)
1974{
1975 while (iIndent-- > 0)
1976 pHlp->pfnPrintf(pHlp, " ");
1977}
1978
1979static void pciR3BusInfo(PPCIBUS pBus, PCDBGFINFOHLP pHlp, int iIndent, bool fRegisters)
1980{
1981 for (uint32_t iDev = 0; iDev < RT_ELEMENTS(pBus->devices); iDev++)
1982 {
1983 PPCIDEVICE pPciDev = pBus->devices[iDev];
1984 if (pPciDev != NULL)
1985 {
1986 pciR3PrintIndent(pHlp, iIndent);
1987
1988 /*
1989 * For passthrough devices MSI/MSI-X mostly reflects the way interrupts delivered to the guest,
1990 * as host driver handles real devices interrupts.
1991 */
1992 pHlp->pfnPrintf(pHlp, "%02x:%02x:%02x %s%s: %04x-%04x%s%s",
1993 pBus->iBus, (iDev >> 3) & 0xff, iDev & 0x7,
1994 pPciDev->name,
1995 pciDevIsPassthrough(pPciDev) ? " (PASSTHROUGH)" : "",
1996 PCIDevGetWord(pPciDev, VBOX_PCI_VENDOR_ID), PCIDevGetWord(pPciDev, VBOX_PCI_DEVICE_ID),
1997 pciDevIsMsiCapable(pPciDev) ? " MSI" : "",
1998 pciDevIsMsixCapable(pPciDev) ? " MSI-X" : ""
1999 );
2000 if (PCIDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN) != 0)
2001 pHlp->pfnPrintf(pHlp, " IRQ%d", PCIDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE));
2002
2003 pHlp->pfnPrintf(pHlp, "\n");
2004
2005 uint16_t iCmd = PCIDevGetWord(pPciDev, VBOX_PCI_COMMAND);
2006 if ((iCmd & (VBOX_PCI_COMMAND_IO | VBOX_PCI_COMMAND_MEMORY)) != 0)
2007 {
2008 for (int iRegion = 0; iRegion < PCI_NUM_REGIONS; iRegion++)
2009 {
2010 PCIIORegion* pRegion = &pPciDev->Int.s.aIORegions[iRegion];
2011 uint64_t iRegionSize = pRegion->size;
2012
2013 if (iRegionSize == 0)
2014 continue;
2015
2016 uint32_t u32Addr = PCIDevGetDWord(pPciDev, PCIDevGetRegionReg(iRegion));
2017 const char * pszDesc;
2018 char szDescBuf[128];
2019
2020 bool f64Bit = !!(pRegion->type & PCI_ADDRESS_SPACE_BAR64);
2021 if (pRegion->type & PCI_ADDRESS_SPACE_IO)
2022 {
2023 pszDesc = "IO";
2024 u32Addr &= ~0x3;
2025 }
2026 else
2027 {
2028 RTStrPrintf(szDescBuf, sizeof(szDescBuf), "MMIO%s%s",
2029 f64Bit ? "64" : "32",
2030 (pRegion->type & PCI_ADDRESS_SPACE_MEM_PREFETCH) ? " PREFETCH" : "");
2031 pszDesc = szDescBuf;
2032 u32Addr &= ~0xf;
2033 }
2034
2035 pciR3PrintIndent(pHlp, iIndent + 2);
2036 pHlp->pfnPrintf(pHlp, "%s region #%d: %x..%x\n",
2037 pszDesc, iRegion, u32Addr, u32Addr+iRegionSize);
2038 if (f64Bit)
2039 iRegion++;
2040 }
2041 }
2042
2043 pciR3PrintIndent(pHlp, iIndent + 2);
2044 uint16_t iStatus = PCIDevGetWord(pPciDev, VBOX_PCI_STATUS);
2045 pHlp->pfnPrintf(pHlp, "Command: %.*Rhxs, Status: %.*Rhxs\n",
2046 sizeof(uint16_t), &iCmd, sizeof(uint16_t), &iStatus);
2047 pciR3PrintIndent(pHlp, iIndent + 2);
2048 pHlp->pfnPrintf(pHlp, "Bus master: %s\n",
2049 iCmd & VBOX_PCI_COMMAND_MASTER ? "Yes" : "No");
2050
2051 if (fRegisters)
2052 {
2053 pciR3PrintIndent(pHlp, iIndent + 2);
2054 pHlp->pfnPrintf(pHlp, "PCI registers:\n");
2055 for (int iReg = 0; iReg < 0x100; )
2056 {
2057 int iPerLine = 0x10;
2058 Assert (0x100 % iPerLine == 0);
2059 pciR3PrintIndent(pHlp, iIndent + 3);
2060
2061 while (iPerLine-- > 0)
2062 {
2063 pHlp->pfnPrintf(pHlp, "%02x ", PCIDevGetByte(pPciDev, iReg++));
2064 }
2065 pHlp->pfnPrintf(pHlp, "\n");
2066 }
2067 }
2068 }
2069 }
2070
2071 if (pBus->cBridges > 0)
2072 {
2073 pciR3PrintIndent(pHlp, iIndent);
2074 pHlp->pfnPrintf(pHlp, "Registered %d bridges, subordinate buses info follows\n", pBus->cBridges);
2075 for (uint32_t iBridge = 0; iBridge < pBus->cBridges; iBridge++)
2076 {
2077 PPCIBUS pBusSub = PDMINS_2_DATA(pBus->papBridgesR3[iBridge]->pDevIns, PPCIBUS);
2078 pciR3BusInfo(pBusSub, pHlp, iIndent + 1, fRegisters);
2079 }
2080 }
2081}
2082
2083/**
2084 * Info handler, device version.
2085 *
2086 * @param pDevIns Device instance which registered the info.
2087 * @param pHlp Callback functions for doing output.
2088 * @param pszArgs Argument string. Optional and specific to the handler.
2089 */
2090static DECLCALLBACK(void) pciR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
2091{
2092 PPCIBUS pBus = DEVINS_2_PCIBUS(pDevIns);
2093
2094 if (pszArgs == NULL || !*pszArgs || !strcmp(pszArgs, "basic"))
2095 pciR3BusInfo(pBus, pHlp, 0, false);
2096 else if (!strcmp(pszArgs, "verbose"))
2097 pciR3BusInfo(pBus, pHlp, 0, true);
2098 else
2099 pHlp->pfnPrintf(pHlp, "Invalid argument. Recognized arguments are 'basic', 'verbose'.\n");
2100}
2101
2102/**
2103 * @copydoc FNPDMDEVRELOCATE
2104 */
2105static DECLCALLBACK(void) pciR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2106{
2107 PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
2108 PPCIBUS pBus = &pGlobals->PciBus;
2109 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2110
2111 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2112 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2113
2114 /* Relocate RC pointers for the attached pci devices. */
2115 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->devices); i++)
2116 {
2117 if (pBus->devices[i])
2118 pBus->devices[i]->Int.s.pBusRC += offDelta;
2119 }
2120}
2121
2122
2123/**
2124 * @copydoc FNPDMDEVRESET
2125 */
2126static DECLCALLBACK(void) pciR3Reset(PPDMDEVINS pDevIns)
2127{
2128 pciR3FakePCIBIOS(pDevIns);
2129}
2130
2131/**
2132 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2133 */
2134static DECLCALLBACK(int) pciR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2135{
2136 Assert(iInstance == 0);
2137 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2138
2139 /*
2140 * Validate and read configuration.
2141 */
2142 if (!CFGMR3AreValuesValid(pCfg, "IOAPIC\0" "GCEnabled\0" "R0Enabled\0"))
2143 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2144
2145 /* query whether we got an IOAPIC */
2146 bool fUseIoApic;
2147 int rc = CFGMR3QueryBoolDef(pCfg, "IOAPIC", &fUseIoApic, false);
2148 if (RT_FAILURE(rc))
2149 return PDMDEV_SET_ERROR(pDevIns, rc,
2150 N_("Configuration error: Failed to query boolean value \"IOAPIC\""));
2151
2152 /* check if RC code is enabled. */
2153 bool fGCEnabled;
2154 rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2155 if (RT_FAILURE(rc))
2156 return PDMDEV_SET_ERROR(pDevIns, rc,
2157 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2158
2159 /* check if R0 code is enabled. */
2160 bool fR0Enabled;
2161 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2162 if (RT_FAILURE(rc))
2163 return PDMDEV_SET_ERROR(pDevIns, rc,
2164 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2165 Log(("PCI: fUseIoApic=%RTbool fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fUseIoApic, fGCEnabled, fR0Enabled));
2166
2167 /*
2168 * Init data and register the PCI bus.
2169 */
2170 PPCIGLOBALS pGlobals = PDMINS_2_DATA(pDevIns, PPCIGLOBALS);
2171 pGlobals->pci_bios_io_addr = 0xc000;
2172 pGlobals->pci_bios_mem_addr = 0xf0000000;
2173 memset((void *)&pGlobals->pci_irq_levels, 0, sizeof(pGlobals->pci_irq_levels));
2174 pGlobals->fUseIoApic = fUseIoApic;
2175 memset((void *)&pGlobals->pci_apic_irq_levels, 0, sizeof(pGlobals->pci_apic_irq_levels));
2176
2177 pGlobals->pDevInsR3 = pDevIns;
2178 pGlobals->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2179 pGlobals->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2180
2181 pGlobals->PciBus.pDevInsR3 = pDevIns;
2182 pGlobals->PciBus.pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2183 pGlobals->PciBus.pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2184 pGlobals->PciBus.papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE)
2185 * RT_ELEMENTS(pGlobals->PciBus.devices));
2186
2187 PDMPCIBUSREG PciBusReg;
2188 PPCIBUS pBus = &pGlobals->PciBus;
2189 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2190 PciBusReg.pfnRegisterR3 = pciR3Register;
2191 PciBusReg.pfnRegisterMsiR3 = NULL;
2192 PciBusReg.pfnIORegionRegisterR3 = pciR3CommonIORegionRegister;
2193 PciBusReg.pfnSetConfigCallbacksR3 = pciR3CommonSetConfigCallbacks;
2194 PciBusReg.pfnSetIrqR3 = pciSetIrq;
2195 PciBusReg.pfnFakePCIBIOSR3 = pciR3FakePCIBIOS;
2196 PciBusReg.pszSetIrqRC = fGCEnabled ? "pciSetIrq" : NULL;
2197 PciBusReg.pszSetIrqR0 = fR0Enabled ? "pciSetIrq" : NULL;
2198 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2199 if (RT_FAILURE(rc))
2200 return PDMDEV_SET_ERROR(pDevIns, rc,
2201 N_("Failed to register ourselves as a PCI Bus"));
2202 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2203 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2204 N_("PCI helper version mismatch; got %#x expected %#x"),
2205 pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION);
2206
2207 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2208 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2209
2210 /* Disable default device locking. */
2211 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
2212 AssertRCReturn(rc, rc);
2213
2214 /*
2215 * Fill in PCI configs and add them to the bus.
2216 */
2217 /* i440FX */
2218 PCIDevSetVendorId( &pBus->PciDev, 0x8086); /* Intel */
2219 PCIDevSetDeviceId( &pBus->PciDev, 0x1237);
2220 PCIDevSetRevisionId(&pBus->PciDev, 0x02);
2221 PCIDevSetClassSub( &pBus->PciDev, 0x00); /* host2pci */
2222 PCIDevSetClassBase( &pBus->PciDev, 0x06); /* PCI_bridge */
2223 PCIDevSetHeaderType(&pBus->PciDev, 0x00);
2224
2225 pBus->PciDev.pDevIns = pDevIns;
2226 pciDevSetRequestedDevfunc(&pBus->PciDev);
2227 pciR3RegisterDeviceInternal(pBus, 0, &pBus->PciDev, "i440FX");
2228
2229 /* PIIX3 */
2230 PCIDevSetVendorId( &pGlobals->PIIX3State.dev, 0x8086); /* Intel */
2231 PCIDevSetDeviceId( &pGlobals->PIIX3State.dev, 0x7000); /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
2232 PCIDevSetClassSub( &pGlobals->PIIX3State.dev, 0x01); /* PCI_ISA */
2233 PCIDevSetClassBase( &pGlobals->PIIX3State.dev, 0x06); /* PCI_bridge */
2234 PCIDevSetHeaderType(&pGlobals->PIIX3State.dev, 0x80); /* PCI_multifunction, generic */
2235
2236 pGlobals->PIIX3State.dev.pDevIns = pDevIns;
2237 pciDevSetRequestedDevfunc(&pGlobals->PIIX3State.dev);
2238 pciR3RegisterDeviceInternal(pBus, 8, &pGlobals->PIIX3State.dev, "PIIX3");
2239 pciR3Piix3Reset(&pGlobals->PIIX3State);
2240
2241 pBus->iDevSearch = 16;
2242
2243 /*
2244 * Register I/O ports and save state.
2245 */
2246 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cf8, 1, NULL, pciIOPortAddressWrite, pciIOPortAddressRead, NULL, NULL, "i440FX (PCI)");
2247 if (RT_FAILURE(rc))
2248 return rc;
2249 rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cfc, 4, NULL, pciIOPortDataWrite, pciIOPortDataRead, NULL, NULL, "i440FX (PCI)");
2250 if (RT_FAILURE(rc))
2251 return rc;
2252 if (fGCEnabled)
2253 {
2254 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cf8, 1, NIL_RTGCPTR, "pciIOPortAddressWrite", "pciIOPortAddressRead", NULL, NULL, "i440FX (PCI)");
2255 if (RT_FAILURE(rc))
2256 return rc;
2257 rc = PDMDevHlpIOPortRegisterRC(pDevIns, 0x0cfc, 4, NIL_RTGCPTR, "pciIOPortDataWrite", "pciIOPortDataRead", NULL, NULL, "i440FX (PCI)");
2258 if (RT_FAILURE(rc))
2259 return rc;
2260 }
2261 if (fR0Enabled)
2262 {
2263 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cf8, 1, NIL_RTR0PTR, "pciIOPortAddressWrite", "pciIOPortAddressRead", NULL, NULL, "i440FX (PCI)");
2264 if (RT_FAILURE(rc))
2265 return rc;
2266 rc = PDMDevHlpIOPortRegisterR0(pDevIns, 0x0cfc, 4, NIL_RTR0PTR, "pciIOPortDataWrite", "pciIOPortDataRead", NULL, NULL, "i440FX (PCI)");
2267 if (RT_FAILURE(rc))
2268 return rc;
2269 }
2270
2271 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_PCI_SAVED_STATE_VERSION, sizeof(*pBus) + 16*128, "pgm",
2272 NULL, NULL, NULL,
2273 NULL, pciR3SaveExec, NULL,
2274 NULL, pciR3LoadExec, NULL);
2275 if (RT_FAILURE(rc))
2276 return rc;
2277
2278 PDMDevHlpDBGFInfoRegister(pDevIns, "pci",
2279 "Display PCI bus status. Recognizes 'basic' or 'verbose' as arguments, defaults to 'basic'.",
2280 pciR3Info);
2281 PDMDevHlpDBGFInfoRegister(pDevIns, "pciirq", "Display PCI IRQ routing state. (no arguments)", pciR3IrqInfo);
2282
2283 return VINF_SUCCESS;
2284}
2285
2286
2287/**
2288 * The device registration structure.
2289 */
2290const PDMDEVREG g_DevicePCI =
2291{
2292 /* u32Version */
2293 PDM_DEVREG_VERSION,
2294 /* szName */
2295 "pci",
2296 /* szRCMod */
2297 "VBoxDDGC.gc",
2298 /* szR0Mod */
2299 "VBoxDDR0.r0",
2300 /* pszDescription */
2301 "i440FX PCI bridge and PIIX3 ISA bridge.",
2302 /* fFlags */
2303 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2304 /* fClass */
2305 PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
2306 /* cMaxInstances */
2307 1,
2308 /* cbInstance */
2309 sizeof(PCIGLOBALS),
2310 /* pfnConstruct */
2311 pciR3Construct,
2312 /* pfnDestruct */
2313 NULL,
2314 /* pfnRelocate */
2315 pciR3Relocate,
2316 /* pfnIOCtl */
2317 NULL,
2318 /* pfnPowerOn */
2319 NULL,
2320 /* pfnReset */
2321 pciR3Reset,
2322 /* pfnSuspend */
2323 NULL,
2324 /* pfnResume */
2325 NULL,
2326 /* pfnAttach */
2327 NULL,
2328 /* pfnDetach */
2329 NULL,
2330 /* pfnQueryInterface */
2331 NULL,
2332 /* pfnInitComplete */
2333 NULL,
2334 /* pfnPowerOff */
2335 NULL,
2336 /* pfnSoftReset */
2337 NULL,
2338 /* u32VersionEnd */
2339 PDM_DEVREG_VERSION
2340
2341};
2342#endif /* IN_RING3 */
2343
2344
2345/**
2346 * Set the IRQ for a PCI device on a secondary bus.
2347 *
2348 * @param pDevIns Device instance of the PCI Bus.
2349 * @param pPciDev The PCI device structure.
2350 * @param iIrq IRQ number to set.
2351 * @param iLevel IRQ level.
2352 * @param uTagSrc The IRQ tag and source ID (for tracing).
2353 */
2354PDMBOTHCBDECL(void) pcibridgeSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)
2355{
2356 /*
2357 * The PCI-to-PCI bridge specification defines how the interrupt pins
2358 * are routed from the secondary to the primary bus (see chapter 9).
2359 * iIrq gives the interrupt pin the pci device asserted.
2360 * We change iIrq here according to the spec and call the SetIrq function
2361 * of our parent passing the device which asserted the interrupt instead of the device of the bridge.
2362 */
2363 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
2364 PPCIDEVICE pPciDevBus = pPciDev;
2365 int iIrqPinBridge = iIrq;
2366 uint8_t uDevFnBridge = 0;
2367
2368 /* Walk the chain until we reach the host bus. */
2369 do
2370 {
2371 uDevFnBridge = pBus->PciDev.devfn;
2372 iIrqPinBridge = ((pPciDevBus->devfn >> 3) + iIrqPinBridge) & 3;
2373
2374 /* Get the parent. */
2375 pBus = pBus->PciDev.Int.s.CTX_SUFF(pBus);
2376 pPciDevBus = &pBus->PciDev;
2377 } while (pBus->iBus != 0);
2378
2379 AssertMsg(pBus->iBus == 0, ("This is not the host pci bus iBus=%d\n", pBus->iBus));
2380 pciSetIrqInternal(PCIBUS_2_PCIGLOBALS(pBus), uDevFnBridge, pPciDev, iIrqPinBridge, iLevel, uTagSrc);
2381}
2382
2383#ifdef IN_RING3
2384
2385/**
2386 * @callback_method_impl{FNPCIBRIDGECONFIGWRITE}
2387 */
2388static void pcibridgeR3ConfigWrite(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, uint32_t u32Value, unsigned cb)
2389{
2390 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
2391
2392 LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u u32Value=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, u32Value, cb));
2393
2394 /* If the current bus is not the target bus search for the bus which contains the device. */
2395 if (iBus != pBus->PciDev.config[VBOX_PCI_SECONDARY_BUS])
2396 {
2397 PPCIDEVICE pBridgeDevice = pciR3FindBridge(pBus, iBus);
2398 if (pBridgeDevice)
2399 {
2400 AssertPtr(pBridgeDevice->Int.s.pfnBridgeConfigWrite);
2401 pBridgeDevice->Int.s.pfnBridgeConfigWrite(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, u32Value, cb);
2402 }
2403 }
2404 else
2405 {
2406 /* This is the target bus, pass the write to the device. */
2407 PPCIDEVICE pPciDev = pBus->devices[iDevice];
2408 if (pPciDev)
2409 {
2410 Log(("%s: %s: addr=%02x val=%08x len=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
2411 pPciDev->Int.s.pfnConfigWrite(pPciDev, u32Address, u32Value, cb);
2412 }
2413 }
2414}
2415
2416/**
2417 * @callback_method_impl{FNPCIBRIDGECONFIGREAD}
2418 */
2419static uint32_t pcibridgeR3ConfigRead(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, uint32_t u32Address, unsigned cb)
2420{
2421 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
2422 uint32_t u32Value = 0xffffffff; /* Return value in case there is no device. */
2423
2424 LogFlowFunc((": pDevIns=%p iBus=%d iDevice=%d u32Address=%u cb=%d\n", pDevIns, iBus, iDevice, u32Address, cb));
2425
2426 /* If the current bus is not the target bus search for the bus which contains the device. */
2427 if (iBus != pBus->PciDev.config[VBOX_PCI_SECONDARY_BUS])
2428 {
2429 PPCIDEVICE pBridgeDevice = pciR3FindBridge(pBus, iBus);
2430 if (pBridgeDevice)
2431 {
2432 AssertPtr( pBridgeDevice->Int.s.pfnBridgeConfigRead);
2433 u32Value = pBridgeDevice->Int.s.pfnBridgeConfigRead(pBridgeDevice->pDevIns, iBus, iDevice, u32Address, cb);
2434 }
2435 }
2436 else
2437 {
2438 /* This is the target bus, pass the read to the device. */
2439 PPCIDEVICE pPciDev = pBus->devices[iDevice];
2440 if (pPciDev)
2441 {
2442 u32Value = pPciDev->Int.s.pfnConfigRead(pPciDev, u32Address, cb);
2443 Log(("%s: %s: u32Address=%02x u32Value=%08x cb=%d\n", __FUNCTION__, pPciDev->name, u32Address, u32Value, cb));
2444 }
2445 }
2446
2447 return u32Value;
2448}
2449
2450
2451/**
2452 * @copydoc FNSSMDEVSAVEEXEC
2453 */
2454static DECLCALLBACK(int) pcibridgeR3SaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)
2455{
2456 PPCIBUS pThis = PDMINS_2_DATA(pDevIns, PPCIBUS);
2457 return pciR3CommonSaveExec(pThis, pSSM);
2458}
2459
2460
2461/**
2462 * @copydoc FNSSMDEVLOADEXEC
2463 */
2464static DECLCALLBACK(int) pcibridgeR3LoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)
2465{
2466 PPCIBUS pThis = PDMINS_2_DATA(pDevIns, PPCIBUS);
2467 if (uVersion > VBOX_PCI_SAVED_STATE_VERSION)
2468 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
2469 return pciR3CommonLoadExec(pThis, pSSM, uVersion, uPass);
2470}
2471
2472
2473/**
2474 * Registers the device with the default PCI bus.
2475 *
2476 * @returns VBox status code.
2477 * @param pDevIns Device instance of the PCI Bus.
2478 * @param pPciDev The PCI device structure.
2479 * Any PCI enabled device must keep this in it's instance data!
2480 * Fill in the PCI data config before registration, please.
2481 * @param pszName Pointer to device name (permanent, readonly). For debugging, not unique.
2482 * @param iDev The PCI device number. Use a negative value for auto assigning one.
2483 */
2484static DECLCALLBACK(int) pcibridgeR3RegisterDevice(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
2485{
2486 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
2487
2488 /*
2489 * Check input.
2490 */
2491 if ( !pszName
2492 || !pPciDev
2493 || iDev >= (int)RT_ELEMENTS(pBus->devices))
2494 {
2495 AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
2496 return VERR_INVALID_PARAMETER;
2497 }
2498
2499 /*
2500 * Register the device.
2501 */
2502 return pciR3RegisterDeviceInternal(pBus, iDev, pPciDev, pszName);
2503}
2504
2505
2506/**
2507 * @copydoc FNPDMDEVRESET
2508 */
2509static DECLCALLBACK(void) pcibridgeR3Reset(PPDMDEVINS pDevIns)
2510{
2511 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
2512
2513 /* Reset config space to default values. */
2514 pBus->PciDev.config[VBOX_PCI_PRIMARY_BUS] = 0;
2515 pBus->PciDev.config[VBOX_PCI_SECONDARY_BUS] = 0;
2516 pBus->PciDev.config[VBOX_PCI_SUBORDINATE_BUS] = 0;
2517}
2518
2519
2520/**
2521 * @copydoc FNPDMDEVRELOCATE
2522 */
2523static DECLCALLBACK(void) pcibridgeR3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
2524{
2525 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
2526 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2527
2528 /* Relocate RC pointers for the attached pci devices. */
2529 for (uint32_t i = 0; i < RT_ELEMENTS(pBus->devices); i++)
2530 {
2531 if (pBus->devices[i])
2532 pBus->devices[i]->Int.s.pBusRC += offDelta;
2533 }
2534}
2535
2536
2537/**
2538 * @interface_method_impl{PDMDEVREG,pfnConstruct}
2539 */
2540static DECLCALLBACK(int) pcibridgeR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
2541{
2542 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
2543
2544 /*
2545 * Validate and read configuration.
2546 */
2547 if (!CFGMR3AreValuesValid(pCfg, "GCEnabled\0" "R0Enabled\0"))
2548 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
2549
2550 /* check if RC code is enabled. */
2551 bool fGCEnabled;
2552 int rc = CFGMR3QueryBoolDef(pCfg, "GCEnabled", &fGCEnabled, true);
2553 if (RT_FAILURE(rc))
2554 return PDMDEV_SET_ERROR(pDevIns, rc,
2555 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
2556
2557 /* check if R0 code is enabled. */
2558 bool fR0Enabled;
2559 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
2560 if (RT_FAILURE(rc))
2561 return PDMDEV_SET_ERROR(pDevIns, rc,
2562 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
2563 Log(("PCI: fGCEnabled=%RTbool fR0Enabled=%RTbool\n", fGCEnabled, fR0Enabled));
2564
2565 /*
2566 * Init data and register the PCI bus.
2567 */
2568 PPCIBUS pBus = PDMINS_2_DATA(pDevIns, PPCIBUS);
2569 pBus->pDevInsR3 = pDevIns;
2570 pBus->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
2571 pBus->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
2572 pBus->papBridgesR3 = (PPCIDEVICE *)PDMDevHlpMMHeapAllocZ(pDevIns, sizeof(PPCIDEVICE) * RT_ELEMENTS(pBus->devices));
2573
2574 PDMPCIBUSREG PciBusReg;
2575 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
2576 PciBusReg.pfnRegisterR3 = pcibridgeR3RegisterDevice;
2577 PciBusReg.pfnRegisterMsiR3 = NULL;
2578 PciBusReg.pfnIORegionRegisterR3 = pciR3CommonIORegionRegister;
2579 PciBusReg.pfnSetConfigCallbacksR3 = pciR3CommonSetConfigCallbacks;
2580 PciBusReg.pfnSetIrqR3 = pcibridgeSetIrq;
2581 PciBusReg.pfnFakePCIBIOSR3 = NULL; /* Only needed for the first bus. */
2582 PciBusReg.pszSetIrqRC = fGCEnabled ? "pcibridgeSetIrq" : NULL;
2583 PciBusReg.pszSetIrqR0 = fR0Enabled ? "pcibridgeSetIrq" : NULL;
2584 rc = PDMDevHlpPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
2585 if (RT_FAILURE(rc))
2586 return PDMDEV_SET_ERROR(pDevIns, rc,
2587 N_("Failed to register ourselves as a PCI Bus"));
2588 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
2589 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
2590 N_("PCI helper version mismatch; got %#x expected %#x"),
2591 pBus->pPciHlpR3->u32Version, PDM_PCIHLPR3_VERSION);
2592
2593 pBus->pPciHlpRC = pBus->pPciHlpR3->pfnGetRCHelpers(pDevIns);
2594 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
2595
2596 /*
2597 * Fill in PCI configs and add them to the bus.
2598 */
2599 PCIDevSetVendorId( &pBus->PciDev, 0x8086); /* Intel */
2600 PCIDevSetDeviceId( &pBus->PciDev, 0x2448); /* 82801 Mobile PCI bridge. */
2601 PCIDevSetRevisionId(&pBus->PciDev, 0xf2);
2602 PCIDevSetClassSub( &pBus->PciDev, 0x04); /* pci2pci */
2603 PCIDevSetClassBase( &pBus->PciDev, 0x06); /* PCI_bridge */
2604 PCIDevSetClassProg( &pBus->PciDev, 0x01); /* Supports subtractive decoding. */
2605 PCIDevSetHeaderType(&pBus->PciDev, 0x01); /* Single function device which adheres to the PCI-to-PCI bridge spec. */
2606 PCIDevSetCommand( &pBus->PciDev, 0x00);
2607 PCIDevSetStatus( &pBus->PciDev, 0x20); /* 66MHz Capable. */
2608 PCIDevSetInterruptLine(&pBus->PciDev, 0x00); /* This device does not assert interrupts. */
2609
2610 /*
2611 * This device does not generate interrupts. Interrupt delivery from
2612 * devices attached to the bus is unaffected.
2613 */
2614 PCIDevSetInterruptPin (&pBus->PciDev, 0x00);
2615
2616 pBus->PciDev.pDevIns = pDevIns;
2617
2618 /* Bridge-specific data */
2619 pciDevSetPci2PciBridge(&pBus->PciDev);
2620 pBus->PciDev.Int.s.pfnBridgeConfigRead = pcibridgeR3ConfigRead;
2621 pBus->PciDev.Int.s.pfnBridgeConfigWrite = pcibridgeR3ConfigWrite;
2622
2623 /*
2624 * Register this PCI bridge. The called function will take care on which bus we will get registered.
2625 */
2626 rc = PDMDevHlpPCIRegister (pDevIns, &pBus->PciDev);
2627 if (RT_FAILURE(rc))
2628 return rc;
2629
2630 pBus->iDevSearch = 0;
2631 /*
2632 * The iBus property doesn't really represent the bus number
2633 * because the guest and the BIOS can choose different bus numbers
2634 * for them.
2635 * The bus number is mainly for the setIrq function to indicate
2636 * when the host bus is reached which will have iBus = 0.
2637 * That's why the + 1.
2638 */
2639 pBus->iBus = iInstance + 1;
2640
2641 /*
2642 * Register SSM handlers. We use the same saved state version as for the host bridge
2643 * to make changes easier.
2644 */
2645 rc = PDMDevHlpSSMRegisterEx(pDevIns, VBOX_PCI_SAVED_STATE_VERSION, sizeof(*pBus) + 16*128, "pgm",
2646 NULL, NULL, NULL,
2647 NULL, pcibridgeR3SaveExec, NULL,
2648 NULL, pcibridgeR3LoadExec, NULL);
2649 if (RT_FAILURE(rc))
2650 return rc;
2651
2652 return VINF_SUCCESS;
2653}
2654
2655
2656/**
2657 * The device registration structure
2658 * for the PCI-to-PCI bridge.
2659 */
2660const PDMDEVREG g_DevicePCIBridge =
2661{
2662 /* u32Version */
2663 PDM_DEVREG_VERSION,
2664 /* szName */
2665 "pcibridge",
2666 /* szRCMod */
2667 "VBoxDDGC.gc",
2668 /* szR0Mod */
2669 "VBoxDDR0.r0",
2670 /* pszDescription */
2671 "82801 Mobile PCI to PCI bridge",
2672 /* fFlags */
2673 PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
2674 /* fClass */
2675 PDM_DEVREG_CLASS_BUS_PCI,
2676 /* cMaxInstances */
2677 ~0U,
2678 /* cbInstance */
2679 sizeof(PCIBUS),
2680 /* pfnConstruct */
2681 pcibridgeR3Construct,
2682 /* pfnDestruct */
2683 NULL,
2684 /* pfnRelocate */
2685 pcibridgeR3Relocate,
2686 /* pfnIOCtl */
2687 NULL,
2688 /* pfnPowerOn */
2689 NULL,
2690 /* pfnReset */
2691 pcibridgeR3Reset,
2692 /* pfnSuspend */
2693 NULL,
2694 /* pfnResume */
2695 NULL,
2696 /* pfnAttach */
2697 NULL,
2698 /* pfnDetach */
2699 NULL,
2700 /* pfnQueryInterface */
2701 NULL,
2702 /* pfnInitComplete */
2703 NULL,
2704 /* pfnPowerOff */
2705 NULL,
2706 /* pfnSoftReset */
2707 NULL,
2708 /* u32VersionEnd */
2709 PDM_DEVREG_VERSION
2710};
2711
2712#endif /* IN_RING3 */
2713#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
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