VirtualBox

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

Last change on this file since 13192 was 13192, checked in by vboxsync, 16 years ago

PCI: Forgotten variable initialization

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