VirtualBox

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

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

Eliminated HCPTRTYPE and replaced with R3R0PTRTYPE where necessary.

  • Property svn:eol-style set to native
File size: 54.1 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 && device_id == 0x7010) {
775 /* PIIX3 IDE */
776 pci_config_writew(d, 0x40, 0x8000); /* enable IDE0 */
777 pci_config_writew(d, 0x42, 0x8000); /* enable IDE1 */
778 goto default_map;
779 } else {
780 /* IDE: we map it as in ISA mode */
781 pci_set_io_region_addr(d, 0, 0x1f0);
782 pci_set_io_region_addr(d, 1, 0x3f4);
783 pci_set_io_region_addr(d, 2, 0x170);
784 pci_set_io_region_addr(d, 3, 0x374);
785 }
786 break;
787 case 0x0300:
788 if (vendor_id != 0x80ee)
789 goto default_map;
790 /* VGA: map frame buffer to default Bochs VBE address */
791 pci_set_io_region_addr(d, 0, 0xE0000000);
792 break;
793 case 0x0800:
794 /* PIC */
795 vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
796 device_id = pci_config_readw(d, PCI_DEVICE_ID);
797 if (vendor_id == 0x1014) {
798 /* IBM */
799 if (device_id == 0x0046 || device_id == 0xFFFF) {
800 /* MPIC & MPIC2 */
801 pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
802 }
803 }
804 break;
805 case 0xff00:
806 if (vendor_id == 0x0106b &&
807 (device_id == 0x0017 || device_id == 0x0022)) {
808 /* macio bridge */
809 pci_set_io_region_addr(d, 0, 0x80800000);
810 }
811 break;
812 default:
813 default_map:
814 /* default memory mappings */
815 for(i = 0; i < PCI_NUM_REGIONS; i++) {
816 r = &d->Int.s.aIORegions[i];
817
818 if (r->size) {
819 if (r->type & PCI_ADDRESS_SPACE_IO)
820 paddr = &PCIBUS2PCIGLOBALS(d->Int.s.pBus)->pci_bios_io_addr;
821 else
822 paddr = &PCIBUS2PCIGLOBALS(d->Int.s.pBus)->pci_bios_mem_addr;
823 *paddr = (*paddr + r->size - 1) & ~(r->size - 1);
824 pci_set_io_region_addr(d, i, *paddr);
825 *paddr += r->size;
826 }
827 }
828 break;
829 }
830
831 /* map the interrupt */
832 pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
833 if (pin != 0) {
834 pin = pci_slot_get_pirq(d, pin - 1);
835 pic_irq = pci_irqs[pin];
836 pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
837 }
838}
839
840/* -=-=-=-=-=- wrappers -=-=-=-=-=- */
841
842/**
843 * Port I/O Handler for PCI address OUT operations.
844 *
845 * @returns VBox status code.
846 *
847 * @param pDevIns The device instance.
848 * @param pvUser User argument - ignored.
849 * @param uPort Port number used for the IN operation.
850 * @param u32 The value to output.
851 * @param cb The value size in bytes.
852 */
853static DECLCALLBACK(int) pciIOPortAddressWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
854{
855 Log(("pciIOPortAddressWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
856 NOREF(pvUser);
857 if (cb == 4)
858 {
859 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_WRITE);
860 pci_addr_writel(PDMINS2DATA(pDevIns, PCIBus *), Port, u32);
861 PCI_UNLOCK(pDevIns);
862 }
863 /* else: 440FX does "pass through to the bus" for other writes, what ever that means.
864 * Linux probes for cmd640 using byte writes/reads during ide init. We'll just ignore it. */
865 return VINF_SUCCESS;
866}
867
868/**
869 * Port I/O Handler for PCI address IN operations.
870 *
871 * @returns VBox status code.
872 *
873 * @param pDevIns The device instance.
874 * @param pvUser User argument - ignored.
875 * @param uPort Port number used for the IN operation.
876 * @param pu32 Where to store the result.
877 * @param cb Number of bytes read.
878 */
879static DECLCALLBACK(int) pciIOPortAddressRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
880{
881 NOREF(pvUser);
882 if (cb == 4)
883 {
884 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_READ);
885 *pu32 = pci_addr_readl(PDMINS2DATA(pDevIns, PCIBus *), Port);
886 PCI_UNLOCK(pDevIns);
887 Log(("pciIOPortAddressRead: Port=%#x cb=%d -> %#x\n", Port, cb, *pu32));
888 return VINF_SUCCESS;
889 }
890 /* else: 440FX does "pass through to the bus" for other writes, what ever that means.
891 * Linux probes for cmd640 using byte writes/reads during ide init. We'll just ignore it. */
892 Log(("pciIOPortAddressRead: Port=%#x cb=%d VERR_IOM_IOPORT_UNUSED\n", Port, cb));
893 return VERR_IOM_IOPORT_UNUSED;
894}
895
896
897/**
898 * Port I/O Handler for PCI data OUT operations.
899 *
900 * @returns VBox status code.
901 *
902 * @param pDevIns The device instance.
903 * @param pvUser User argument - ignored.
904 * @param uPort Port number used for the IN operation.
905 * @param u32 The value to output.
906 * @param cb The value size in bytes.
907 */
908static DECLCALLBACK(int) pciIOPortDataWrite(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t u32, unsigned cb)
909{
910 Log(("pciIOPortDataWrite: Port=%#x u32=%#x cb=%d\n", Port, u32, cb));
911 NOREF(pvUser);
912 if (!(Port % cb))
913 {
914 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_WRITE);
915 pci_data_write(PDMINS2DATA(pDevIns, PCIBus *), Port, u32, cb);
916 PCI_UNLOCK(pDevIns);
917 }
918 else
919 AssertMsgFailed(("Write to port %#x u32=%#x cb=%d\n", Port, u32, cb));
920 return VINF_SUCCESS;
921}
922
923
924/**
925 * Port I/O Handler for PCI data IN operations.
926 *
927 * @returns VBox status code.
928 *
929 * @param pDevIns The device instance.
930 * @param pvUser User argument - ignored.
931 * @param uPort Port number used for the IN operation.
932 * @param pu32 Where to store the result.
933 * @param cb Number of bytes read.
934 */
935static DECLCALLBACK(int) pciIOPortDataRead(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT Port, uint32_t *pu32, unsigned cb)
936{
937 NOREF(pvUser);
938 if (!(Port % cb))
939 {
940 PCI_LOCK(pDevIns, VINF_IOM_HC_IOPORT_READ);
941 *pu32 = pci_data_read(PDMINS2DATA(pDevIns, PCIBus *), Port, cb);
942 PCI_UNLOCK(pDevIns);
943 Log(("pciIOPortDataRead: Port=%#x cb=%#x -> %#x\n", Port, cb, *pu32));
944 return VINF_SUCCESS;
945 }
946 AssertMsgFailed(("Read from port %#x cb=%d\n", Port, cb));
947 return VERR_IOM_IOPORT_UNUSED;
948}
949
950
951/**
952 * Saves a state of the PCI device.
953 *
954 * @returns VBox status code.
955 * @param pDevIns Device instance of the PCI Bus.
956 * @param pPciDev Pointer to PCI device.
957 * @param pSSMHandle The handle to save the state to.
958 */
959static DECLCALLBACK(int) pciGenericSaveExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSMHandle)
960{
961 return SSMR3PutMem(pSSMHandle, &pPciDev->config[0], sizeof(pPciDev->config));
962}
963
964
965/**
966 * Loads a saved PCI device state.
967 *
968 * @returns VBox status code.
969 * @param pDevIns Device instance of the PCI Bus.
970 * @param pPciDev Pointer to PCI device.
971 * @param pSSMHandle The handle to the saved state.
972 */
973static DECLCALLBACK(int) pciGenericLoadExec(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PSSMHANDLE pSSMHandle)
974{
975 return SSMR3GetMem(pSSMHandle, &pPciDev->config[0], sizeof(pPciDev->config));
976}
977
978
979/**
980 * Saves a state of the PCI device.
981 *
982 * @returns VBox status code.
983 * @param pDevIns The device instance.
984 * @param pPciDev Pointer to PCI device.
985 * @param pSSMHandle The handle to save the state to.
986 */
987static DECLCALLBACK(int) pciSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle)
988{
989 uint32_t i;
990 PPCIBUS pData = PDMINS2DATA(pDevIns, PPCIBUS);
991 PPCIGLOBALS pGlobals = PCIBUS2PCIGLOBALS(pData);
992
993 /*
994 * Bus state data.
995 */
996 SSMR3PutU32(pSSMHandle, pData->uConfigReg);
997 SSMR3PutBool(pSSMHandle, pGlobals->fUseIoApic);
998 SSMR3PutU32(pSSMHandle, ~0); /* separator */
999
1000 /*
1001 * Iterate all the devices.
1002 */
1003 for (i = 0; i < ELEMENTS(pData->devices); i++)
1004 {
1005 PPCIDEVICE pDev = pData->devices[i];
1006 if (pDev)
1007 {
1008 int rc;
1009 SSMR3PutU32(pSSMHandle, i);
1010 SSMR3PutMem(pSSMHandle, pDev->config, sizeof(pDev->config));
1011 rc = SSMR3PutS32(pSSMHandle, pDev->Int.s.iIrq);
1012 if (VBOX_FAILURE(rc))
1013 return rc;
1014 }
1015 }
1016 return SSMR3PutU32(pSSMHandle, ~0); /* terminator */
1017}
1018
1019/**
1020 * Loads a saved PCI device state.
1021 *
1022 * @returns VBox status code.
1023 * @param pDevIns The device instance.
1024 * @param pSSMHandle The handle to the saved state.
1025 * @param u32Version The data unit version number.
1026 */
1027static DECLCALLBACK(int) pciLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSMHandle, uint32_t u32Version)
1028{
1029 PPCIBUS pData = PDMINS2DATA(pDevIns, PPCIBUS);
1030 PPCIGLOBALS pGlobals = PCIBUS2PCIGLOBALS(pData);
1031 uint32_t u32;
1032 uint32_t i;
1033 int rc;
1034
1035 /*
1036 * Check the version.
1037 */
1038 if (u32Version > 2)
1039 {
1040 AssertFailed();
1041 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1042 }
1043
1044 /*
1045 * Bus state data.
1046 */
1047 SSMR3GetU32(pSSMHandle, &pData->uConfigReg);
1048 if (u32Version > 1)
1049 SSMR3GetBool(pSSMHandle, &pGlobals->fUseIoApic);
1050
1051 /* separator */
1052 rc = SSMR3GetU32(pSSMHandle, &u32);
1053 if (VBOX_FAILURE(rc))
1054 return rc;
1055 if (u32 != (uint32_t)~0)
1056 AssertMsgFailedReturn(("u32=%#x\n", u32), rc);
1057
1058 /*
1059 * Iterate all the devices.
1060 */
1061 for (i = 0;; i++)
1062 {
1063 PCIDEVICE DevTmp;
1064 PPCIDEVICE pDev;
1065
1066 /* index / terminator */
1067 rc = SSMR3GetU32(pSSMHandle, &u32);
1068 if (VBOX_FAILURE(rc))
1069 return rc;
1070 if (u32 == (uint32_t)~0)
1071 break;
1072 if ( u32 >= ELEMENTS(pData->devices)
1073 || u32 < i)
1074 {
1075 AssertMsgFailed(("u32=%#x i=%#x\n", u32, i));
1076 return rc;
1077 }
1078
1079 /* skip forward to the device checking that no new devices are present. */
1080 for (; i < u32; i++)
1081 {
1082 if (pData->devices[i])
1083 {
1084 LogRel(("New device in slot %#x, %s (vendor=%#06x device=%#06x)\n", i, pData->devices[i]->name,
1085 PCIDevGetVendorId(pData->devices[i]), PCIDevGetDeviceId(pData->devices[i])));
1086 if (SSMR3HandleGetAfter(pSSMHandle) != SSMAFTER_DEBUG_IT)
1087 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
1088 }
1089 }
1090
1091 /* get the data */
1092 SSMR3GetMem(pSSMHandle, DevTmp.config, sizeof(DevTmp.config));
1093 rc = SSMR3GetS32(pSSMHandle, &DevTmp.Int.s.iIrq);
1094 if (VBOX_FAILURE(rc))
1095 return rc;
1096
1097 /* check that it's still around. */
1098 pDev = pData->devices[i];
1099 if (!pDev)
1100 {
1101 LogRel(("Device in slot %#x has been removed! vendor=%#06x device=%#06x\n", i,
1102 PCIDevGetVendorId(&DevTmp), PCIDevGetDeviceId(&DevTmp)));
1103 if (SSMR3HandleGetAfter(pSSMHandle) != SSMAFTER_DEBUG_IT)
1104 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
1105 continue;
1106 }
1107
1108 /* match the vendor id assuming that this will never be changed. */
1109 if ( DevTmp.config[0] != pDev->config[0]
1110 || DevTmp.config[1] != pDev->config[1])
1111 {
1112 LogRel(("Device in slot %#x (%s) vendor id mismatch! saved=%.4Vhxs current=%.4Vhxs\n",
1113 i, pDev->name, DevTmp.config, pDev->config));
1114 AssertFailedReturn(VERR_SSM_LOAD_CONFIG_MISMATCH);
1115 }
1116
1117 /* commit the loaded device config. */
1118 memcpy(pDev->config, DevTmp.config, sizeof(pDev->config));
1119 if (DevTmp.Int.s.iIrq >= PCI_DEVICES_MAX)
1120 {
1121 LogRel(("Device %s: Too many devices %d (max=%d)\n", pDev->name, DevTmp.Int.s.iIrq, PCI_DEVICES_MAX));
1122 AssertFailedReturn(VERR_TOO_MUCH_DATA);
1123 }
1124
1125 pDev->Int.s.iIrq = DevTmp.Int.s.iIrq;
1126 }
1127 return VINF_SUCCESS;
1128}
1129
1130
1131/* -=-=-=-=-=- real code -=-=-=-=-=- */
1132
1133
1134/**
1135 * Registers the device with the default PCI bus.
1136 *
1137 * @returns VBox status code.
1138 * @param pBus The bus to register with.
1139 * @param iDev The PCI device ordinal.
1140 * @param pPciDev The PCI device structure.
1141 * @param pszName Pointer to device name (permanent, readonly). For debugging, not unique.
1142 */
1143static void pciRegisterInternal(PPCIBUS pBus, int iDev, PPCIDEVICE pPciDev, const char *pszName)
1144{
1145 Assert(!pBus->devices[iDev]);
1146 pPciDev->devfn = iDev;
1147 pPciDev->name = pszName;
1148 pPciDev->Int.s.pBus = pBus;
1149 pPciDev->Int.s.pfnConfigRead = pci_default_read_config;
1150 pPciDev->Int.s.pfnConfigWrite = pci_default_write_config;
1151 AssertMsg(pBus->uIrqIndex < PCI_DEVICES_MAX,
1152 ("Device %s: Too many devices %d (max=%d)\n",
1153 pszName, pBus->uIrqIndex, PCI_DEVICES_MAX));
1154 pPciDev->Int.s.iIrq = pBus->uIrqIndex++;
1155 pBus->devices[iDev] = pPciDev;
1156 Log(("PCI: Registered device %d function %d (%#x) '%s'.\n",
1157 iDev >> 3, iDev & 7, 0x80000000 | (iDev << 8), pszName));
1158}
1159
1160
1161/**
1162 * Registers the device with the default PCI bus.
1163 *
1164 * @returns VBox status code.
1165 * @param pDevIns Device instance of the PCI Bus.
1166 * @param pPciDev The PCI device structure.
1167 * Any PCI enabled device must keep this in it's instance data!
1168 * Fill in the PCI data config before registration, please.
1169 * @param pszName Pointer to device name (permanent, readonly). For debugging, not unique.
1170 * @param iDev The PCI device number. Use a negative value for auto assigning one.
1171 */
1172static DECLCALLBACK(int) pciRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, const char *pszName, int iDev)
1173{
1174 PPCIBUS pBus = PDMINS2DATA(pDevIns, PPCIBUS);
1175
1176 /*
1177 * Check input.
1178 */
1179 if ( !pszName
1180 || !pPciDev
1181 || iDev >= (int)ELEMENTS(pBus->devices)
1182 || (iDev >= 0 && iDev <= 8))
1183 {
1184 AssertMsgFailed(("Invalid argument! pszName=%s pPciDev=%p iDev=%d\n", pszName, pPciDev, iDev));
1185 return VERR_INVALID_PARAMETER;
1186 }
1187
1188 /*
1189 * Find device slot.
1190 */
1191 if (iDev < 0)
1192 {
1193 /*
1194 * Special check for the IDE controller which is our function 1 device
1195 * before searching.
1196 */
1197 if ( !strcmp(pszName, "piix3ide")
1198 && !pBus->devices[9])
1199 iDev = 9;
1200 else
1201 {
1202 Assert(!(pBus->iDevSearch % 8));
1203 for (iDev = pBus->iDevSearch; iDev < (int)ELEMENTS(pBus->devices); iDev += 8)
1204 if ( !pBus->devices[iDev]
1205 && !pBus->devices[iDev + 1]
1206 && !pBus->devices[iDev + 2]
1207 && !pBus->devices[iDev + 3]
1208 && !pBus->devices[iDev + 4]
1209 && !pBus->devices[iDev + 5]
1210 && !pBus->devices[iDev + 6]
1211 && !pBus->devices[iDev + 7])
1212 break;
1213 if (iDev >= (int)ELEMENTS(pBus->devices))
1214 {
1215 AssertMsgFailed(("Couldn't find free spot!\n"));
1216 return VERR_PDM_TOO_PCI_MANY_DEVICES;
1217 }
1218 }
1219 pPciDev->Int.s.fRequestedDevFn = false;
1220 }
1221 else
1222 {
1223 /*
1224 * An explicit request.
1225 *
1226 * If the slot is occupied we'll have to relocate the device
1227 * currently occupying it first. This can only be done if the
1228 * existing device wasn't explicitly assigned. Also we limit
1229 * ourselves to function 0 devices.
1230 *
1231 * If you start setting devices + function in the
1232 * config, do it for all pci devices!
1233 */
1234 AssertReleaseMsg(iDev > 8, ("iDev=%d pszName=%s\n", iDev, pszName));
1235 if (pBus->devices[iDev])
1236 {
1237 int iDevRel;
1238 AssertReleaseMsg(!(iDev % 8), ("PCI Configuration Conflict! iDev=%d pszName=%s clashes with %s\n",
1239 iDev, pszName, pBus->devices[iDev]->name));
1240 if ( pBus->devices[iDev]->Int.s.fRequestedDevFn
1241 || (pBus->devices[iDev + 1] && pBus->devices[iDev + 1]->Int.s.fRequestedDevFn)
1242 || (pBus->devices[iDev + 2] && pBus->devices[iDev + 2]->Int.s.fRequestedDevFn)
1243 || (pBus->devices[iDev + 3] && pBus->devices[iDev + 3]->Int.s.fRequestedDevFn)
1244 || (pBus->devices[iDev + 4] && pBus->devices[iDev + 4]->Int.s.fRequestedDevFn)
1245 || (pBus->devices[iDev + 5] && pBus->devices[iDev + 5]->Int.s.fRequestedDevFn)
1246 || (pBus->devices[iDev + 6] && pBus->devices[iDev + 6]->Int.s.fRequestedDevFn)
1247 || (pBus->devices[iDev + 7] && pBus->devices[iDev + 7]->Int.s.fRequestedDevFn))
1248 {
1249 AssertReleaseMsgFailed(("Configuration error:'%s' and '%s' are both configured as device %d\n",
1250 pszName, pBus->devices[iDev]->name, iDev));
1251 return VERR_INTERNAL_ERROR;
1252 }
1253
1254 /* Find free slot for the device(s) we're moving and move them. */
1255 for (iDevRel = pBus->iDevSearch; iDevRel < (int)ELEMENTS(pBus->devices); iDevRel += 8)
1256 {
1257 if ( !pBus->devices[iDevRel]
1258 && !pBus->devices[iDevRel + 1]
1259 && !pBus->devices[iDevRel + 2]
1260 && !pBus->devices[iDevRel + 3]
1261 && !pBus->devices[iDevRel + 4]
1262 && !pBus->devices[iDevRel + 5]
1263 && !pBus->devices[iDevRel + 6]
1264 && !pBus->devices[iDevRel + 7])
1265 {
1266 int i = 0;
1267 for (i = 0; i < 8; i++)
1268 {
1269 if (!pBus->devices[iDev + i])
1270 continue;
1271 Log(("PCI: relocating '%s' from slot %#x to %#x\n", pBus->devices[iDev + i]->name, iDev + i, iDevRel + i));
1272 pBus->devices[iDevRel + i] = pBus->devices[iDev + i];
1273 pBus->devices[iDevRel + i]->devfn = i;
1274 pBus->devices[iDev + i] = NULL;
1275 }
1276 }
1277 }
1278 if (pBus->devices[iDev])
1279 {
1280 AssertMsgFailed(("Couldn't find free spot!\n"));
1281 return VERR_PDM_TOO_PCI_MANY_DEVICES;
1282 }
1283 } /* if conflict */
1284 pPciDev->Int.s.fRequestedDevFn = true;
1285 }
1286
1287 /*
1288 * Register the device.
1289 */
1290 pciRegisterInternal(pBus, iDev, pPciDev, pszName);
1291 return VINF_SUCCESS;
1292}
1293
1294
1295static DECLCALLBACK(int) pciIORegionRegister(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, int iRegion, uint32_t cbRegion, PCIADDRESSSPACE enmType, PFNPCIIOREGIONMAP pfnCallback)
1296{
1297 PPCIIOREGION pRegion;
1298
1299 /*
1300 * Validate.
1301 */
1302 if ( enmType != PCI_ADDRESS_SPACE_MEM
1303 && enmType != PCI_ADDRESS_SPACE_IO
1304 && enmType != PCI_ADDRESS_SPACE_MEM_PREFETCH)
1305 {
1306 AssertMsgFailed(("Invalid enmType=%#x? Or was this a bitmask after all...\n", enmType));
1307 return VERR_INVALID_PARAMETER;
1308 }
1309 if ((unsigned)iRegion >= PCI_NUM_REGIONS)
1310 {
1311 AssertMsgFailed(("Invalid iRegion=%d PCI_NUM_REGIONS=%d\n", iRegion, PCI_NUM_REGIONS));
1312 return VERR_INVALID_PARAMETER;
1313 }
1314
1315 /*
1316 * Register the I/O region.
1317 */
1318 pRegion = &pPciDev->Int.s.aIORegions[iRegion];
1319 pRegion->addr = ~0U;
1320 pRegion->size = cbRegion;
1321 pRegion->type = enmType;
1322 pRegion->map_func = pfnCallback;
1323 return VINF_SUCCESS;
1324}
1325
1326
1327/**
1328 * @copydoc PDMPCIBUSREG::pfnSetConfigCallbacksHC
1329 */
1330static DECLCALLBACK(void) pciSetConfigCallbacks(PPDMDEVINS pDevIns, PPCIDEVICE pPciDev, PFNPCICONFIGREAD pfnRead, PPFNPCICONFIGREAD ppfnReadOld,
1331 PFNPCICONFIGWRITE pfnWrite, PPFNPCICONFIGWRITE ppfnWriteOld)
1332{
1333 if (ppfnReadOld)
1334 *ppfnReadOld = pPciDev->Int.s.pfnConfigRead;
1335 pPciDev->Int.s.pfnConfigRead = pfnRead;
1336
1337 if (ppfnWriteOld)
1338 *ppfnWriteOld = pPciDev->Int.s.pfnConfigWrite;
1339 pPciDev->Int.s.pfnConfigWrite = pfnWrite;
1340}
1341
1342
1343/**
1344 * Called to perform the job of the bios.
1345 *
1346 * @returns VBox status.
1347 * @param pDevIns Device instance of the first bus.
1348 */
1349static DECLCALLBACK(int) pciFakePCIBIOS(PPDMDEVINS pDevIns)
1350{
1351 int rc;
1352 unsigned i;
1353 uint8_t elcr[2] = {0, 0};
1354 PPCIGLOBALS pGlobals = DEVINS2PCIGLOBALS(pDevIns);
1355 PPCIBUS pBus = PDMINS2DATA(pDevIns, PPCIBUS);
1356 PVM pVM = PDMDevHlpGetVM(pDevIns);
1357 Assert(pVM);
1358
1359 /*
1360 * Set the start addresses.
1361 */
1362 pGlobals->pci_bios_io_addr = 0xc000;
1363 pGlobals->pci_bios_mem_addr = 0xf0000000;
1364
1365 /*
1366 * Activate IRQ mappings.
1367 */
1368 for (i = 0; i < 4; i++)
1369 {
1370 uint8_t irq = pci_irqs[i];
1371 /* Set to trigger level. */
1372 elcr[irq >> 3] |= (1 << (irq & 7));
1373 /* Activate irq remapping in PIIX3. */
1374 pci_config_writeb(&pBus->PIIX3State.dev, 0x60 + i, irq);
1375 }
1376
1377 /* Tell to the PIC. */
1378 rc = IOMIOPortWrite(pVM, 0x4d0, elcr[0], sizeof(uint8_t));
1379 if (rc == VINF_SUCCESS)
1380 rc = IOMIOPortWrite(pVM, 0x4d1, elcr[1], sizeof(uint8_t));
1381 if (rc != VINF_SUCCESS)
1382 {
1383 AssertMsgFailed(("Writing to PIC failed!\n"));
1384 return VBOX_SUCCESS(rc) ? VERR_INTERNAL_ERROR : rc;
1385 }
1386
1387 /*
1388 * Init the devices.
1389 */
1390 for (i = 0; i < ELEMENTS(pBus->devices); i++)
1391 {
1392 if (pBus->devices[i])
1393 {
1394 Log2(("PCI: Initializing device %d (%#x) '%s'\n",
1395 i, 0x80000000 | (i << 8), pBus->devices[i]->name));
1396 pci_bios_init_device(pBus->devices[i]);
1397 }
1398 }
1399 return VINF_SUCCESS;
1400}
1401
1402/**
1403 * @copydoc FNPDMDEVRELOCATE
1404 */
1405static DECLCALLBACK(void) pciRelocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
1406{
1407 PPCIBUS pBus = PDMINS2DATA(pDevIns, PPCIBUS);
1408 pBus->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
1409 pBus->pPciHlpGC = pBus->pPciHlpR3->pfnGetGCHelpers(pDevIns);
1410}
1411
1412
1413/**
1414 * Construct a PCI Bus device instance for a VM.
1415 *
1416 * @returns VBox status.
1417 * @param pDevIns The device instance data.
1418 * If the registration structure is needed, pDevIns->pDevReg points to it.
1419 * @param iInstance Instance number. Use this to figure out which registers and such to use.
1420 * The device number is also found in pDevIns->iInstance, but since it's
1421 * likely to be freqently used PDM passes it as parameter.
1422 * @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
1423 * of the device instance. It's also found in pDevIns->pCfgHandle, but like
1424 * iInstance it's expected to be used a bit in this function.
1425 */
1426static DECLCALLBACK(int) pciConstruct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfgHandle)
1427{
1428 PPCIGLOBALS pGlobals = DEVINS2PCIGLOBALS(pDevIns);
1429 PPCIBUS pBus = PDMINS2DATA(pDevIns, PPCIBUS);
1430 PDMPCIBUSREG PciBusReg;
1431 int rc;
1432 bool fGCEnabled;
1433 bool fR0Enabled;
1434 bool fUseIoApic;
1435 Assert(iInstance == 0);
1436
1437 /*
1438 * Validate and read configuration.
1439 */
1440 if (!CFGMR3AreValuesValid(pCfgHandle, "IOAPIC\0" "GCEnabled\0R0Enabled\0"))
1441 return VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES;
1442
1443 /* query whether we got an IOAPIC */
1444 rc = CFGMR3QueryBool(pCfgHandle, "IOAPIC", &fUseIoApic);
1445 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1446 fUseIoApic = false;
1447 else if (VBOX_FAILURE(rc))
1448 return PDMDEV_SET_ERROR(pDevIns, rc,
1449 N_("Configuration error: Failed to query boolean value \"IOAPIC\"."));
1450
1451 /* check if GC code is enabled. */
1452 rc = CFGMR3QueryBool(pCfgHandle, "GCEnabled", &fGCEnabled);
1453 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1454 fGCEnabled = true;
1455 else if (VBOX_FAILURE(rc))
1456 return PDMDEV_SET_ERROR(pDevIns, rc,
1457 N_("Configuration error: Failed to query boolean value \"GCEnabled\"."));
1458 Log(("PCI: fGCEnabled=%d\n", fGCEnabled));
1459
1460 /* check if R0 code is enabled. */
1461 rc = CFGMR3QueryBool(pCfgHandle, "R0Enabled", &fR0Enabled);
1462 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
1463 fR0Enabled = true;
1464 else if (VBOX_FAILURE(rc))
1465 return PDMDEV_SET_ERROR(pDevIns, rc,
1466 N_("Configuration error: Failed to query boolean value \"R0Enabled\"."));
1467 Log(("PCI: fR0Enabled=%d\n", fR0Enabled));
1468
1469 /*
1470 * Init data and register the PCI bus.
1471 */
1472 pGlobals->pci_mem_base = 0;
1473 pGlobals->pci_bios_io_addr = 0xc000;
1474 pGlobals->pci_bios_mem_addr = 0xf0000000;
1475 memset(&pGlobals->pci_irq_levels, 0, sizeof(pGlobals->pci_irq_levels));
1476 pGlobals->fUseIoApic = fUseIoApic;
1477 memset(&pGlobals->pci_apic_irq_levels, 0, sizeof(pGlobals->pci_apic_irq_levels));
1478
1479 pBus->pDevInsHC = pDevIns;
1480 pBus->pDevInsGC = PDMDEVINS_2_GCPTR(pDevIns);
1481
1482 PciBusReg.u32Version = PDM_PCIBUSREG_VERSION;
1483 PciBusReg.pfnRegisterHC = pciRegister;
1484 PciBusReg.pfnIORegionRegisterHC = pciIORegionRegister;
1485 PciBusReg.pfnSetConfigCallbacksHC = pciSetConfigCallbacks;
1486 PciBusReg.pfnSetIrqHC = pciSetIrq;
1487 PciBusReg.pfnSaveExecHC = pciGenericSaveExec;
1488 PciBusReg.pfnLoadExecHC = pciGenericLoadExec;
1489 PciBusReg.pfnFakePCIBIOSHC = pciFakePCIBIOS;
1490 PciBusReg.pszSetIrqGC = fGCEnabled ? "pciSetIrq" : NULL;
1491 PciBusReg.pszSetIrqR0 = fR0Enabled ? "pciSetIrq" : NULL;
1492 rc = pDevIns->pDevHlp->pfnPCIBusRegister(pDevIns, &PciBusReg, &pBus->pPciHlpR3);
1493 if (VBOX_FAILURE(rc))
1494 return PDMDEV_SET_ERROR(pDevIns, rc,
1495 N_("Failed to register ourselves as a PCI Bus"));
1496
1497 pBus->pPciHlpGC = pBus->pPciHlpR3->pfnGetGCHelpers(pDevIns);
1498 pBus->pPciHlpR0 = pBus->pPciHlpR3->pfnGetR0Helpers(pDevIns);
1499
1500 /*
1501 * Fill in PCI configs and add them to the bus.
1502 */
1503 /* i440FX */
1504 pBus->PciDev.config[0x00] = 0x86; /* vendor_id: Intel */
1505 pBus->PciDev.config[0x01] = 0x80;
1506 pBus->PciDev.config[0x02] = 0x37; /* device_id: */
1507 pBus->PciDev.config[0x03] = 0x12;
1508 pBus->PciDev.config[0x08] = 0x02; /* revision */
1509 pBus->PciDev.config[0x0a] = 0x00; /* class_sub = host2pci */
1510 pBus->PciDev.config[0x0b] = 0x06; /* class_base = PCI_bridge */
1511 pBus->PciDev.config[0x0e] = 0x00; /* header_type */
1512 pBus->PciDev.pDevIns = pDevIns;
1513 pBus->PciDev.Int.s.fRequestedDevFn= true;
1514 pciRegisterInternal(pBus, 0, &pBus->PciDev, "i440FX");
1515
1516 /* PIIX3 */
1517 pBus->PIIX3State.dev.config[0x00] = 0x86; /* vendor: Intel */
1518 pBus->PIIX3State.dev.config[0x01] = 0x80;
1519 pBus->PIIX3State.dev.config[0x02] = 0x00; /* device_id: 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */
1520 pBus->PIIX3State.dev.config[0x03] = 0x70;
1521 pBus->PIIX3State.dev.config[0x0a] = 0x01; /* class_sub = PCI_ISA */
1522 pBus->PIIX3State.dev.config[0x0b] = 0x06; /* class_base = PCI_bridge */
1523 pBus->PIIX3State.dev.config[0x0e] = 0x80; /* header_type = PCI_multifunction, generic */
1524 pBus->PIIX3State.dev.pDevIns = pDevIns;
1525 pBus->PciDev.Int.s.fRequestedDevFn= true;
1526 pciRegisterInternal(pBus, 8, &pBus->PIIX3State.dev, "PIIX3");
1527 piix3_reset(&pBus->PIIX3State);
1528
1529 pBus->iDevSearch = 16;
1530
1531 /*
1532 * Register I/O ports and save state.
1533 */
1534 rc = PDMDevHlpIOPortRegister(pDevIns, 0xcf8, 1, NULL, pciIOPortAddressWrite, pciIOPortAddressRead, NULL, NULL, "i440FX (PCI)");
1535 if (VBOX_FAILURE(rc))
1536 return rc;
1537 rc = PDMDevHlpIOPortRegister(pDevIns, 0xcfc, 4, NULL, pciIOPortDataWrite, pciIOPortDataRead, NULL, NULL, "i440FX (PCI)");
1538 if (VBOX_FAILURE(rc))
1539 return rc;
1540 rc = PDMDevHlpSSMRegister(pDevIns, "pci", iInstance, 2, sizeof(*pBus),
1541 NULL, pciSaveExec, NULL, NULL, pciLoadExec, NULL);
1542 if (VBOX_FAILURE(rc))
1543 return rc;
1544
1545 return VINF_SUCCESS;
1546}
1547
1548
1549/**
1550 * The device registration structure.
1551 */
1552const PDMDEVREG g_DevicePCI =
1553{
1554 /* u32Version */
1555 PDM_DEVREG_VERSION,
1556 /* szDeviceName */
1557 "pci",
1558 /* szGCMod */
1559 "VBoxDDGC.gc",
1560 /* szR0Mod */
1561 "VBoxDDR0.r0",
1562 /* pszDescription */
1563 "i440FX PCI bridge and PIIX3 ISA bridge.",
1564 /* fFlags */
1565 PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT | PDM_DEVREG_FLAGS_GUEST_BITS_32 | PDM_DEVREG_FLAGS_GC | PDM_DEVREG_FLAGS_R0,
1566 /* fClass */
1567 PDM_DEVREG_CLASS_BUS_PCI | PDM_DEVREG_CLASS_BUS_ISA,
1568 /* cMaxInstances */
1569 1,
1570 /* cbInstance */
1571 sizeof(PCIBUS),
1572 /* pfnConstruct */
1573 pciConstruct,
1574 /* pfnDestruct */
1575 NULL,
1576 /* pfnRelocate */
1577 pciRelocate,
1578 /* pfnIOCtl */
1579 NULL,
1580 /* pfnPowerOn */
1581 NULL,
1582 /* pfnReset */
1583 NULL,
1584 /* pfnSuspend */
1585 NULL,
1586 /* pfnResume */
1587 NULL,
1588 /* pfnAttach */
1589 NULL,
1590 /* pfnDetach */
1591 NULL,
1592 /* pfnQueryInterface */
1593 NULL,
1594 /* pfnInitComplete */
1595 NULL
1596};
1597#endif /* IN_RING3 */
1598#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