VirtualBox

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

Last change on this file since 3839 was 3650, checked in by vboxsync, 18 years ago

Don't allow the guest to set status bits of the PCI status register to 1, writing a 1 has to clear the corresponding bit. Though fixes no known issue. And don't depend on vl_vbox.h anymore.

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

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