VirtualBox

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

Last change on this file since 5881 was 5361, checked in by vboxsync, 17 years ago

Added option to emulate PIIX4 IDE controller. Defaults to PIIX4 for new VMs
and to PIIX3 when no setting is present in XML.

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