VirtualBox

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

Last change on this file since 2685 was 2597, checked in by vboxsync, 18 years ago

New device helper PCISetConfigCallbacks. (patch from R. Zeljko)

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