VirtualBox

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

Last change on this file since 7640 was 7635, checked in by vboxsync, 17 years ago

The new MMIO2 code.
WARNING! This changes the pci mapping protocol for MMIO2 so it's working the same way as I/O ports and normal MMIO memory. External users of the interface will have to update their mapping routines.

  • Property svn:eol-style set to native
File size: 54.6 KB
Line 
1/* $Id: $ */
2/** @file
3 * PCI BUS Device.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
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 declare at the right point - include "PCIInternal.h". */
48#define PCI_INCLUDE_PRIVATE
49#include <VBox/pci.h>
50#include <VBox/pdmdev.h>
51#include <iprt/assert.h>
52#include <iprt/string.h>
53
54#include "Builtins.h"
55
56
57/*******************************************************************************
58* Defined Constants And Macros *
59*******************************************************************************/
60/** @def PCI_LOCK
61 * Acquires the PDM lock. This is a NOP if locking is disabled. */
62/** @def PCI_UNLOCK
63 * Releases the PDM lock. This is a NOP if locking is disabled. */
64#ifdef VBOX_WITH_PDM_LOCK
65# define PCI_LOCK(pDevIns, rc) \
66 do { \
67 int rc2 = PDMINS2DATA(pDevIns, PCIBus *)->CTXALLSUFF(pPciHlp)->pfnLock((pDevIns), rc); \
68 if (rc2 != VINF_SUCCESS) \
69 return rc2; \
70 } while (0)
71# define PCI_UNLOCK(pDevIns) \
72 PDMINS2DATA(pDevIns, PCIBus *)->CTXALLSUFF(pPciHlp)->pfnUnlock(pDevIns)
73#else /* !VBOX_WITH_PDM_LOCK */
74# define PCI_LOCK(pThis, rc) do { } while (0)
75# define PCI_UNLOCK(pThis) do { } while (0)
76#endif /* !VBOX_WITH_PDM_LOCK */
77
78
79/*******************************************************************************
80* Structures and Typedefs *
81*******************************************************************************/
82/**
83 * PIIX3 ISA Bridge state.
84 */
85typedef struct PIIX3State
86{
87 /** The PCI device of the bridge. */
88 PCIDEVICE dev;
89} PIIX3State, PIIX3, *PPIIX3;
90
91
92/** Maximum number of PCI devices.
93 * Defined like this to make interrupt handling simple. */
94#define PCI_DEVICES_MAX 64
95/** Number of uint32_t entries needed make a bitmask of the interrupts. */
96#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
97
98/**
99 * PCI Globals.
100 *
101 * @remark
102 * These are currently put in the PCIBus structure since we've
103 * only got one PCI bus in the current VM configurations. This
104 * makes life somewhat simpler in GC.
105 */
106typedef struct PCIGLOBALS
107{
108 /** Irq levels for the four PCI Irqs. */
109 uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];
110 /** The base address for PCI assigned MMIO addresses. */
111 RTGCPHYS32 pci_mem_base;
112 /** The next I/O port address which the PCI BIOS will use. */
113 uint32_t pci_bios_io_addr;
114 /** The next MMIO address which the PCI BIOS will use. */
115 uint32_t pci_bios_mem_addr;
116 /** I/O APIC usage flag */
117 bool fUseIoApic;
118 /** I/O APIC irq levels */
119 uint32_t pci_apic_irq_levels[8][PCI_IRQ_WORDS];
120 /** ACPI IRQ level */
121 uint32_t acpi_irq_level;
122 /** ACPI PIC IRQ */
123 int acpi_irq;
124} PCIGLOBALS;
125/** Pointer to per VM data. */
126typedef PCIGLOBALS *PPCIGLOBALS;
127
128
129/**
130 * PCI Bus instance.
131 */
132typedef struct PCIBus
133{
134 /** IRQ index */
135 uint32_t uIrqIndex;
136 /** Bus number. */
137 int32_t iBus;
138 /** Start device number. */
139 int32_t iDevSearch;
140 /** Config register. */
141 uint32_t uConfigReg;
142 /** Array of PCI devices. */
143 R3PTRTYPE(PPCIDEVICE) devices[256];
144
145 /** HC pointer to the device instance. */
146 R3R0PTRTYPE(PPDMDEVINS) pDevInsHC;
147 /** Pointer to the PCI R3 helpers. */
148 PCPDMPCIHLPR3 pPciHlpR3;
149
150 /** GC pointer to the device instance. */
151 PPDMDEVINSGC pDevInsGC;
152 /** Pointer to the PCI GC helpers. */
153 PCPDMPCIHLPGC pPciHlpGC;
154 /** Pointer to the PCI R0 helpers. */
155 PCPDMPCIHLPR0 pPciHlpR0;
156
157 /** The PCI device for the PCI bridge. */
158 PCIDEVICE PciDev;
159 /** ISA bridge state. */
160 PIIX3 PIIX3State;
161 /** The global data.
162 * Since we've only got one bus at present, we put it here to keep things simple. */
163 PCIGLOBALS Globals;
164} PCIBUS;
165/** Pointer to a PCIBUS instance. */
166typedef PCIBUS *PPCIBUS;
167typedef PCIBUS PCIBus;
168
169
170/** Converts a bus instance pointer to a device instance pointer. */
171#define PCIBUS2DEVINS(pPciBus) ((pPciBus)->CTXSUFF(pDevIns))
172/** Converts a device instance pointer to a PCIGLOBALS pointer. */
173#define DEVINS2PCIGLOBALS(pDevIns) ((PPCIGLOBALS)(&PDMINS2DATA(pDevIns, PPCIBUS)->Globals))
174/** Converts a bus instance pointer to a PCIGLOBALS pointer. */
175#define PCIBUS2PCIGLOBALS(pPciBus) ((PPCIGLOBALS)(&pPciBus->Globals))
176
177
178#ifndef VBOX_DEVICE_STRUCT_TESTCASE
179/*******************************************************************************
180* Internal Functions *
181*******************************************************************************/
182__BEGIN_DECLS
183
184PDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel);
185
186__END_DECLS
187
188
189#define DEBUG_PCI
190
191#define PCI_VENDOR_ID 0x00 /* 16 bits */
192#define PCI_DEVICE_ID 0x02 /* 16 bits */
193#define PCI_COMMAND 0x04 /* 16 bits */
194#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
195#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
196#define PCI_CLASS_DEVICE 0x0a /* Device class */
197#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */
198#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */
199#define PCI_MIN_GNT 0x3e /* 8 bits */
200#define PCI_MAX_LAT 0x3f /* 8 bits */
201
202#ifdef IN_RING3
203
204static void pci_addr_writel(PCIBus *s, uint32_t addr, uint32_t val)
205{
206 s->uConfigReg = val;
207}
208
209static uint32_t pci_addr_readl(PCIBus *s, uint32_t addr)
210{
211 return s->uConfigReg;
212}
213
214static void pci_update_mappings(PCIDevice *d)
215{
216 PPCIBUS pBus = d->Int.s.pBus;
217 PCIIORegion *r;
218 int cmd, i;
219 uint32_t last_addr, new_addr, config_ofs;
220
221 cmd = RT_LE2H_U16(*(uint16_t *)(d->config + PCI_COMMAND));
222 for(i = 0; i < PCI_NUM_REGIONS; i++) {
223 r = &d->Int.s.aIORegions[i];
224 if (i == PCI_ROM_SLOT) {
225 config_ofs = 0x30;
226 } else {
227 config_ofs = 0x10 + i * 4;
228 }
229 if (r->size != 0) {
230 if (r->type & PCI_ADDRESS_SPACE_IO) {
231 if (cmd & PCI_COMMAND_IO) {
232 new_addr = RT_LE2H_U32(*(uint32_t *)(d->config +
233 config_ofs));
234 new_addr = new_addr & ~(r->size - 1);
235 last_addr = new_addr + r->size - 1;
236 /* NOTE: we have only 64K ioports on PC */
237 if (last_addr <= new_addr || new_addr == 0 ||
238 last_addr >= 0x10000) {
239 new_addr = ~0U;
240 }
241 } else {
242 new_addr = ~0U;
243 }
244 } else {
245 if (cmd & PCI_COMMAND_MEMORY) {
246 new_addr = RT_LE2H_U32(*(uint32_t *)(d->config +
247 config_ofs));
248 /* the ROM slot has a specific enable bit */
249 if (i == PCI_ROM_SLOT && !(new_addr & 1))
250 goto no_mem_map;
251 new_addr = new_addr & ~(r->size - 1);
252 last_addr = new_addr + r->size - 1;
253 /* NOTE: we do not support wrapping */
254 /* XXX: as we cannot support really dynamic
255 mappings, we handle specific values as invalid
256 mappings. */
257 if (last_addr <= new_addr || new_addr == 0 ||
258 last_addr == ~0U) {
259 new_addr = ~0U;
260 }
261 } else {
262 no_mem_map:
263 new_addr = ~0U;
264 }
265 }
266 /* now do the real mapping */
267 if (new_addr != r->addr) {
268 if (r->addr != ~0U) {
269 if (r->type & PCI_ADDRESS_SPACE_IO) {
270 int devclass;
271 /* NOTE: specific hack for IDE in PC case:
272 only one byte must be mapped. */
273 devclass = d->config[0x0a] | (d->config[0x0b] << 8);
274 if (devclass == 0x0101 && r->size == 4) {
275 int rc = d->pDevIns->pDevHlp->pfnIOPortDeregister(d->pDevIns, r->addr + 2, 1);
276 AssertRC(rc);
277 } else {
278 int rc = d->pDevIns->pDevHlp->pfnIOPortDeregister(d->pDevIns, r->addr, r->size);
279 AssertRC(rc);
280 }
281 } else {
282 RTGCPHYS GCPhysBase = r->addr + PCIBUS2PCIGLOBALS(pBus)->pci_mem_base;
283 int rc;
284 if (pBus->pPciHlpR3->pfnIsMMIO2Base(pBus->pDevInsHC, d->pDevIns, GCPhysBase))
285 {
286 /* unmap it. */
287 int rc = r->map_func(d, i, NIL_RTGCPHYS, r->size, (PCIADDRESSSPACE)(r->type));
288 AssertRC(rc);
289 rc = PDMDevHlpMMIO2Unmap(d->pDevIns, i, GCPhysBase);
290 }
291 else
292 rc = d->pDevIns->pDevHlp->pfnMMIODeregister(d->pDevIns, GCPhysBase, r->size);
293 AssertMsgRC(rc, ("rc=%Rrc d=%s i=%d GCPhysBase=%RGp size=%#x\n", rc, d->name, i, GCPhysBase, r->size));
294 }
295 }
296 r->addr = new_addr;
297 if (r->addr != ~0U) {
298 int rc = r->map_func(d, i,
299 r->addr + (r->type & PCI_ADDRESS_SPACE_IO ? 0 : PCIBUS2PCIGLOBALS(pBus)->pci_mem_base),
300 r->size, (PCIADDRESSSPACE)(r->type));
301 AssertRC(rc);
302 }
303 }
304 }
305 }
306}
307
308
309static DECLCALLBACK(uint32_t) pci_default_read_config(PCIDevice *d, uint32_t address, unsigned len)
310{
311 uint32_t val;
312 switch(len) {
313 case 1:
314 val = d->config[address];
315 break;
316 case 2:
317 val = RT_LE2H_U16(*(uint16_t *)(d->config + address));
318 break;
319 default:
320 case 4:
321 val = RT_LE2H_U32(*(uint32_t *)(d->config + address));
322 break;
323 }
324 return val;
325}
326
327static DECLCALLBACK(void) pci_default_write_config(PCIDevice *d, uint32_t address, uint32_t val, unsigned len)
328{
329 int can_write;
330 unsigned i;
331 uint32_t end, addr;
332
333 if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
334 (address >= 0x30 && address < 0x34))) {
335 PCIIORegion *r;
336 int reg;
337
338 if ( address >= 0x30 ) {
339 reg = PCI_ROM_SLOT;
340 }else{
341 reg = (address - 0x10) >> 2;
342 }
343 r = &d->Int.s.aIORegions[reg];
344 if (r->size == 0)
345 goto default_config;
346 /* compute the stored value */
347 if (reg == PCI_ROM_SLOT) {
348 /* keep ROM enable bit */
349 val &= (~(r->size - 1)) | 1;
350 } else {
351 val &= ~(r->size - 1);
352 val |= r->type;
353 }
354 *(uint32_t *)(d->config + address) = RT_H2LE_U32(val);
355 pci_update_mappings(d);
356 return;
357 }
358 default_config:
359 /* not efficient, but simple */
360 addr = address;
361 for(i = 0; i < len; i++) {
362 /* default read/write accesses */
363 switch(d->config[0x0e]) {
364 case 0x00:
365 case 0x80:
366 switch(addr) {
367 case 0x00:
368 case 0x01:
369 case 0x02:
370 case 0x03:
371 case 0x08:
372 case 0x09:
373 case 0x0a:
374 case 0x0b:
375 case 0x0e:
376 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: /* base */
377 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
378 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
379 case 0x30: case 0x31: case 0x32: case 0x33: /* rom */
380 case 0x3d:
381 can_write = 0;
382 break;
383 default:
384 can_write = 1;
385 break;
386 }
387 break;
388 default:
389 case 0x01:
390 switch(addr) {
391 case 0x00:
392 case 0x01:
393 case 0x02:
394 case 0x03:
395 case 0x08:
396 case 0x09:
397 case 0x0a:
398 case 0x0b:
399 case 0x0e:
400 case 0x38: case 0x39: case 0x3a: case 0x3b: /* rom */
401 case 0x3d:
402 can_write = 0;
403 break;
404 default:
405 can_write = 1;
406 break;
407 }
408 break;
409 }
410#ifdef VBOX
411 /* status register: only clear bits by writing a '1' at the corresponding bit */
412 if (addr == 0x06)
413 {
414 d->config[addr] &= ~val;
415 d->config[addr] |= 0x08; /* interrupt status */
416 }
417 else if (addr == 0x07)
418 {
419 d->config[addr] &= ~val;
420 }
421 else
422#endif
423 if (can_write) {
424 d->config[addr] = val;
425 }
426 addr++;
427 val >>= 8;
428 }
429
430 end = address + len;
431 if (end > PCI_COMMAND && address < (PCI_COMMAND + 2)) {
432 /* if the command register is modified, we must modify the mappings */
433 pci_update_mappings(d);
434 }
435}
436
437static void pci_data_write(PCIBus *s, uint32_t addr, uint32_t val, int len)
438{
439 PCIDevice *pci_dev;
440 int config_addr, iBus;
441
442 Log(("pci_data_write: addr=%08x val=%08x len=%d\n", s->uConfigReg, val, len));
443
444 if (!(s->uConfigReg & (1 << 31))) {
445 return;
446 }
447 if ((s->uConfigReg & 0x3) != 0) {
448 return;
449 }
450 iBus = (s->uConfigReg >> 16) & 0xff;
451 if (iBus != 0)
452 return;
453 pci_dev = s->devices[(s->uConfigReg >> 8) & 0xff];
454 if (!pci_dev)
455 return;
456 config_addr = (s->uConfigReg & 0xfc) | (addr & 3);
457 Log(("pci_config_write: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, val, len));
458 pci_dev->Int.s.pfnConfigWrite(pci_dev, config_addr, val, len);
459}
460
461static uint32_t pci_data_read(PCIBus *s, uint32_t addr, int len)
462{
463 PCIDevice *pci_dev;
464 int config_addr, iBus;
465 uint32_t val;
466
467 if (!(s->uConfigReg & (1 << 31)))
468 goto fail;
469 if ((s->uConfigReg & 0x3) != 0)
470 goto fail;
471 iBus = (s->uConfigReg >> 16) & 0xff;
472 if (iBus != 0)
473 goto fail;
474 pci_dev = s->devices[(s->uConfigReg >> 8) & 0xff];
475 if (!pci_dev) {
476 fail:
477 switch(len) {
478 case 1:
479 val = 0xff;
480 break;
481 case 2:
482 val = 0xffff;
483 break;
484 default:
485 case 4:
486 val = 0xffffffff;
487 break;
488 }
489 goto the_end;
490 }
491 config_addr = (s->uConfigReg & 0xfc) | (addr & 3);
492 val = pci_dev->Int.s.pfnConfigRead(pci_dev, config_addr, len);
493 Log(("pci_config_read: %s: addr=%02x val=%08x len=%d\n", pci_dev->name, config_addr, val, len));
494 the_end:
495 return val;
496}
497
498#endif /* IN_RING3 */
499
500
501/* return the global irq number corresponding to a given device irq
502 pin. We could also use the bus number to have a more precise
503 mapping. */
504static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
505{
506 int slot_addend;
507 slot_addend = (pci_dev->devfn >> 3) - 1;
508 return (irq_num + slot_addend) & 3;
509}
510
511static inline int pci_slot_get_apic_pirq(PCIDevice *pci_dev, int irq_num)
512{
513 return (irq_num + (pci_dev->devfn >> 3)) & 7;
514}
515
516static inline int get_pci_irq_apic_level(PPCIGLOBALS pGlobals, int irq_num)
517{
518 int apic_level;
519 apic_level = ((pGlobals->pci_apic_irq_levels[irq_num][0] |
520 pGlobals->pci_apic_irq_levels[irq_num][1]) != 0);
521 return apic_level;
522}
523
524static void apic_set_irq(PPCIBUS pBus, PCIDevice *pci_dev, int irq_num1, int level, int acpi_irq)
525{
526 if (acpi_irq == -1) {
527 int shift, apic_irq, apic_level;
528 uint32_t *p;
529 PPCIGLOBALS pGlobals = PCIBUS2PCIGLOBALS(pBus);
530 int uIrqIndex = pci_dev->Int.s.iIrq;
531 int irq_num = pci_slot_get_apic_pirq(pci_dev, irq_num1);
532
533 p = &pGlobals->pci_apic_irq_levels[irq_num][uIrqIndex >> 5];
534 shift = (uIrqIndex & 0x1f);
535 *p = (*p & ~(1 << shift)) | ((level & PDM_IRQ_LEVEL_HIGH) << shift);
536 apic_irq = irq_num + 0x10;
537 apic_level = get_pci_irq_apic_level(pGlobals, irq_num);
538 Log3(("apic_set_irq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d\n",
539 HCSTRING(pci_dev->name), irq_num1, level, apic_irq, apic_level, irq_num));
540 pBus->CTXALLSUFF(pPciHlp)->pfnIoApicSetIrq(CTXSUFF(pBus->pDevIns), apic_irq, apic_level);
541
542 if ((level & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP) {
543 *p = (*p & ~(1 << shift));
544 apic_level = get_pci_irq_apic_level(pGlobals, irq_num);
545 Log3(("apic_set_irq: %s: irq_num1=%d level=%d apic_irq=%d apic_level=%d irq_num1=%d (flop)\n",
546 HCSTRING(pci_dev->name), irq_num1, level, apic_irq, apic_level, irq_num));
547 pBus->CTXALLSUFF(pPciHlp)->pfnIoApicSetIrq(CTXSUFF(pBus->pDevIns), apic_irq, apic_level);
548 }
549 } else {
550 Log3(("apic_set_irq: %s: irq_num1=%d level=%d acpi_irq=%d\n",
551 HCSTRING(pci_dev->name), irq_num1, level, acpi_irq));
552 pBus->CTXALLSUFF(pPciHlp)->pfnIoApicSetIrq(CTXSUFF(pBus->pDevIns), acpi_irq, level);
553 }
554}
555
556static inline int get_pci_irq_level(PPCIGLOBALS pGlobals, int irq_num)
557{
558 int pic_level;
559#if (PCI_IRQ_WORDS == 2)
560 pic_level = ((pGlobals->pci_irq_levels[irq_num][0] |
561 pGlobals->pci_irq_levels[irq_num][1]) != 0);
562#else
563 {
564 int i;
565 pic_level = 0;
566 for(i = 0; i < PCI_IRQ_WORDS; i++) {
567 if (pGlobals->pci_irq_levels[irq_num][i]) {
568 pic_level = 1;
569 break;
570 }
571 }
572 }
573#endif
574 return pic_level;
575}
576
577/**
578 * Set the IRQ for a PCI device.
579 *
580 * @param pDevIns Device instance of the PCI Bus.
581 * @param pPciDev The PCI device structure.
582 * @param iIrq IRQ number to set.
583 * @param iLevel IRQ level.
584 */
585PDMBOTHCBDECL(void) pciSetIrq(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iIrq, int iLevel)
586{
587 PPCIBUS pBus = PDMINS2DATA(pDevIns, PPCIBUS);
588 PPCIGLOBALS pGlobals = PCIBUS2PCIGLOBALS(pBus);
589 uint8_t *pbCfg = pBus->PIIX3State.dev.config;
590 const bool fIsAcpiDevice = pPciDev->config[2] == 0x13 && pPciDev->config[3] == 0x71;
591 const bool fIsApicEnabled = pGlobals->fUseIoApic && pbCfg[0xde] == 0xbe && pbCfg[0xad] == 0xef;
592 int pic_irq, pic_level;
593 uint32_t *p;
594
595 /* apic only */
596 if (fIsApicEnabled)
597 {
598 if (fIsAcpiDevice)
599 /*
600 * ACPI needs special treatment since SCI is hardwired and
601 * should not be affected by PCI IRQ routing tables at the
602 * same time SCI IRQ is shared in PCI sense hence this
603 * kludge (i.e. we fetch the hardwired value from ACPIs
604 * PCI device configuration space).
605 */
606 apic_set_irq(pBus, pPciDev, -1, iLevel, pPciDev->config[0x3c]);
607 else
608 apic_set_irq(pBus, pPciDev, iIrq, iLevel, -1);
609 return;
610 }
611
612 if (fIsAcpiDevice)
613 {
614 /* As per above treat ACPI in a special way */
615 pic_irq = pPciDev->config[0x3c];
616 pGlobals->acpi_irq = pic_irq;
617 pGlobals->acpi_irq_level = iLevel & PDM_IRQ_LEVEL_HIGH;
618 }
619 else
620 {
621 int shift, irq_num, uIrqIndex;
622 irq_num = pci_slot_get_pirq(pPciDev, iIrq);
623 uIrqIndex = pPciDev->Int.s.iIrq;
624 p = &pGlobals->pci_irq_levels[irq_num][uIrqIndex >> 5];
625 shift = (uIrqIndex & 0x1f);
626 *p = (*p & ~(1 << shift)) | ((iLevel & PDM_IRQ_LEVEL_HIGH) << shift);
627
628 /* now we change the pic irq level according to the piix irq mappings */
629 pic_irq = pbCfg[0x60 + irq_num];
630 if (pic_irq >= 16)
631 {
632 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
633 *p = (*p & ~(1 << shift));
634 return;
635 }
636 }
637
638 /* the pic level is the logical OR of all the PCI irqs mapped to it */
639 pic_level = 0;
640 if (pic_irq == pbCfg[0x60])
641 pic_level |= get_pci_irq_level(pGlobals, 0);
642 if (pic_irq == pbCfg[0x61])
643 pic_level |= get_pci_irq_level(pGlobals, 1);
644 if (pic_irq == pbCfg[0x62])
645 pic_level |= get_pci_irq_level(pGlobals, 2);
646 if (pic_irq == pbCfg[0x63])
647 pic_level |= get_pci_irq_level(pGlobals, 3);
648 if (pic_irq == pGlobals->acpi_irq)
649 pic_level |= pGlobals->acpi_irq_level;
650
651 Log3(("piix3_set_irq: %s: iLevel=%d iIrq=%d pic_irq=%d pic_level=%d\n",
652 HCSTRING(pPciDev->name), iLevel, iIrq, pic_irq, pic_level));
653 pBus->CTXALLSUFF(pPciHlp)->pfnIsaSetIrq(CTXSUFF(pBus->pDevIns), pic_irq, pic_level);
654
655 /** @todo optimize pci irq flip-flop some rainy day. */
656 if ((iLevel & PDM_IRQ_LEVEL_FLIP_FLOP) == PDM_IRQ_LEVEL_FLIP_FLOP)
657 pciSetIrq(pDevIns, pPciDev, iIrq, PDM_IRQ_LEVEL_LOW);
658}
659
660#ifdef IN_RING3
661
662static void piix3_reset(PIIX3State *d)
663{
664 uint8_t *pci_conf = d->dev.config;
665
666 pci_conf[0x04] = 0x07; /* master, memory and I/O */
667 pci_conf[0x05] = 0x00;
668 pci_conf[0x06] = 0x00;
669 pci_conf[0x07] = 0x02; /* PCI_status_devsel_medium */
670 pci_conf[0x4c] = 0x4d;
671 pci_conf[0x4e] = 0x03;
672 pci_conf[0x4f] = 0x00;
673 pci_conf[0x60] = 0x80;
674 pci_conf[0x69] = 0x02;
675 pci_conf[0x70] = 0x80;
676 pci_conf[0x76] = 0x0c;
677 pci_conf[0x77] = 0x0c;
678 pci_conf[0x78] = 0x02;
679 pci_conf[0x79] = 0x00;
680 pci_conf[0x80] = 0x00;
681 pci_conf[0x82] = 0x02; /* Get rid of the Linux guest "Enabling Passive Release" PCI quirk warning. */
682 pci_conf[0xa0] = 0x08;
683 pci_conf[0xa0] = 0x08;
684 pci_conf[0xa2] = 0x00;
685 pci_conf[0xa3] = 0x00;
686 pci_conf[0xa4] = 0x00;
687 pci_conf[0xa5] = 0x00;
688 pci_conf[0xa6] = 0x00;
689 pci_conf[0xa7] = 0x00;
690 pci_conf[0xa8] = 0x0f;
691 pci_conf[0xaa] = 0x00;
692 pci_conf[0xab] = 0x00;
693 pci_conf[0xac] = 0x00;
694 pci_conf[0xae] = 0x00;
695}
696
697static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
698{
699 PCIBus *s = d->Int.s.pBus;
700 s->uConfigReg = 0x80000000 | (s->iBus << 16) |
701 (d->devfn << 8) | addr;
702 pci_data_write(s, 0, val, 4);
703}
704
705static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
706{
707 PCIBus *s = d->Int.s.pBus;
708 s->uConfigReg = 0x80000000 | (s->iBus << 16) |
709 (d->devfn << 8) | (addr & ~3);
710 pci_data_write(s, addr & 3, val, 2);
711}
712
713static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
714{
715 PCIBus *s = d->Int.s.pBus;
716 s->uConfigReg = 0x80000000 | (s->iBus << 16) |
717 (d->devfn << 8) | (addr & ~3);
718 pci_data_write(s, addr & 3, val, 1);
719}
720
721static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
722{
723 PCIBus *s = d->Int.s.pBus;
724 s->uConfigReg = 0x80000000 | (s->iBus << 16) |
725 (d->devfn << 8) | (addr & ~3);
726 return pci_data_read(s, addr & 3, 2);
727}
728
729static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
730{
731 PCIBus *s = d->Int.s.pBus;
732 s->uConfigReg = 0x80000000 | (s->iBus << 16) |
733 (d->devfn << 8) | (addr & ~3);
734 return pci_data_read(s, addr & 3, 1);
735}
736
737/* host irqs corresponding to PCI irqs A-D */
738static const uint8_t pci_irqs[4] = { 11, 9, 11, 9 }; /* bird: added const */
739
740static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
741{
742 PCIIORegion *r;
743 uint16_t cmd;
744 uint32_t ofs;
745
746 if ( region_num == PCI_ROM_SLOT ) {
747 ofs = 0x30;
748 }else{
749 ofs = 0x10 + region_num * 4;
750 }
751
752 pci_config_writel(d, ofs, addr);
753 r = &d->Int.s.aIORegions[region_num];
754
755 /* enable memory mappings */
756 cmd = pci_config_readw(d, PCI_COMMAND);
757 if ( region_num == PCI_ROM_SLOT )
758 cmd |= 2;
759 else if (r->type & PCI_ADDRESS_SPACE_IO)
760 cmd |= 1;
761 else
762 cmd |= 2;
763 pci_config_writew(d, PCI_COMMAND, cmd);
764}
765
766static void pci_bios_init_device(PCIDevice *d)
767{
768 int devclass;
769 PCIIORegion *r;
770 uint32_t *paddr;
771 int i, pin, pic_irq, vendor_id, device_id;
772
773 devclass = pci_config_readw(d, PCI_CLASS_DEVICE);
774 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
775 device_id = pci_config_readw(d, PCI_DEVICE_ID);
776 switch(devclass)
777 {
778 case 0x0101:
779 if (vendor_id == 0x8086 &&
780 (device_id == 0x7010 || device_id == 0x7111)) {
781 /* PIIX3 or PIIX4 IDE */
782 pci_config_writew(d, 0x40, 0x8000); /* enable IDE0 */
783 pci_config_writew(d, 0x42, 0x8000); /* enable IDE1 */
784 goto default_map;
785 } else {
786 /* IDE: we map it as in ISA mode */
787 pci_set_io_region_addr(d, 0, 0x1f0);
788 pci_set_io_region_addr(d, 1, 0x3f4);
789 pci_set_io_region_addr(d, 2, 0x170);
790 pci_set_io_region_addr(d, 3, 0x374);
791 }
792 break;
793 case 0x0300:
794 if (vendor_id != 0x80ee)
795 goto default_map;
796 /* VGA: map frame buffer to default Bochs VBE address */
797 pci_set_io_region_addr(d, 0, 0xE0000000);
798 break;
799 case 0x0800:
800 /* PIC */
801 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
802 device_id = pci_config_readw(d, PCI_DEVICE_ID);
803 if (vendor_id == 0x1014) {
804 /* IBM */
805 if (device_id == 0x0046 || device_id == 0xFFFF) {
806 /* MPIC & MPIC2 */
807 pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
808 }
809 }
810 break;
811 case 0xff00:
812 if (vendor_id == 0x0106b &&
813 (device_id == 0x0017 || device_id == 0x0022)) {
814 /* macio bridge */
815 pci_set_io_region_addr(d, 0, 0x80800000);
816 }
817 break;
818 default:
819 default_map:
820 /* default memory mappings */
821 for(i = 0; i < PCI_NUM_REGIONS; i++) {
822 r = &d->Int.s.aIORegions[i];
823
824 if (r->size) {
825 if (r->type & PCI_ADDRESS_SPACE_IO)
826 paddr = &PCIBUS2PCIGLOBALS(d->Int.s.pBus)->pci_bios_io_addr;
827 else
828 paddr = &PCIBUS2PCIGLOBALS(d->Int.s.pBus)->pci_bios_mem_addr;
829 *paddr = (*paddr + r->size - 1) & ~(r->size - 1);
830 pci_set_io_region_addr(d, i, *paddr);
831 *paddr += r->size;
832 }
833 }
834 break;
835 }
836
837 /* map the interrupt */
838 pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
839 if (pin != 0) {
840 pin = pci_slot_get_pirq(d, pin - 1);
841 pic_irq = pci_irqs[pin];
842 pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
843 }
844}
845
846/* -=-=-=-=-=- wrappers -=-=-=-=-=- */
847
848/**
849 * Port I/O Handler for PCI address OUT operations.
850 *
851 * @returns VBox status code.
852 *
853 * @param pDevIns The device instance.
854 * @param pvUser User argument - ignored.
855 * @param uPort Port number used for the IN operation.
856 * @param u32 The value to output.
857 * @param cb The value size in bytes.
858 */
859static DECLCALLBACK(int) pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
860{
861 Log(("pciIOPortAddressWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
862 NOREF(pvUser);
863 if (cb == 4)
864 {
865 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_WRITE);
866 pci_addr_writel(PDMINS2DATA(pDevIns, PCIBus *), Port, u32);
867 PCI_UNLOCK(pDevIns);
868 }
869 /* else: 440FX does "pass through to the bus" for other writes, what ever that means.
870 * Linux probes for cmd640 using byte writes/reads during ide init. We'll just ignore it. */
871 return VINF_SUCCESS;
872}
873
874/**
875 * Port I/O Handler for PCI address IN operations.
876 *
877 * @returns VBox status code.
878 *
879 * @param pDevIns The device instance.
880 * @param pvUser User argument - ignored.
881 * @param uPort Port number used for the IN operation.
882 * @param pu32 Where to store the result.
883 * @param cb Number of bytes read.
884 */
885static DECLCALLBACK(int) pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
886{
887 NOREF(pvUser);
888 if (cb == 4)
889 {
890 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_READ);
891 *pu32 = pci_addr_readl(PDMINS2DATA(pDevIns, PCIBus *), Port);
892 PCI_UNLOCK(pDevIns);
893 Log(("pciIOPortAddressRead: Port=%#x cb=%d -> %#x\n", Port, cb, *pu32));
894 return VINF_SUCCESS;
895 }
896 /* else: 440FX does "pass through to the bus" for other writes, what ever that means.
897 * Linux probes for cmd640 using byte writes/reads during ide init. We'll just ignore it. */
898 Log(("pciIOPortAddressRead: Port=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", Port, cb));
899 return VERR_IOM_IOPORT_UNUSED;
900}
901
902
903/**
904 * Port I/O Handler for PCI data OUT operations.
905 *
906 * @returns VBox status code.
907 *
908 * @param pDevIns The device instance.
909 * @param pvUser User argument - ignored.
910 * @param uPort Port number used for the IN operation.
911 * @param u32 The value to output.
912 * @param cb The value size in bytes.
913 */
914static DECLCALLBACK(int) pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
915{
916 Log(("pciIOPortDataWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
917 NOREF(pvUser);
918 if (!(Port % cb))
919 {
920 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_WRITE);
921 pci_data_write(PDMINS2DATA(pDevIns, PCIBus *), Port, u32, cb);
922 PCI_UNLOCK(pDevIns);
923 }
924 else
925 AssertMsgFailed(("Write to port %#x u32=%#x cb=%d\n", Port, u32, cb));
926 return VINF_SUCCESS;
927}
928
929
930/**
931 * Port I/O Handler for PCI data IN operations.
932 *
933 * @returns VBox status code.
934 *
935 * @param pDevIns The device instance.
936 * @param pvUser User argument - ignored.
937 * @param uPort Port number used for the IN operation.
938 * @param pu32 Where to store the result.
939 * @param cb Number of bytes read.
940 */
941static DECLCALLBACK(int) pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
942{
943 NOREF(pvUser);
944 if (!(Port % cb))
945 {
946 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_READ);
947 *pu32 = pci_data_read(PDMINS2DATA(pDevIns, PCIBus *), Port, cb);
948 PCI_UNLOCK(pDevIns);
949 Log(("pciIOPortDataRead: Port=%#x cb=%#x -> %#x\n", Port, cb, *pu32));
950 return VINF_SUCCESS;
951 }
952 AssertMsgFailed(("Read from port %#x cb=%d\n", Port, cb));
953 return VERR_IOM_IOPORT_UNUSED;
954}
955
956
957/**
958 * Saves a state of the PCI device.
959 *
960 * @returns VBox status code.
961 * @param pDevIns Device instance of the PCI Bus.
962 * @param pPciDev Pointer to PCI device.
963 * @param pSSMHandle The handle to save the state to.
964 */
965static DECLCALLBACK(int) pciGenericSaveExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSMHandle)
966{
967 return SSMR3PutMem(pSSMHandle, &pPciDev->config[0], sizeof(pPciDev->config));
968}
969
970
971/**
972 * Loads a saved PCI device state.
973 *
974 * @returns VBox status code.
975 * @param pDevIns Device instance of the PCI Bus.
976 * @param pPciDev Pointer to PCI device.
977 * @param pSSMHandle The handle to the saved state.
978 */
979static DECLCALLBACK(int) pciGenericLoadExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSMHandle)
980{
981 return SSMR3GetMem(pSSMHandle, &pPciDev->config[0], sizeof(pPciDev->config));
982}
983
984
985/**
986 * Saves a state of the PCI device.
987 *
988 * @returns VBox status code.
989 * @param pDevIns The device instance.
990 * @param pPciDev Pointer to PCI device.
991 * @param pSSMHandle The handle to save the state to.
992 */
993static DECLCALLBACK(int) pciSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
994{
995 uint32_t i;
996 PPCIBUS pData = PDMINS2DATA(pDevIns, PPCIBUS);
997 PPCIGLOBALS pGlobals = PCIBUS2PCIGLOBALS(pData);
998
999 /*
1000 * Bus state data.
1001 */
1002 SSMR3PutU32(pSSMHandle, pData->uConfigReg);
1003 SSMR3PutBool(pSSMHandle, pGlobals->fUseIoApic);
1004 SSMR3PutU32(pSSMHandle, ~0); /* separator */
1005
1006 /*
1007 * Iterate all the devices.
1008 */
1009 for (i = 0; i < ELEMENTS(pData->devices); i++)
1010 {
1011 PPCIDEVICE pDev = pData->devices[i];
1012 if (pDev)
1013 {
1014 int rc;
1015 SSMR3PutU32(pSSMHandle, i);
1016 SSMR3PutMem(pSSMHandle, pDev->config, sizeof(pDev->config));
1017 rc = SSMR3PutS32(pSSMHandle, pDev->Int.s.iIrq);
1018 if (VBOX_FAILURE(rc))
1019 return rc;
1020 }
1021 }
1022 return SSMR3PutU32(pSSMHandle, ~0); /* terminator */
1023}
1024
1025/**
1026 * Loads a saved PCI device state.
1027 *
1028 * @returns VBox status code.
1029 * @param pDevIns The device instance.
1030 * @param pSSMHandle The handle to the saved state.
1031 * @param u32Version The data unit version number.
1032 */
1033static DECLCALLBACK(int) pciLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
1034{
1035 PPCIBUS pData = PDMINS2DATA(pDevIns, PPCIBUS);
1036 PPCIGLOBALS pGlobals = PCIBUS2PCIGLOBALS(pData);
1037 uint32_t u32;
1038 uint32_t i;
1039 int rc;
1040
1041 /*
1042 * Check the version.
1043 */
1044 if (u32Version > 2)
1045 {
1046 AssertFailed();
1047 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1048 }
1049
1050 /*
1051 * Bus state data.
1052 */
1053 SSMR3GetU32(pSSMHandle, &pData->uConfigReg);
1054 if (u32Version > 1)
1055 SSMR3GetBool(pSSMHandle, &pGlobals->fUseIoApic);
1056
1057 /* separator */
1058 rc = SSMR3GetU32(pSSMHandle, &u32);
1059 if (VBOX_FAILURE(rc))
1060 return rc;
1061 if (u32 != (uint32_t)~0)
1062 AssertMsgFailedReturn(("u32=%#x\n", u32), rc);
1063
1064 /*
1065 * Iterate all the devices.
1066 */
1067 for (i = 0;; i++)
1068 {
1069 PCIDEVICE DevTmp;
1070 PPCIDEVICE pDev;
1071
1072 /* index / terminator */
1073 rc = SSMR3GetU32(pSSMHandle, &u32);
1074 if (VBOX_FAILURE(rc))
1075 return rc;
1076 if (u32 == (uint32_t)~0)
1077 break;
1078 if ( u32 >= ELEMENTS(pData->devices)
1079 || u32 < i)
1080 {
1081 AssertMsgFailed(("u32=%#x i=%#x\n", u32, i));
1082 return rc;
1083 }
1084
1085 /* skip forward to the device checking that no new devices are present. */
1086 for (; i < u32; i++)
1087 {
1088 if (pData->devices[i])
1089 {
1090 LogRel(("New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pData->devices[i]->name,
1091 PCIDevGetVendorId(pData->devices[i]), PCIDevGetDeviceId(pData->devices[i])));
1092 if (SSMR3HandleGetAfter(pSSMHandle) != SSMAFTER_DEBUG_IT)
1093 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
1094 }
1095 }
1096
1097 /* get the data */
1098 SSMR3GetMem(pSSMHandle, DevTmp.config, sizeof(DevTmp.config));
1099 rc = SSMR3GetS32(pSSMHandle, &DevTmp.Int.s.iIrq);
1100 if (VBOX_FAILURE(rc))
1101 return rc;
1102
1103 /* check that it's still around. */
1104 pDev = pData->devices[i];
1105 if (!pDev)
1106 {
1107 LogRel(("Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", i,
1108 PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp)));
1109 if (SSMR3HandleGetAfter(pSSMHandle) != SSMAFTER_DEBUG_IT)
1110 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
1111 continue;
1112 }
1113
1114 /* match the vendor id assuming that this will never be changed. */
1115 if ( DevTmp.config[0] != pDev->config[0]
1116 || DevTmp.config[1] != pDev->config[1])
1117 {
1118 LogRel(("Device in slot %#x (%s) vendor id mismatch! saved=%.4Vhxs current=%.4Vhxs\n",
1119 i, pDev->name, DevTmp.config, pDev->config));
1120 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
1121 }
1122
1123 /* commit the loaded device config. */
1124 memcpy(pDev->config, DevTmp.config, sizeof(pDev->config));
1125 if (DevTmp.Int.s.iIrq >= PCI_DEVICES_MAX)
1126 {
1127 LogRel(("Device %s: Too many devices %d (max=%d)\n", pDev->name, DevTmp.Int.s.iIrq, PCI_DEVICES_MAX));
1128 AssertFailedReturn(VERR_TOO_MUCH_DATA);
1129 }
1130
1131 pDev->Int.s.iIrq = DevTmp.Int.s.iIrq;
1132 }
1133 return VINF_SUCCESS;
1134}
1135
1136
1137/* -=-=-=-=-=- real code -=-=-=-=-=- */
1138
1139
1140/**
1141 * Registers the device with the default PCI bus.
1142 *
1143 * @returns VBox status code.
1144 * @param pBus The bus to register with.
1145 * @param iDev The PCI device ordinal.
1146 * @param pPciDev The PCI device structure.
1147 * @param pszName Pointer to device name (permanent, readonly). For debugging, not unique.
1148 */
1149static void pciRegisterInternal(PPCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName)
1150{
1151 Assert(!pBus->devices[iDev]);
1152 pPciDev->devfn = iDev;
1153 pPciDev->name = pszName;
1154 pPciDev->Int.s.pBus = pBus;
1155 pPciDev->Int.s.pfnConfigRead = pci_default_read_config;
1156 pPciDev->Int.s.pfnConfigWrite = pci_default_write_config;
1157 AssertMsg(pBus->uIrqIndex < PCI_DEVICES_MAX,
1158 ("Device %s: Too many devices %d (max=%d)\n",
1159 pszName, pBus->uIrqIndex, PCI_DEVICES_MAX));
1160 pPciDev->Int.s.iIrq = pBus->uIrqIndex++;
1161 pBus->devices[iDev] = pPciDev;
1162 Log(("PCI: Registered device %d function %d (%#x) '%s'.\n",
1163 iDev >> 3, iDev & 7, 0x80000000 | (iDev << 8), pszName));
1164}
1165
1166
1167/**
1168 * Registers the device with the default PCI bus.
1169 *
1170 * @returns VBox status code.
1171 * @param pDevIns Device instance of the PCI Bus.
1172 * @param pPciDev The PCI device structure.
1173 * Any PCI enabled device must keep this in it's instance data!
1174 * Fill in the PCI data config before registration, please.
1175 * @param pszName Pointer to device name (permanent, readonly). For debugging, not unique.
1176 * @param iDev The PCI device number. Use a negative value for auto assigning one.
1177 */
1178static DECLCALLBACK(int) pciRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
1179{
1180 PPCIBUS pBus = PDMINS2DATA(pDevIns, PPCIBUS);
1181
1182 /*
1183 * Check input.
1184 */
1185 if ( !pszName
1186 || !pPciDev
1187 || iDev >= (int)ELEMENTS(pBus->devices)
1188 || (iDev >= 0 && iDev <= 8))
1189 {
1190 AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
1191 return VERR_INVALID_PARAMETER;
1192 }
1193
1194 /*
1195 * Find device slot.
1196 */
1197 if (iDev < 0)
1198 {
1199 /*
1200 * Special check for the IDE controller which is our function 1 device
1201 * before searching.
1202 */
1203 if ( !strcmp(pszName, "piix3ide")
1204 && !pBus->devices[9])
1205 iDev = 9;
1206 else
1207 {
1208 Assert(!(pBus->iDevSearch % 8));
1209 for (iDev = pBus->iDevSearch; iDev < (int)ELEMENTS(pBus->devices); iDev += 8)
1210 if ( !pBus->devices[iDev]
1211 && !pBus->devices[iDev + 1]
1212 && !pBus->devices[iDev + 2]
1213 && !pBus->devices[iDev + 3]
1214 && !pBus->devices[iDev + 4]
1215 && !pBus->devices[iDev + 5]
1216 && !pBus->devices[iDev + 6]
1217 && !pBus->devices[iDev + 7])
1218 break;
1219 if (iDev >= (int)ELEMENTS(pBus->devices))
1220 {
1221 AssertMsgFailed(("Couldn't find free spot!\n"));
1222 return VERR_PDM_TOO_PCI_MANY_DEVICES;
1223 }
1224 }
1225 pPciDev->Int.s.fRequestedDevFn = false;
1226 }
1227 else
1228 {
1229 /*
1230 * An explicit request.
1231 *
1232 * If the slot is occupied we'll have to relocate the device
1233 * currently occupying it first. This can only be done if the
1234 * existing device wasn't explicitly assigned. Also we limit
1235 * ourselves to function 0 devices.
1236 *
1237 * If you start setting devices + function in the
1238 * config, do it for all pci devices!
1239 */
1240 AssertReleaseMsg(iDev > 8, ("iDev=%d pszName=%s\n", iDev, pszName));
1241 if (pBus->devices[iDev])
1242 {
1243 int iDevRel;
1244 AssertReleaseMsg(!(iDev % 8), ("PCI Configuration Conflict! iDev=%d pszName=%s clashes with %s\n",
1245 iDev, pszName, pBus->devices[iDev]->name));
1246 if ( pBus->devices[iDev]->Int.s.fRequestedDevFn
1247 || (pBus->devices[iDev + 1] && pBus->devices[iDev + 1]->Int.s.fRequestedDevFn)
1248 || (pBus->devices[iDev + 2] && pBus->devices[iDev + 2]->Int.s.fRequestedDevFn)
1249 || (pBus->devices[iDev + 3] && pBus->devices[iDev + 3]->Int.s.fRequestedDevFn)
1250 || (pBus->devices[iDev + 4] && pBus->devices[iDev + 4]->Int.s.fRequestedDevFn)
1251 || (pBus->devices[iDev + 5] && pBus->devices[iDev + 5]->Int.s.fRequestedDevFn)
1252 || (pBus->devices[iDev + 6] && pBus->devices[iDev + 6]->Int.s.fRequestedDevFn)
1253 || (pBus->devices[iDev + 7] && pBus->devices[iDev + 7]->Int.s.fRequestedDevFn))
1254 {
1255 AssertReleaseMsgFailed(("Configuration error:'%s' and '%s' are both configured as device %d\n",
1256 pszName, pBus->devices[iDev]->name, iDev));
1257 return VERR_INTERNAL_ERROR;
1258 }
1259
1260 /* Find free slot for the device(s) we're moving and move them. */
1261 for (iDevRel = pBus->iDevSearch; iDevRel < (int)ELEMENTS(pBus->devices); iDevRel += 8)
1262 {
1263 if ( !pBus->devices[iDevRel]
1264 && !pBus->devices[iDevRel + 1]
1265 && !pBus->devices[iDevRel + 2]
1266 && !pBus->devices[iDevRel + 3]
1267 && !pBus->devices[iDevRel + 4]
1268 && !pBus->devices[iDevRel + 5]
1269 && !pBus->devices[iDevRel + 6]
1270 && !pBus->devices[iDevRel + 7])
1271 {
1272 int i = 0;
1273 for (i = 0; i < 8; i++)
1274 {
1275 if (!pBus->devices[iDev + i])
1276 continue;
1277 Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->devices[iDev + i]->name, iDev + i, iDevRel + i));
1278 pBus->devices[iDevRel + i] = pBus->devices[iDev + i];
1279 pBus->devices[iDevRel + i]->devfn = i;
1280 pBus->devices[iDev + i] = NULL;
1281 }
1282 }
1283 }
1284 if (pBus->devices[iDev])
1285 {
1286 AssertMsgFailed(("Couldn't find free spot!\n"));
1287 return VERR_PDM_TOO_PCI_MANY_DEVICES;
1288 }
1289 } /* if conflict */
1290 pPciDev->Int.s.fRequestedDevFn = true;
1291 }
1292
1293 /*
1294 * Register the device.
1295 */
1296 pciRegisterInternal(pBus, iDev, pPciDev, pszName);
1297 return VINF_SUCCESS;
1298}
1299
1300
1301static DECLCALLBACK(int) pciIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, uint32_t cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
1302{
1303 PPCIIOREGION pRegion;
1304
1305 /*
1306 * Validate.
1307 */
1308 if ( enmType != PCI_ADDRESS_SPACE_MEM
1309 && enmType != PCI_ADDRESS_SPACE_IO
1310 && enmType != PCI_ADDRESS_SPACE_MEM_PREFETCH)
1311 {
1312 AssertMsgFailed(("Invalid enmType=%#x? Or was this a bitmask after all...\n", enmType));
1313 return VERR_INVALID_PARAMETER;
1314 }
1315 if ((unsigned)iRegion >= PCI_NUM_REGIONS)
1316 {
1317 AssertMsgFailed(("Invalid iRegion=%d PCI_NUM_REGIONS=%d\n", iRegion, PCI_NUM_REGIONS));
1318 return VERR_INVALID_PARAMETER;
1319 }
1320
1321 /*
1322 * Register the I/O region.
1323 */
1324 pRegion = &pPciDev->Int.s.aIORegions[iRegion];
1325 pRegion->addr = ~0U;
1326 pRegion->size = cbRegion;
1327 pRegion->type = enmType;
1328 pRegion->map_func = pfnCallback;
1329 return VINF_SUCCESS;
1330}
1331
1332
1333/**
1334 * @copydoc PDMPCIBUSREG::pfnSetConfigCallbacksHC
1335 */
1336static DECLCALLBACK(void) pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
1337 PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
1338{
1339 if (ppfnReadOld)
1340 *ppfnReadOld = pPciDev->Int.s.pfnConfigRead;
1341 pPciDev->Int.s.pfnConfigRead = pfnRead;
1342
1343 if (ppfnWriteOld)
1344 *ppfnWriteOld = pPciDev->Int.s.pfnConfigWrite;
1345 pPciDev->Int.s.pfnConfigWrite = pfnWrite;
1346}
1347
1348
1349/**
1350 * Called to perform the job of the bios.
1351 *
1352 * @returns VBox status.
1353 * @param pDevIns Device instance of the first bus.
1354 */
1355static DECLCALLBACK(int) pciFakePCIBIOS(PPDMDEVINS pDevIns)
1356{
1357 int rc;
1358 unsigned i;
1359 uint8_t elcr[2] = {0, 0};
1360 PPCIGLOBALS pGlobals = DEVINS2PCIGLOBALS(pDevIns);
1361 PPCIBUS pBus = PDMINS2DATA(pDevIns, PPCIBUS);
1362 PVM pVM = PDMDevHlpGetVM(pDevIns);
1363 Assert(pVM);
1364
1365 /*
1366 * Set the start addresses.
1367 */
1368 pGlobals->pci_bios_io_addr = 0xc000;
1369 pGlobals->pci_bios_mem_addr = 0xf0000000;
1370
1371 /*
1372 * Activate IRQ mappings.
1373 */
1374 for (i = 0; i < 4; i++)
1375 {
1376 uint8_t irq = pci_irqs[i];
1377 /* Set to trigger level. */
1378 elcr[irq >> 3] |= (1 << (irq & 7));
1379 /* Activate irq remapping in PIIX3. */
1380 pci_config_writeb(&pBus->PIIX3State.dev, 0x60 + i, irq);
1381 }
1382
1383 /* Tell to the PIC. */
1384 rc = IOMIOPortWrite(pVM, 0x4d0, elcr[0], sizeof(uint8_t));
1385 if (rc == VINF_SUCCESS)
1386 rc = IOMIOPortWrite(pVM, 0x4d1, elcr[1], sizeof(uint8_t));
1387 if (rc != VINF_SUCCESS)
1388 {
1389 AssertMsgFailed(("Writing to PIC failed!\n"));
1390 return VBOX_SUCCESS(rc) ? VERR_INTERNAL_ERROR : rc;
1391 }
1392
1393 /*
1394 * Init the devices.
1395 */
1396 for (i = 0; i < ELEMENTS(pBus->devices); i++)
1397 {
1398 if (pBus->devices[i])
1399 {
1400 Log2(("PCI: Initializing device %d (%#x) '%s'\n",
1401 i, 0x80000000 | (i << 8), pBus->devices[i]->name));
1402 pci_bios_init_device(pBus->devices[i]);
1403 }
1404 }
1405 return VINF_SUCCESS;
1406}
1407
1408/**
1409 * @copydoc FNPDMDEVRELOCATE
1410 */
1411static DECLCALLBACK(void) pciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1412{
1413 PPCIBUS pBus = PDMINS2DATA(pDevIns, PPCIBUS);
1414 pBus->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
1415 pBus->pPciHlpGC = pBus->pPciHlpR3->pfnGetGCHelpers(pDevIns);
1416}
1417
1418
1419/**
1420 * Construct a PCI Bus device instance for a VM.
1421 *
1422 * @returns VBox status.
1423 * @param pDevIns The device instance data.
1424 * If the registration structure is needed, pDevIns->pDevReg points to it.
1425 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1426 * The device number is also found in pDevIns->iInstance, but since it's
1427 * likely to be freqently used PDM passes it as parameter.
1428 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1429 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1430 * iInstance it's expected to be used a bit in this function.
1431 */
1432static DECLCALLBACK(int) pciConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1433{
1434 PPCIGLOBALS pGlobals = DEVINS2PCIGLOBALS(pDevIns);
1435 PPCIBUS pBus = PDMINS2DATA(pDevIns, PPCIBUS);
1436 PDMPCIBUSREG PciBusReg;
1437 int rc;
1438 bool fGCEnabled;
1439 bool fR0Enabled;
1440 bool fUseIoApic;
1441 Assert(iInstance == 0);
1442
1443 /*
1444 * Validate and read configuration.
1445 */
1446 if (!CFGMR3AreValuesValid(pCfgHandle, "IOAPIC\0" "GCEnabled\0R0Enabled\0"))
1447 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1448
1449 /* query whether we got an IOAPIC */
1450 rc = CFGMR3QueryBool(pCfgHandle, "IOAPIC", &fUseIoApic);
1451 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1452 fUseIoApic = false;
1453 else if (VBOX_FAILURE(rc))
1454 return PDMDEV_SET_ERROR(pDevIns, rc,
1455 N_("Configuration error: Failed to query boolean value \"IOAPIC\""));
1456
1457 /* check if GC code is enabled. */
1458 rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &fGCEnabled);
1459 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1460 fGCEnabled = true;
1461 else if (VBOX_FAILURE(rc))
1462 return PDMDEV_SET_ERROR(pDevIns, rc,
1463 N_("Configuration error: Failed to query boolean value \"GCEnabled\""));
1464 Log(("PCI: fGCEnabled=%d\n", fGCEnabled));
1465
1466 /* check if R0 code is enabled. */
1467 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &fR0Enabled);
1468 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1469 fR0Enabled = true;
1470 else if (VBOX_FAILURE(rc))
1471 return PDMDEV_SET_ERROR(pDevIns, rc,
1472 N_("Configuration error: Failed to query boolean value \"R0Enabled\""));
1473 Log(("PCI: fR0Enabled=%d\n", fR0Enabled));
1474
1475 /*
1476 * Init data and register the PCI bus.
1477 */
1478 pGlobals->pci_mem_base = 0;
1479 pGlobals->pci_bios_io_addr = 0xc000;
1480 pGlobals->pci_bios_mem_addr = 0xf0000000;
1481 memset(&pGlobals->pci_irq_levels, 0, sizeof(pGlobals->pci_irq_levels));
1482 pGlobals->fUseIoApic = fUseIoApic;
1483 memset(&pGlobals->pci_apic_irq_levels, 0, sizeof(pGlobals->pci_apic_irq_levels));
1484
1485 pBus->pDevInsHC = pDevIns;
1486 pBus->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
1487
1488 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
1489 PciBusReg.pfnRegisterHC = pciRegister;
1490 PciBusReg.pfnIORegionRegisterHC = pciIORegionRegister;
1491 PciBusReg.pfnSetConfigCallbacksHC = pciSetConfigCallbacks;
1492 PciBusReg.pfnSetIrqHC = pciSetIrq;
1493 PciBusReg.pfnSaveExecHC = pciGenericSaveExec;
1494 PciBusReg.pfnLoadExecHC = pciGenericLoadExec;
1495 PciBusReg.pfnFakePCIBIOSHC = pciFakePCIBIOS;
1496 PciBusReg.pszSetIrqGC = fGCEnabled ? "pciSetIrq" : NULL;
1497 PciBusReg.pszSetIrqR0 = fR0Enabled ? "pciSetIrq" : NULL;
1498 rc = pDevIns->pDevHlp->pfnPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
1499 if (VBOX_FAILURE(rc))
1500 return PDMDEV_SET_ERROR(pDevIns, rc,
1501 N_("Failed to register ourselves as a PCI Bus"));
1502 if (pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION)
1503 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS,
1504 N_("PCI helper version mismatch; got %#x expected %#x"),
1505 pBus->pPciHlpR3->u32Version != PDM_PCIHLPR3_VERSION);
1506
1507 pBus->pPciHlpGC = pBus->pPciHlpR3->pfnGetGCHelpers(pDevIns);
1508 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
1509
1510 /*
1511 * Fill in PCI configs and add them to the bus.
1512 */
1513 /* i440FX */
1514 pBus->PciDev.config[0x00] = 0x86; /* vendor_id: Intel */
1515 pBus->PciDev.config[0x01] = 0x80;
1516 pBus->PciDev.config[0x02] = 0x37; /* device_id: */
1517 pBus->PciDev.config[0x03] = 0x12;
1518 pBus->PciDev.config[0x08] = 0x02; /* revision */
1519 pBus->PciDev.config[0x0a] = 0x00; /* class_sub = host2pci */
1520 pBus->PciDev.config[0x0b] = 0x06; /* class_base = PCI_bridge */
1521 pBus->PciDev.config[0x0e] = 0x00; /* header_type */
1522 pBus->PciDev.pDevIns = pDevIns;
1523 pBus->PciDev.Int.s.fRequestedDevFn= true;
1524 pciRegisterInternal(pBus, 0, &pBus->PciDev, "i440FX");
1525
1526 /* PIIX3 */
1527 pBus->PIIX3State.dev.config[0x00] = 0x86; /* vendor: Intel */
1528 pBus->PIIX3State.dev.config[0x01] = 0x80;
1529 pBus->PIIX3State.dev.config[0x02] = 0x00; /* device_id: 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
1530 pBus->PIIX3State.dev.config[0x03] = 0x70;
1531 pBus->PIIX3State.dev.config[0x0a] = 0x01; /* class_sub = PCI_ISA */
1532 pBus->PIIX3State.dev.config[0x0b] = 0x06; /* class_base = PCI_bridge */
1533 pBus->PIIX3State.dev.config[0x0e] = 0x80; /* header_type = PCI_multifunction, generic */
1534 pBus->PIIX3State.dev.pDevIns = pDevIns;
1535 pBus->PciDev.Int.s.fRequestedDevFn= true;
1536 pciRegisterInternal(pBus, 8, &pBus->PIIX3State.dev, "PIIX3");
1537 piix3_reset(&pBus->PIIX3State);
1538
1539 pBus->iDevSearch = 16;
1540
1541 /*
1542 * Register I/O ports and save state.
1543 */
1544 rc = PDMDevHlpIOPortRegister(pDevIns, 0xcf8, 1, NULL, pciIOPortAddressWrite, pciIOPortAddressRead, NULL, NULL, "i440FX (PCI)");
1545 if (VBOX_FAILURE(rc))
1546 return rc;
1547 rc = PDMDevHlpIOPortRegister(pDevIns, 0xcfc, 4, NULL, pciIOPortDataWrite, pciIOPortDataRead, NULL, NULL, "i440FX (PCI)");
1548 if (VBOX_FAILURE(rc))
1549 return rc;
1550 rc = PDMDevHlpSSMRegister(pDevIns, "pci", iInstance, 2, sizeof(*pBus),
1551 NULL, pciSaveExec, NULL, NULL, pciLoadExec, NULL);
1552 if (VBOX_FAILURE(rc))
1553 return rc;
1554
1555 return VINF_SUCCESS;
1556}
1557
1558
1559/**
1560 * The device registration structure.
1561 */
1562const PDMDEVREG g_DevicePCI =
1563{
1564 /* u32Version */
1565 PDM_DEVREG_VERSION,
1566 /* szDeviceName */
1567 "pci",
1568 /* szGCMod */
1569 "VBoxDDGC.gc",
1570 /* szR0Mod */
1571 "VBoxDDR0.r0",
1572 /* pszDescription */
1573 "i440FX PCI bridge and PIIX3 ISA bridge.",
1574 /* fFlags */
1575 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32 | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
1576 /* fClass */
1577 PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
1578 /* cMaxInstances */
1579 1,
1580 /* cbInstance */
1581 sizeof(PCIBUS),
1582 /* pfnConstruct */
1583 pciConstruct,
1584 /* pfnDestruct */
1585 NULL,
1586 /* pfnRelocate */
1587 pciRelocate,
1588 /* pfnIOCtl */
1589 NULL,
1590 /* pfnPowerOn */
1591 NULL,
1592 /* pfnReset */
1593 NULL,
1594 /* pfnSuspend */
1595 NULL,
1596 /* pfnResume */
1597 NULL,
1598 /* pfnAttach */
1599 NULL,
1600 /* pfnDetach */
1601 NULL,
1602 /* pfnQueryInterface */
1603 NULL,
1604 /* pfnInitComplete */
1605 NULL
1606};
1607#endif /* IN_RING3 */
1608#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette