VirtualBox

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

Last change on this file since 1 was 1, checked in by vboxsync, 55 years ago

import

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