Commit 69b910399a3c40620a5213adaeb14a37366d97ac
1 parent
158156d1
PCI support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@818 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
10 changed files
with
842 additions
and
30 deletions
Changelog
| ... | ... | @@ -8,6 +8,9 @@ version 0.5.6: |
| 8 | 8 | - int13 CDROM BIOS fix (aka Solaris x86 install CD fix) |
| 9 | 9 | - int15, ah=86 BIOS fix (aka Solaris x86 hardware probe hang up fix) |
| 10 | 10 | - BSR/BSF "undefined behaviour" fix |
| 11 | + - vmdk2raw: convert VMware disk images to raw images | |
| 12 | + - PCI support | |
| 13 | + - NE2K PCI support | |
| 11 | 14 | |
| 12 | 15 | version 0.5.5: |
| 13 | 16 | ... | ... |
Makefile.target
| ... | ... | @@ -232,7 +232,7 @@ ifeq ($(ARCH),alpha) |
| 232 | 232 | endif |
| 233 | 233 | |
| 234 | 234 | # must use static linking to avoid leaving stuff in virtual address space |
| 235 | -VL_OBJS=vl.o osdep.o block.o monitor.o | |
| 235 | +VL_OBJS=vl.o osdep.o block.o monitor.o pci.o pci2isa.o | |
| 236 | 236 | |
| 237 | 237 | ifeq ($(TARGET_ARCH), i386) |
| 238 | 238 | # Hardware support | ... | ... |
hw/ide.c
| ... | ... | @@ -1433,18 +1433,14 @@ static void ide_guess_geometry(IDEState *s) |
| 1433 | 1433 | } |
| 1434 | 1434 | } |
| 1435 | 1435 | |
| 1436 | -void ide_init(int iobase, int iobase2, int irq, | |
| 1437 | - BlockDriverState *hd0, BlockDriverState *hd1) | |
| 1436 | +static void ide_init2(IDEState *ide_state, int irq, | |
| 1437 | + BlockDriverState *hd0, BlockDriverState *hd1) | |
| 1438 | 1438 | { |
| 1439 | - IDEState *s, *ide_state; | |
| 1439 | + IDEState *s; | |
| 1440 | 1440 | static int drive_serial = 1; |
| 1441 | 1441 | int i, cylinders, heads, secs; |
| 1442 | 1442 | int64_t nb_sectors; |
| 1443 | 1443 | |
| 1444 | - ide_state = qemu_mallocz(sizeof(IDEState) * 2); | |
| 1445 | - if (!ide_state) | |
| 1446 | - return; | |
| 1447 | - | |
| 1448 | 1444 | for(i = 0; i < 2; i++) { |
| 1449 | 1445 | s = ide_state + i; |
| 1450 | 1446 | if (i == 0) |
| ... | ... | @@ -1483,6 +1479,22 @@ void ide_init(int iobase, int iobase2, int irq, |
| 1483 | 1479 | s->irq = irq; |
| 1484 | 1480 | ide_reset(s); |
| 1485 | 1481 | } |
| 1482 | +} | |
| 1483 | + | |
| 1484 | +/***********************************************************/ | |
| 1485 | +/* ISA IDE definitions */ | |
| 1486 | + | |
| 1487 | +void isa_ide_init(int iobase, int iobase2, int irq, | |
| 1488 | + BlockDriverState *hd0, BlockDriverState *hd1) | |
| 1489 | +{ | |
| 1490 | + IDEState *ide_state; | |
| 1491 | + | |
| 1492 | + ide_state = qemu_mallocz(sizeof(IDEState) * 2); | |
| 1493 | + if (!ide_state) | |
| 1494 | + return; | |
| 1495 | + | |
| 1496 | + ide_init2(ide_state, irq, hd0, hd1); | |
| 1497 | + | |
| 1486 | 1498 | register_ioport_write(iobase, 8, 1, ide_ioport_write, ide_state); |
| 1487 | 1499 | register_ioport_read(iobase, 8, 1, ide_ioport_read, ide_state); |
| 1488 | 1500 | if (iobase2) { |
| ... | ... | @@ -1496,3 +1508,87 @@ void ide_init(int iobase, int iobase2, int irq, |
| 1496 | 1508 | register_ioport_write(iobase, 4, 4, ide_data_writel, ide_state); |
| 1497 | 1509 | register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state); |
| 1498 | 1510 | } |
| 1511 | + | |
| 1512 | +/***********************************************************/ | |
| 1513 | +/* PCI IDE definitions */ | |
| 1514 | + | |
| 1515 | +typedef struct PCIIDEState { | |
| 1516 | + PCIDevice dev; | |
| 1517 | + IDEState ide_if[4]; | |
| 1518 | +} PCIIDEState; | |
| 1519 | + | |
| 1520 | +static uint32_t ide_read_config(PCIDevice *d, | |
| 1521 | + uint32_t address, int len) | |
| 1522 | +{ | |
| 1523 | + uint32_t val; | |
| 1524 | + val = 0; | |
| 1525 | + memcpy(&val, d->config + address, len); | |
| 1526 | + return val; | |
| 1527 | +} | |
| 1528 | + | |
| 1529 | +static void ide_write_config(PCIDevice *d, | |
| 1530 | + uint32_t address, uint32_t val, int len) | |
| 1531 | +{ | |
| 1532 | + memcpy(d->config + address, &val, len); | |
| 1533 | +} | |
| 1534 | + | |
| 1535 | +static void ide_map(PCIDevice *pci_dev, int region_num, | |
| 1536 | + uint32_t addr, uint32_t size, int type) | |
| 1537 | +{ | |
| 1538 | + PCIIDEState *d = (PCIIDEState *)pci_dev; | |
| 1539 | + IDEState *ide_state; | |
| 1540 | + | |
| 1541 | + if (region_num <= 3) { | |
| 1542 | + ide_state = &d->ide_if[(region_num >> 1) * 2]; | |
| 1543 | + if (region_num & 1) { | |
| 1544 | + register_ioport_read(addr + 2, 1, 1, ide_status_read, ide_state); | |
| 1545 | + register_ioport_write(addr + 2, 1, 1, ide_cmd_write, ide_state); | |
| 1546 | + } else { | |
| 1547 | + register_ioport_write(addr, 8, 1, ide_ioport_write, ide_state); | |
| 1548 | + register_ioport_read(addr, 8, 1, ide_ioport_read, ide_state); | |
| 1549 | + | |
| 1550 | + /* data ports */ | |
| 1551 | + register_ioport_write(addr, 2, 2, ide_data_writew, ide_state); | |
| 1552 | + register_ioport_read(addr, 2, 2, ide_data_readw, ide_state); | |
| 1553 | + register_ioport_write(addr, 4, 4, ide_data_writel, ide_state); | |
| 1554 | + register_ioport_read(addr, 4, 4, ide_data_readl, ide_state); | |
| 1555 | + } | |
| 1556 | + } | |
| 1557 | +} | |
| 1558 | + | |
| 1559 | +/* hd_table must contain 4 block drivers */ | |
| 1560 | +void pci_ide_init(BlockDriverState **hd_table) | |
| 1561 | +{ | |
| 1562 | + PCIIDEState *d; | |
| 1563 | + uint8_t *pci_conf; | |
| 1564 | + | |
| 1565 | + d = (PCIIDEState *)pci_register_device("IDE", sizeof(PCIIDEState), | |
| 1566 | + 0, -1, | |
| 1567 | + ide_read_config, | |
| 1568 | + ide_write_config); | |
| 1569 | + pci_conf = d->dev.config; | |
| 1570 | + pci_conf[0x00] = 0x86; // Intel | |
| 1571 | + pci_conf[0x01] = 0x80; | |
| 1572 | + pci_conf[0x02] = 0x00; // fake | |
| 1573 | + pci_conf[0x03] = 0x01; // fake | |
| 1574 | + pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE | |
| 1575 | + pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage | |
| 1576 | + pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic | |
| 1577 | + | |
| 1578 | + pci_conf[0x2c] = 0x86; // subsys vendor | |
| 1579 | + pci_conf[0x2d] = 0x80; // subsys vendor | |
| 1580 | + pci_conf[0x2e] = 0x00; // fake | |
| 1581 | + pci_conf[0x2f] = 0x01; // fake | |
| 1582 | + | |
| 1583 | + pci_register_io_region((PCIDevice *)d, 0, 0x8, | |
| 1584 | + PCI_ADDRESS_SPACE_IO, ide_map); | |
| 1585 | + pci_register_io_region((PCIDevice *)d, 1, 0x4, | |
| 1586 | + PCI_ADDRESS_SPACE_IO, ide_map); | |
| 1587 | + pci_register_io_region((PCIDevice *)d, 2, 0x8, | |
| 1588 | + PCI_ADDRESS_SPACE_IO, ide_map); | |
| 1589 | + pci_register_io_region((PCIDevice *)d, 3, 0x4, | |
| 1590 | + PCI_ADDRESS_SPACE_IO, ide_map); | |
| 1591 | + | |
| 1592 | + ide_init2(&d->ide_if[0], 14, hd_table[0], hd_table[1]); | |
| 1593 | + ide_init2(&d->ide_if[2], 15, hd_table[2], hd_table[3]); | |
| 1594 | +} | ... | ... |
hw/ne2000.c
| ... | ... | @@ -368,7 +368,7 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) |
| 368 | 368 | } |
| 369 | 369 | |
| 370 | 370 | static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr, |
| 371 | - uint32_t val) | |
| 371 | + uint32_t val) | |
| 372 | 372 | { |
| 373 | 373 | if (addr < 32 || |
| 374 | 374 | (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { |
| ... | ... | @@ -382,8 +382,17 @@ static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr, |
| 382 | 382 | addr &= ~1; /* XXX: check exact behaviour if not even */ |
| 383 | 383 | if (addr < 32 || |
| 384 | 384 | (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { |
| 385 | - s->mem[addr] = val; | |
| 386 | - s->mem[addr + 1] = val >> 8; | |
| 385 | + *(uint16_t *)(s->mem + addr) = cpu_to_le16(val); | |
| 386 | + } | |
| 387 | +} | |
| 388 | + | |
| 389 | +static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr, | |
| 390 | + uint32_t val) | |
| 391 | +{ | |
| 392 | + addr &= ~3; /* XXX: check exact behaviour if not even */ | |
| 393 | + if (addr < 32 || | |
| 394 | + (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { | |
| 395 | + *(uint32_t *)(s->mem + addr) = cpu_to_le32(val); | |
| 387 | 396 | } |
| 388 | 397 | } |
| 389 | 398 | |
| ... | ... | @@ -402,12 +411,23 @@ static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr) |
| 402 | 411 | addr &= ~1; /* XXX: check exact behaviour if not even */ |
| 403 | 412 | if (addr < 32 || |
| 404 | 413 | (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { |
| 405 | - return s->mem[addr] | (s->mem[addr + 1] << 8); | |
| 414 | + return le16_to_cpu(*(uint16_t *)(s->mem + addr)); | |
| 406 | 415 | } else { |
| 407 | 416 | return 0xffff; |
| 408 | 417 | } |
| 409 | 418 | } |
| 410 | 419 | |
| 420 | +static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr) | |
| 421 | +{ | |
| 422 | + addr &= ~3; /* XXX: check exact behaviour if not even */ | |
| 423 | + if (addr < 32 || | |
| 424 | + (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { | |
| 425 | + return le32_to_cpu(*(uint32_t *)(s->mem + addr)); | |
| 426 | + } else { | |
| 427 | + return 0xffffffff; | |
| 428 | + } | |
| 429 | +} | |
| 430 | + | |
| 411 | 431 | static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 412 | 432 | { |
| 413 | 433 | NE2000State *s = opaque; |
| ... | ... | @@ -468,6 +488,53 @@ static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr) |
| 468 | 488 | return ret; |
| 469 | 489 | } |
| 470 | 490 | |
| 491 | +static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val) | |
| 492 | +{ | |
| 493 | + NE2000State *s = opaque; | |
| 494 | + | |
| 495 | +#ifdef DEBUG_NE2000 | |
| 496 | + printf("NE2000: asic writel val=0x%04x\n", val); | |
| 497 | +#endif | |
| 498 | + if (s->rcnt == 0) | |
| 499 | + return; | |
| 500 | + /* 32 bit access */ | |
| 501 | + ne2000_mem_writel(s, s->rsar, val); | |
| 502 | + s->rsar += 4; | |
| 503 | + s->rcnt -= 4; | |
| 504 | + /* wrap */ | |
| 505 | + if (s->rsar == s->stop) | |
| 506 | + s->rsar = s->start; | |
| 507 | + if (s->rcnt == 0) { | |
| 508 | + /* signal end of transfert */ | |
| 509 | + s->isr |= ENISR_RDC; | |
| 510 | + ne2000_update_irq(s); | |
| 511 | + } | |
| 512 | +} | |
| 513 | + | |
| 514 | +static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr) | |
| 515 | +{ | |
| 516 | + NE2000State *s = opaque; | |
| 517 | + int ret; | |
| 518 | + | |
| 519 | + /* 32 bit access */ | |
| 520 | + ret = ne2000_mem_readl(s, s->rsar); | |
| 521 | + s->rsar += 4; | |
| 522 | + s->rcnt -= 4; | |
| 523 | + | |
| 524 | + /* wrap */ | |
| 525 | + if (s->rsar == s->stop) | |
| 526 | + s->rsar = s->start; | |
| 527 | + if (s->rcnt == 0) { | |
| 528 | + /* signal end of transfert */ | |
| 529 | + s->isr |= ENISR_RDC; | |
| 530 | + ne2000_update_irq(s); | |
| 531 | + } | |
| 532 | +#ifdef DEBUG_NE2000 | |
| 533 | + printf("NE2000: asic readl val=0x%04x\n", ret); | |
| 534 | +#endif | |
| 535 | + return ret; | |
| 536 | +} | |
| 537 | + | |
| 471 | 538 | static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
| 472 | 539 | { |
| 473 | 540 | /* nothing to do (end of reset pulse) */ |
| ... | ... | @@ -480,7 +547,7 @@ static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr) |
| 480 | 547 | return 0; |
| 481 | 548 | } |
| 482 | 549 | |
| 483 | -void ne2000_init(int base, int irq, NetDriverState *nd) | |
| 550 | +void isa_ne2000_init(int base, int irq, NetDriverState *nd) | |
| 484 | 551 | { |
| 485 | 552 | NE2000State *s; |
| 486 | 553 | |
| ... | ... | @@ -505,3 +572,78 @@ void ne2000_init(int base, int irq, NetDriverState *nd) |
| 505 | 572 | |
| 506 | 573 | qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); |
| 507 | 574 | } |
| 575 | + | |
| 576 | +/***********************************************************/ | |
| 577 | +/* PCI NE2000 definitions */ | |
| 578 | + | |
| 579 | +typedef struct PCINE2000State { | |
| 580 | + PCIDevice dev; | |
| 581 | + NE2000State ne2000; | |
| 582 | +} PCINE2000State; | |
| 583 | + | |
| 584 | +static uint32_t ne2000_read_config(PCIDevice *d, | |
| 585 | + uint32_t address, int len) | |
| 586 | +{ | |
| 587 | + uint32_t val; | |
| 588 | + val = 0; | |
| 589 | + memcpy(&val, d->config + address, len); | |
| 590 | + return val; | |
| 591 | +} | |
| 592 | + | |
| 593 | +static void ne2000_write_config(PCIDevice *d, | |
| 594 | + uint32_t address, uint32_t val, int len) | |
| 595 | +{ | |
| 596 | + memcpy(d->config + address, &val, len); | |
| 597 | +} | |
| 598 | + | |
| 599 | +static void ne2000_map(PCIDevice *pci_dev, int region_num, | |
| 600 | + uint32_t addr, uint32_t size, int type) | |
| 601 | +{ | |
| 602 | + PCINE2000State *d = (PCINE2000State *)pci_dev; | |
| 603 | + NE2000State *s = &d->ne2000; | |
| 604 | + | |
| 605 | + register_ioport_write(addr, 16, 1, ne2000_ioport_write, s); | |
| 606 | + register_ioport_read(addr, 16, 1, ne2000_ioport_read, s); | |
| 607 | + | |
| 608 | + register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s); | |
| 609 | + register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s); | |
| 610 | + register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s); | |
| 611 | + register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s); | |
| 612 | + register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s); | |
| 613 | + register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s); | |
| 614 | + | |
| 615 | + register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s); | |
| 616 | + register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); | |
| 617 | +} | |
| 618 | + | |
| 619 | +void pci_ne2000_init(NetDriverState *nd) | |
| 620 | +{ | |
| 621 | + PCINE2000State *d; | |
| 622 | + NE2000State *s; | |
| 623 | + uint8_t *pci_conf; | |
| 624 | + | |
| 625 | + d = (PCINE2000State *)pci_register_device("NE2000", sizeof(PCINE2000State), | |
| 626 | + 0, -1, | |
| 627 | + ne2000_read_config, | |
| 628 | + ne2000_write_config); | |
| 629 | + pci_conf = d->dev.config; | |
| 630 | + pci_conf[0x00] = 0xec; // Realtek 8029 | |
| 631 | + pci_conf[0x01] = 0x10; | |
| 632 | + pci_conf[0x02] = 0x29; | |
| 633 | + pci_conf[0x03] = 0x80; | |
| 634 | + pci_conf[0x0a] = 0x00; // ethernet network controller | |
| 635 | + pci_conf[0x0b] = 0x02; | |
| 636 | + pci_conf[0x0e] = 0x00; // header_type | |
| 637 | + | |
| 638 | + /* XXX: do that in the BIOS */ | |
| 639 | + pci_conf[0x3c] = 11; // interrupt line | |
| 640 | + pci_conf[0x3d] = 1; // interrupt pin | |
| 641 | + | |
| 642 | + pci_register_io_region((PCIDevice *)d, 0, 0x100, | |
| 643 | + PCI_ADDRESS_SPACE_IO, ne2000_map); | |
| 644 | + s = &d->ne2000; | |
| 645 | + s->irq = 11; | |
| 646 | + s->nd = nd; | |
| 647 | + ne2000_reset(s); | |
| 648 | + qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); | |
| 649 | +} | ... | ... |
hw/pc.c
| ... | ... | @@ -380,6 +380,11 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, |
| 380 | 380 | stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); |
| 381 | 381 | } |
| 382 | 382 | |
| 383 | + if (pci_enabled) { | |
| 384 | + i440fx_init(); | |
| 385 | + piix3_init(); | |
| 386 | + } | |
| 387 | + | |
| 383 | 388 | /* init basic PC hardware */ |
| 384 | 389 | register_ioport_write(0x80, 1, 1, ioport80_write, NULL); |
| 385 | 390 | |
| ... | ... | @@ -401,17 +406,25 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, |
| 401 | 406 | fd = serial_open_device(); |
| 402 | 407 | serial_init(0x3f8, 4, fd); |
| 403 | 408 | |
| 404 | - nb_nics1 = nb_nics; | |
| 405 | - if (nb_nics1 > NE2000_NB_MAX) | |
| 406 | - nb_nics1 = NE2000_NB_MAX; | |
| 407 | - for(i = 0; i < nb_nics1; i++) { | |
| 408 | - ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); | |
| 409 | - } | |
| 409 | + if (pci_enabled) { | |
| 410 | + for(i = 0; i < nb_nics; i++) { | |
| 411 | + pci_ne2000_init(&nd_table[i]); | |
| 412 | + } | |
| 413 | + pci_ide_init(bs_table); | |
| 414 | + } else { | |
| 415 | + nb_nics1 = nb_nics; | |
| 416 | + if (nb_nics1 > NE2000_NB_MAX) | |
| 417 | + nb_nics1 = NE2000_NB_MAX; | |
| 418 | + for(i = 0; i < nb_nics1; i++) { | |
| 419 | + isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); | |
| 420 | + } | |
| 410 | 421 | |
| 411 | - for(i = 0; i < 2; i++) { | |
| 412 | - ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], | |
| 413 | - bs_table[2 * i], bs_table[2 * i + 1]); | |
| 422 | + for(i = 0; i < 2; i++) { | |
| 423 | + isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], | |
| 424 | + bs_table[2 * i], bs_table[2 * i + 1]); | |
| 425 | + } | |
| 414 | 426 | } |
| 427 | + | |
| 415 | 428 | kbd_init(); |
| 416 | 429 | DMA_init(); |
| 417 | 430 | |
| ... | ... | @@ -426,4 +439,10 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, |
| 426 | 439 | floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); |
| 427 | 440 | |
| 428 | 441 | cmos_init(ram_size, boot_device); |
| 442 | + | |
| 443 | + /* must be done after all PCI devices are instanciated */ | |
| 444 | + /* XXX: should be done in the Bochs BIOS */ | |
| 445 | + if (pci_enabled) { | |
| 446 | + pci_bios_init(); | |
| 447 | + } | |
| 429 | 448 | } | ... | ... |
hw/pci.c
0 โ 100644
| 1 | +/* | |
| 2 | + * QEMU PCI bus manager | |
| 3 | + * | |
| 4 | + * Copyright (c) 2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include "vl.h" | |
| 25 | + | |
| 26 | +//#define DEBUG_PCI | |
| 27 | + | |
| 28 | +typedef struct PCIBridge { | |
| 29 | + uint32_t config_reg; | |
| 30 | + PCIDevice **pci_bus[256]; | |
| 31 | +} PCIBridge; | |
| 32 | + | |
| 33 | +static PCIBridge pci_bridge; | |
| 34 | +target_phys_addr_t pci_mem_base; | |
| 35 | + | |
| 36 | +/* -1 for devfn means auto assign */ | |
| 37 | +PCIDevice *pci_register_device(const char *name, int instance_size, | |
| 38 | + int bus_num, int devfn, | |
| 39 | + PCIConfigReadFunc *config_read, | |
| 40 | + PCIConfigWriteFunc *config_write) | |
| 41 | +{ | |
| 42 | + PCIBridge *s = &pci_bridge; | |
| 43 | + PCIDevice *pci_dev, **bus; | |
| 44 | + | |
| 45 | + if (!s->pci_bus[bus_num]) { | |
| 46 | + s->pci_bus[bus_num] = qemu_mallocz(256 * sizeof(PCIDevice *)); | |
| 47 | + if (!s->pci_bus[bus_num]) | |
| 48 | + return NULL; | |
| 49 | + } | |
| 50 | + bus = s->pci_bus[bus_num]; | |
| 51 | + if (devfn < 0) { | |
| 52 | + for(devfn = 0 ; devfn < 256; devfn += 8) { | |
| 53 | + if (!bus[devfn]) | |
| 54 | + goto found; | |
| 55 | + } | |
| 56 | + return NULL; | |
| 57 | + found: ; | |
| 58 | + } | |
| 59 | + pci_dev = qemu_mallocz(instance_size); | |
| 60 | + if (!pci_dev) | |
| 61 | + return NULL; | |
| 62 | + pci_dev->bus_num = bus_num; | |
| 63 | + pci_dev->devfn = devfn; | |
| 64 | + pstrcpy(pci_dev->name, sizeof(pci_dev->name), name); | |
| 65 | + pci_dev->config_read = config_read; | |
| 66 | + pci_dev->config_write = config_write; | |
| 67 | + bus[devfn] = pci_dev; | |
| 68 | + return pci_dev; | |
| 69 | +} | |
| 70 | + | |
| 71 | +void pci_register_io_region(PCIDevice *pci_dev, int region_num, | |
| 72 | + uint32_t size, int type, | |
| 73 | + PCIMapIORegionFunc *map_func) | |
| 74 | +{ | |
| 75 | + PCIIORegion *r; | |
| 76 | + | |
| 77 | + if ((unsigned int)region_num >= 6) | |
| 78 | + return; | |
| 79 | + r = &pci_dev->io_regions[region_num]; | |
| 80 | + r->addr = -1; | |
| 81 | + r->size = size; | |
| 82 | + r->type = type; | |
| 83 | + r->map_func = map_func; | |
| 84 | +} | |
| 85 | + | |
| 86 | +static void pci_config_writel(void* opaque, uint32_t addr, uint32_t val) | |
| 87 | +{ | |
| 88 | + PCIBridge *s = opaque; | |
| 89 | + s->config_reg = val; | |
| 90 | +} | |
| 91 | + | |
| 92 | +static uint32_t pci_config_readl(void* opaque, uint32_t addr) | |
| 93 | +{ | |
| 94 | + PCIBridge *s = opaque; | |
| 95 | + return s->config_reg; | |
| 96 | +} | |
| 97 | + | |
| 98 | +static void unmap_region(PCIIORegion *r) | |
| 99 | +{ | |
| 100 | + if (r->addr == -1) | |
| 101 | + return; | |
| 102 | +#ifdef DEBUG_PCI | |
| 103 | + printf("unmap addr=%08x size=%08x\n", r->addr, r->size); | |
| 104 | +#endif | |
| 105 | + if (r->type & PCI_ADDRESS_SPACE_IO) { | |
| 106 | + isa_unassign_ioport(r->addr, r->size); | |
| 107 | + } else { | |
| 108 | + cpu_register_physical_memory(r->addr + pci_mem_base, r->size, | |
| 109 | + IO_MEM_UNASSIGNED); | |
| 110 | + } | |
| 111 | +} | |
| 112 | + | |
| 113 | +static void pci_data_write(void *opaque, uint32_t addr, | |
| 114 | + uint32_t val, int len) | |
| 115 | +{ | |
| 116 | + PCIBridge *s = opaque; | |
| 117 | + PCIDevice **bus, *pci_dev; | |
| 118 | + int config_addr, reg; | |
| 119 | + | |
| 120 | +#if defined(DEBUG_PCI) && 0 | |
| 121 | + printf("pci_data_write: addr=%08x val=%08x len=%d\n", | |
| 122 | + s->config_reg, val, len); | |
| 123 | +#endif | |
| 124 | + if (!(s->config_reg & (1 << 31))) { | |
| 125 | + return; | |
| 126 | + } | |
| 127 | + if ((s->config_reg & 0x3) != 0) { | |
| 128 | + return; | |
| 129 | + } | |
| 130 | + bus = s->pci_bus[(s->config_reg >> 16) & 0xff]; | |
| 131 | + if (!bus) | |
| 132 | + return; | |
| 133 | + pci_dev = bus[(s->config_reg >> 8) & 0xff]; | |
| 134 | + if (!pci_dev) | |
| 135 | + return; | |
| 136 | + config_addr = (s->config_reg & 0xfc) | (addr & 3); | |
| 137 | + | |
| 138 | +#if defined(DEBUG_PCI) | |
| 139 | + printf("pci_config_write: %s: addr=%02x val=%08x len=%d\n", | |
| 140 | + pci_dev->name, config_addr, val, len); | |
| 141 | +#endif | |
| 142 | + if (len == 4 && (config_addr >= 0x10 && config_addr < 0x10 + 4 * 6)) { | |
| 143 | + PCIIORegion *r; | |
| 144 | + reg = (config_addr - 0x10) >> 2; | |
| 145 | + r = &pci_dev->io_regions[reg]; | |
| 146 | + if (r->size == 0) | |
| 147 | + goto default_config; | |
| 148 | + if (val != 0xffffffff && val != 0) { | |
| 149 | + /* XXX: the memory assignment should be global to handle | |
| 150 | + overlaps, but it is not needed at this stage */ | |
| 151 | + /* first unmap the old region */ | |
| 152 | + unmap_region(r); | |
| 153 | + /* change the address */ | |
| 154 | + if (r->type & PCI_ADDRESS_SPACE_IO) | |
| 155 | + r->addr = val & ~0x3; | |
| 156 | + else | |
| 157 | + r->addr = val & ~0xf; | |
| 158 | +#ifdef DEBUG_PCI | |
| 159 | + printf("map addr=%08x size=%08x type=%d\n", | |
| 160 | + r->addr, r->size, r->type); | |
| 161 | +#endif | |
| 162 | + r->map_func(pci_dev, reg, r->addr, r->size, r->type); | |
| 163 | + } | |
| 164 | + /* now compute the stored value */ | |
| 165 | + val &= ~(r->size - 1); | |
| 166 | + val |= r->type; | |
| 167 | + *(uint32_t *)(pci_dev->config + 0x10 + reg * 4) = cpu_to_le32(val); | |
| 168 | + } else { | |
| 169 | + default_config: | |
| 170 | + pci_dev->config_write(pci_dev, config_addr, val, len); | |
| 171 | + } | |
| 172 | +} | |
| 173 | + | |
| 174 | +static uint32_t pci_data_read(void *opaque, uint32_t addr, | |
| 175 | + int len) | |
| 176 | +{ | |
| 177 | + PCIBridge *s = opaque; | |
| 178 | + PCIDevice **bus, *pci_dev; | |
| 179 | + int config_addr; | |
| 180 | + uint32_t val; | |
| 181 | + | |
| 182 | + if (!(s->config_reg & (1 << 31))) | |
| 183 | + goto fail; | |
| 184 | + if ((s->config_reg & 0x3) != 0) | |
| 185 | + goto fail; | |
| 186 | + bus = s->pci_bus[(s->config_reg >> 16) & 0xff]; | |
| 187 | + if (!bus) | |
| 188 | + goto fail; | |
| 189 | + pci_dev = bus[(s->config_reg >> 8) & 0xff]; | |
| 190 | + if (!pci_dev) { | |
| 191 | + fail: | |
| 192 | + val = 0; | |
| 193 | + goto the_end; | |
| 194 | + } | |
| 195 | + config_addr = (s->config_reg & 0xfc) | (addr & 3); | |
| 196 | + val = pci_dev->config_read(pci_dev, config_addr, len); | |
| 197 | +#if defined(DEBUG_PCI) | |
| 198 | + printf("pci_config_read: %s: addr=%02x val=%08x len=%d\n", | |
| 199 | + pci_dev->name, config_addr, val, len); | |
| 200 | +#endif | |
| 201 | + the_end: | |
| 202 | +#if defined(DEBUG_PCI) && 0 | |
| 203 | + printf("pci_data_read: addr=%08x val=%08x len=%d\n", | |
| 204 | + s->config_reg, val, len); | |
| 205 | +#endif | |
| 206 | + return val; | |
| 207 | +} | |
| 208 | + | |
| 209 | +static void pci_data_writeb(void* opaque, uint32_t addr, uint32_t val) | |
| 210 | +{ | |
| 211 | + pci_data_write(opaque, addr, val, 1); | |
| 212 | +} | |
| 213 | + | |
| 214 | +static void pci_data_writew(void* opaque, uint32_t addr, uint32_t val) | |
| 215 | +{ | |
| 216 | + pci_data_write(opaque, addr, val, 2); | |
| 217 | +} | |
| 218 | + | |
| 219 | +static void pci_data_writel(void* opaque, uint32_t addr, uint32_t val) | |
| 220 | +{ | |
| 221 | + pci_data_write(opaque, addr, val, 4); | |
| 222 | +} | |
| 223 | + | |
| 224 | +static uint32_t pci_data_readb(void* opaque, uint32_t addr) | |
| 225 | +{ | |
| 226 | + return pci_data_read(opaque, addr, 1); | |
| 227 | +} | |
| 228 | + | |
| 229 | +static uint32_t pci_data_readw(void* opaque, uint32_t addr) | |
| 230 | +{ | |
| 231 | + return pci_data_read(opaque, addr, 2); | |
| 232 | +} | |
| 233 | + | |
| 234 | +static uint32_t pci_data_readl(void* opaque, uint32_t addr) | |
| 235 | +{ | |
| 236 | + return pci_data_read(opaque, addr, 4); | |
| 237 | +} | |
| 238 | + | |
| 239 | +/* i440FX PCI bridge */ | |
| 240 | + | |
| 241 | +static uint32_t i440_read_config(PCIDevice *d, | |
| 242 | + uint32_t address, int len) | |
| 243 | +{ | |
| 244 | + uint32_t val; | |
| 245 | + val = 0; | |
| 246 | + memcpy(&val, d->config + address, len); | |
| 247 | + return val; | |
| 248 | +} | |
| 249 | + | |
| 250 | +static void i440_write_config(PCIDevice *d, | |
| 251 | + uint32_t address, uint32_t val, int len) | |
| 252 | +{ | |
| 253 | + memcpy(d->config + address, &val, len); | |
| 254 | +} | |
| 255 | + | |
| 256 | +void i440fx_init(void) | |
| 257 | +{ | |
| 258 | + PCIBridge *s = &pci_bridge; | |
| 259 | + PCIDevice *d; | |
| 260 | + | |
| 261 | + register_ioport_write(0xcf8, 4, 4, pci_config_writel, s); | |
| 262 | + register_ioport_read(0xcf8, 4, 4, pci_config_readl, s); | |
| 263 | + | |
| 264 | + register_ioport_write(0xcfc, 4, 1, pci_data_writeb, s); | |
| 265 | + register_ioport_write(0xcfc, 4, 2, pci_data_writew, s); | |
| 266 | + register_ioport_write(0xcfc, 4, 4, pci_data_writel, s); | |
| 267 | + register_ioport_read(0xcfc, 4, 1, pci_data_readb, s); | |
| 268 | + register_ioport_read(0xcfc, 4, 2, pci_data_readw, s); | |
| 269 | + register_ioport_read(0xcfc, 4, 4, pci_data_readl, s); | |
| 270 | + | |
| 271 | + d = pci_register_device("i440FX", sizeof(PCIDevice), 0, 0, | |
| 272 | + i440_read_config, i440_write_config); | |
| 273 | + | |
| 274 | + d->config[0x00] = 0x86; // vendor_id | |
| 275 | + d->config[0x01] = 0x80; | |
| 276 | + d->config[0x02] = 0x37; // device_id | |
| 277 | + d->config[0x03] = 0x12; | |
| 278 | + d->config[0x08] = 0x02; // revision | |
| 279 | + d->config[0x0a] = 0x04; // class_sub = pci2pci | |
| 280 | + d->config[0x0b] = 0x06; // class_base = PCI_bridge | |
| 281 | + d->config[0x0c] = 0x01; // line_size in 32 bit words | |
| 282 | + d->config[0x0e] = 0x01; // header_type | |
| 283 | +} | |
| 284 | + | |
| 285 | +/* NOTE: the following should be done by the BIOS */ | |
| 286 | + | |
| 287 | +static uint32_t pci_bios_io_addr; | |
| 288 | +static uint32_t pci_bios_mem_addr; | |
| 289 | + | |
| 290 | +static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr) | |
| 291 | +{ | |
| 292 | + PCIBridge *s = &pci_bridge; | |
| 293 | + PCIIORegion *r; | |
| 294 | + | |
| 295 | + s->config_reg = 0x80000000 | (d->bus_num << 16) | | |
| 296 | + (d->devfn << 8) | (0x10 + region_num * 4); | |
| 297 | + pci_data_write(s, 0, addr, 4); | |
| 298 | + r = &d->io_regions[region_num]; | |
| 299 | + | |
| 300 | + /* enable memory mappings */ | |
| 301 | + if (r->type & PCI_ADDRESS_SPACE_IO) | |
| 302 | + d->config[0x04] |= 1; | |
| 303 | + else | |
| 304 | + d->config[0x04] |= 2; | |
| 305 | +} | |
| 306 | + | |
| 307 | + | |
| 308 | +static void pci_bios_init_device(PCIDevice *d) | |
| 309 | +{ | |
| 310 | + int class; | |
| 311 | + PCIIORegion *r; | |
| 312 | + uint32_t *paddr; | |
| 313 | + int i; | |
| 314 | + | |
| 315 | + class = d->config[0x0a] | (d->config[0x0b] << 8); | |
| 316 | + switch(class) { | |
| 317 | + case 0x0101: | |
| 318 | + /* IDE: we map it as in ISA mode */ | |
| 319 | + pci_set_io_region_addr(d, 0, 0x1f0); | |
| 320 | + pci_set_io_region_addr(d, 1, 0x3f4); | |
| 321 | + pci_set_io_region_addr(d, 2, 0x170); | |
| 322 | + pci_set_io_region_addr(d, 3, 0x374); | |
| 323 | + break; | |
| 324 | + default: | |
| 325 | + /* default memory mappings */ | |
| 326 | + for(i = 0; i < 6; i++) { | |
| 327 | + r = &d->io_regions[i]; | |
| 328 | + if (r->size) { | |
| 329 | + if (r->type & PCI_ADDRESS_SPACE_IO) | |
| 330 | + paddr = &pci_bios_io_addr; | |
| 331 | + else | |
| 332 | + paddr = &pci_bios_mem_addr; | |
| 333 | + *paddr = (*paddr + r->size - 1) & ~(r->size - 1); | |
| 334 | + pci_set_io_region_addr(d, i, *paddr); | |
| 335 | + *paddr += r->size; | |
| 336 | + } | |
| 337 | + } | |
| 338 | + break; | |
| 339 | + } | |
| 340 | +} | |
| 341 | + | |
| 342 | +/* | |
| 343 | + * This function initializes the PCI devices as a normal PCI BIOS | |
| 344 | + * would do. It is provided just in case the BIOS has no support for | |
| 345 | + * PCI. | |
| 346 | + */ | |
| 347 | +void pci_bios_init(void) | |
| 348 | +{ | |
| 349 | + PCIBridge *s = &pci_bridge; | |
| 350 | + PCIDevice **bus; | |
| 351 | + int bus_num, devfn; | |
| 352 | + | |
| 353 | + pci_bios_io_addr = 0xc000; | |
| 354 | + pci_bios_mem_addr = 0xf0000000; | |
| 355 | + | |
| 356 | + for(bus_num = 0; bus_num < 256; bus_num++) { | |
| 357 | + bus = s->pci_bus[bus_num]; | |
| 358 | + if (bus) { | |
| 359 | + for(devfn = 0; devfn < 256; devfn++) { | |
| 360 | + if (bus[devfn]) | |
| 361 | + pci_bios_init_device(bus[devfn]); | |
| 362 | + } | |
| 363 | + } | |
| 364 | + } | |
| 365 | +} | |
| 366 | + | |
| 367 | + | ... | ... |
hw/pci2isa.c
0 โ 100644
| 1 | +/* | |
| 2 | + * QEMU PCI to ISA bridge | |
| 3 | + * | |
| 4 | + * Copyright (c) 2004 Fabrice Bellard | |
| 5 | + * | |
| 6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | + * of this software and associated documentation files (the "Software"), to deal | |
| 8 | + * in the Software without restriction, including without limitation the rights | |
| 9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | + * copies of the Software, and to permit persons to whom the Software is | |
| 11 | + * furnished to do so, subject to the following conditions: | |
| 12 | + * | |
| 13 | + * The above copyright notice and this permission notice shall be included in | |
| 14 | + * all copies or substantial portions of the Software. | |
| 15 | + * | |
| 16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | + * THE SOFTWARE. | |
| 23 | + */ | |
| 24 | +#include "vl.h" | |
| 25 | + | |
| 26 | +//#define DEBUG_PCI | |
| 27 | + | |
| 28 | +typedef struct PIIX3State { | |
| 29 | + PCIDevice dev; | |
| 30 | + uint8_t elcr1; | |
| 31 | + uint8_t elcr2; | |
| 32 | +} PIIX3State; | |
| 33 | + | |
| 34 | +static void piix3_reset(PIIX3State *d) | |
| 35 | +{ | |
| 36 | + uint8_t *pci_conf = d->dev.config; | |
| 37 | + | |
| 38 | + pci_conf[0x04] = 0x07; // master, memory and I/O | |
| 39 | + pci_conf[0x05] = 0x00; | |
| 40 | + pci_conf[0x06] = 0x00; | |
| 41 | + pci_conf[0x07] = 0x02; // PCI_status_devsel_medium | |
| 42 | + pci_conf[0x4c] = 0x4d; | |
| 43 | + pci_conf[0x4e] = 0x03; | |
| 44 | + pci_conf[0x4f] = 0x00; | |
| 45 | + pci_conf[0x60] = 0x80; | |
| 46 | + pci_conf[0x69] = 0x02; | |
| 47 | + pci_conf[0x70] = 0x80; | |
| 48 | + pci_conf[0x76] = 0x0c; | |
| 49 | + pci_conf[0x77] = 0x0c; | |
| 50 | + pci_conf[0x78] = 0x02; | |
| 51 | + pci_conf[0x79] = 0x00; | |
| 52 | + pci_conf[0x80] = 0x00; | |
| 53 | + pci_conf[0x82] = 0x00; | |
| 54 | + pci_conf[0xa0] = 0x08; | |
| 55 | + pci_conf[0xa0] = 0x08; | |
| 56 | + pci_conf[0xa2] = 0x00; | |
| 57 | + pci_conf[0xa3] = 0x00; | |
| 58 | + pci_conf[0xa4] = 0x00; | |
| 59 | + pci_conf[0xa5] = 0x00; | |
| 60 | + pci_conf[0xa6] = 0x00; | |
| 61 | + pci_conf[0xa7] = 0x00; | |
| 62 | + pci_conf[0xa8] = 0x0f; | |
| 63 | + pci_conf[0xaa] = 0x00; | |
| 64 | + pci_conf[0xab] = 0x00; | |
| 65 | + pci_conf[0xac] = 0x00; | |
| 66 | + pci_conf[0xae] = 0x00; | |
| 67 | + | |
| 68 | + d->elcr1 = 0x00; | |
| 69 | + d->elcr2 = 0x00; | |
| 70 | +} | |
| 71 | + | |
| 72 | +static uint32_t piix3_read_config(PCIDevice *d, | |
| 73 | + uint32_t address, int len) | |
| 74 | +{ | |
| 75 | + uint32_t val; | |
| 76 | + val = 0; | |
| 77 | + memcpy(&val, d->config + address, len); | |
| 78 | + return val; | |
| 79 | +} | |
| 80 | + | |
| 81 | +static void piix3_write_config(PCIDevice *d, | |
| 82 | + uint32_t address, uint32_t val, int len) | |
| 83 | +{ | |
| 84 | + memcpy(d->config + address, &val, len); | |
| 85 | +} | |
| 86 | + | |
| 87 | +void piix3_init(void) | |
| 88 | +{ | |
| 89 | + PIIX3State *d; | |
| 90 | + uint8_t *pci_conf; | |
| 91 | + | |
| 92 | + d = (PIIX3State *)pci_register_device("PIIX3", sizeof(PIIX3State), | |
| 93 | + 0, -1, | |
| 94 | + piix3_read_config, | |
| 95 | + piix3_write_config); | |
| 96 | + pci_conf = d->dev.config; | |
| 97 | + | |
| 98 | + pci_conf[0x00] = 0x86; // Intel | |
| 99 | + pci_conf[0x01] = 0x80; | |
| 100 | + pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) | |
| 101 | + pci_conf[0x03] = 0x70; | |
| 102 | + pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA | |
| 103 | + pci_conf[0x0b] = 0x06; // class_base = PCI_bridge | |
| 104 | + pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic | |
| 105 | + | |
| 106 | + piix3_reset(d); | |
| 107 | +} | ... | ... |
hw/ppc_prep.c
| ... | ... | @@ -962,13 +962,13 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, |
| 962 | 962 | if (nb_nics1 > NE2000_NB_MAX) |
| 963 | 963 | nb_nics1 = NE2000_NB_MAX; |
| 964 | 964 | for(i = 0; i < nb_nics1; i++) { |
| 965 | - ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); | |
| 965 | + isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); | |
| 966 | 966 | } |
| 967 | 967 | #endif |
| 968 | 968 | |
| 969 | 969 | for(i = 0; i < 2; i++) { |
| 970 | - ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], | |
| 971 | - bs_table[2 * i], bs_table[2 * i + 1]); | |
| 970 | + isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], | |
| 971 | + bs_table[2 * i], bs_table[2 * i + 1]); | |
| 972 | 972 | } |
| 973 | 973 | kbd_init(); |
| 974 | 974 | AUD_init(); | ... | ... |
vl.c
| ... | ... | @@ -121,6 +121,7 @@ SerialState *serial_console; |
| 121 | 121 | QEMUTimer *gui_timer; |
| 122 | 122 | int vm_running; |
| 123 | 123 | int audio_enabled = 0; |
| 124 | +int pci_enabled = 0; | |
| 124 | 125 | |
| 125 | 126 | /***********************************************************/ |
| 126 | 127 | /* x86 ISA bus support */ |
| ... | ... | @@ -238,6 +239,21 @@ int register_ioport_write(int start, int length, int size, |
| 238 | 239 | return 0; |
| 239 | 240 | } |
| 240 | 241 | |
| 242 | +void isa_unassign_ioport(int start, int length) | |
| 243 | +{ | |
| 244 | + int i; | |
| 245 | + | |
| 246 | + for(i = start; i < start + length; i++) { | |
| 247 | + ioport_read_table[0][i] = default_ioport_readb; | |
| 248 | + ioport_read_table[1][i] = default_ioport_readw; | |
| 249 | + ioport_read_table[2][i] = default_ioport_readl; | |
| 250 | + | |
| 251 | + ioport_write_table[0][i] = default_ioport_writeb; | |
| 252 | + ioport_write_table[1][i] = default_ioport_writew; | |
| 253 | + ioport_write_table[2][i] = default_ioport_writel; | |
| 254 | + } | |
| 255 | +} | |
| 256 | + | |
| 241 | 257 | void pstrcpy(char *buf, int buf_size, const char *str) |
| 242 | 258 | { |
| 243 | 259 | int c; |
| ... | ... | @@ -1973,6 +1989,7 @@ enum { |
| 1973 | 1989 | QEMU_OPTION_hdachs, |
| 1974 | 1990 | QEMU_OPTION_L, |
| 1975 | 1991 | QEMU_OPTION_no_code_copy, |
| 1992 | + QEMU_OPTION_pci, | |
| 1976 | 1993 | }; |
| 1977 | 1994 | |
| 1978 | 1995 | typedef struct QEMUOption { |
| ... | ... | @@ -1999,7 +2016,7 @@ const QEMUOption qemu_options[] = { |
| 1999 | 2016 | |
| 2000 | 2017 | { "nics", HAS_ARG, QEMU_OPTION_nics}, |
| 2001 | 2018 | { "macaddr", HAS_ARG, QEMU_OPTION_macaddr}, |
| 2002 | - { "n", HAS_ARG, QEMU_OPTION_d }, | |
| 2019 | + { "n", HAS_ARG, QEMU_OPTION_n }, | |
| 2003 | 2020 | { "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd }, |
| 2004 | 2021 | #ifdef CONFIG_SLIRP |
| 2005 | 2022 | { "user-net", 0, QEMU_OPTION_user_net }, |
| ... | ... | @@ -2017,6 +2034,7 @@ const QEMUOption qemu_options[] = { |
| 2017 | 2034 | { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, |
| 2018 | 2035 | { "L", HAS_ARG, QEMU_OPTION_L }, |
| 2019 | 2036 | { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, |
| 2037 | + { "pci", 0, QEMU_OPTION_pci }, | |
| 2020 | 2038 | { NULL }, |
| 2021 | 2039 | }; |
| 2022 | 2040 | |
| ... | ... | @@ -2286,6 +2304,9 @@ int main(int argc, char **argv) |
| 2286 | 2304 | case QEMU_OPTION_S: |
| 2287 | 2305 | start_emulation = 0; |
| 2288 | 2306 | break; |
| 2307 | + case QEMU_OPTION_pci: | |
| 2308 | + pci_enabled = 1; | |
| 2309 | + break; | |
| 2289 | 2310 | } |
| 2290 | 2311 | } |
| 2291 | 2312 | } | ... | ... |
vl.h
| ... | ... | @@ -218,7 +218,7 @@ typedef void QEMUTimerCB(void *opaque); |
| 218 | 218 | |
| 219 | 219 | /* The real time clock should be used only for stuff which does not |
| 220 | 220 | change the virtual machine state, as it is run even if the virtual |
| 221 | - machine is stopped. The real time clock has a frequency or 1000 | |
| 221 | + machine is stopped. The real time clock has a frequency of 1000 | |
| 222 | 222 | Hz. */ |
| 223 | 223 | extern QEMUClock *rt_clock; |
| 224 | 224 | |
| ... | ... | @@ -360,6 +360,61 @@ int register_ioport_read(int start, int length, int size, |
| 360 | 360 | IOPortReadFunc *func, void *opaque); |
| 361 | 361 | int register_ioport_write(int start, int length, int size, |
| 362 | 362 | IOPortWriteFunc *func, void *opaque); |
| 363 | +void isa_unassign_ioport(int start, int length); | |
| 364 | + | |
| 365 | +/* PCI bus */ | |
| 366 | + | |
| 367 | +extern int pci_enabled; | |
| 368 | + | |
| 369 | +extern target_phys_addr_t pci_mem_base; | |
| 370 | + | |
| 371 | +typedef struct PCIDevice PCIDevice; | |
| 372 | + | |
| 373 | +typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, | |
| 374 | + uint32_t address, uint32_t data, int len); | |
| 375 | +typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, | |
| 376 | + uint32_t address, int len); | |
| 377 | +typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, | |
| 378 | + uint32_t addr, uint32_t size, int type); | |
| 379 | + | |
| 380 | +#define PCI_ADDRESS_SPACE_MEM 0x00 | |
| 381 | +#define PCI_ADDRESS_SPACE_IO 0x01 | |
| 382 | +#define PCI_ADDRESS_SPACE_MEM_PREFETCH 0x08 | |
| 383 | + | |
| 384 | +typedef struct PCIIORegion { | |
| 385 | + uint32_t addr; | |
| 386 | + uint32_t size; | |
| 387 | + uint8_t type; | |
| 388 | + PCIMapIORegionFunc *map_func; | |
| 389 | +} PCIIORegion; | |
| 390 | + | |
| 391 | +struct PCIDevice { | |
| 392 | + /* PCI config space */ | |
| 393 | + uint8_t config[256]; | |
| 394 | + | |
| 395 | + /* the following fields are read only */ | |
| 396 | + int bus_num; | |
| 397 | + int devfn; | |
| 398 | + char name[64]; | |
| 399 | + PCIIORegion io_regions[6]; | |
| 400 | + | |
| 401 | + /* do not access the following fields */ | |
| 402 | + PCIConfigReadFunc *config_read; | |
| 403 | + PCIConfigWriteFunc *config_write; | |
| 404 | +}; | |
| 405 | + | |
| 406 | +PCIDevice *pci_register_device(const char *name, int instance_size, | |
| 407 | + int bus_num, int devfn, | |
| 408 | + PCIConfigReadFunc *config_read, | |
| 409 | + PCIConfigWriteFunc *config_write); | |
| 410 | + | |
| 411 | +void pci_register_io_region(PCIDevice *pci_dev, int region_num, | |
| 412 | + uint32_t size, int type, | |
| 413 | + PCIMapIORegionFunc *map_func); | |
| 414 | + | |
| 415 | +void i440fx_init(void); | |
| 416 | +void piix3_init(void); | |
| 417 | +void pci_bios_init(void); | |
| 363 | 418 | |
| 364 | 419 | /* vga.c */ |
| 365 | 420 | |
| ... | ... | @@ -397,8 +452,9 @@ void sdl_display_init(DisplayState *ds); |
| 397 | 452 | |
| 398 | 453 | extern BlockDriverState *bs_table[MAX_DISKS]; |
| 399 | 454 | |
| 400 | -void ide_init(int iobase, int iobase2, int irq, | |
| 401 | - BlockDriverState *hd0, BlockDriverState *hd1); | |
| 455 | +void isa_ide_init(int iobase, int iobase2, int irq, | |
| 456 | + BlockDriverState *hd0, BlockDriverState *hd1); | |
| 457 | +void pci_ide_init(BlockDriverState **hd_table); | |
| 402 | 458 | |
| 403 | 459 | /* oss.c */ |
| 404 | 460 | typedef enum { |
| ... | ... | @@ -446,7 +502,8 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); |
| 446 | 502 | |
| 447 | 503 | /* ne2000.c */ |
| 448 | 504 | |
| 449 | -void ne2000_init(int base, int irq, NetDriverState *nd); | |
| 505 | +void isa_ne2000_init(int base, int irq, NetDriverState *nd); | |
| 506 | +void pci_ne2000_init(NetDriverState *nd); | |
| 450 | 507 | |
| 451 | 508 | /* pckbd.c */ |
| 452 | 509 | ... | ... |