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,6 +8,9 @@ version 0.5.6: | ||
8 | - int13 CDROM BIOS fix (aka Solaris x86 install CD fix) | 8 | - int13 CDROM BIOS fix (aka Solaris x86 install CD fix) |
9 | - int15, ah=86 BIOS fix (aka Solaris x86 hardware probe hang up fix) | 9 | - int15, ah=86 BIOS fix (aka Solaris x86 hardware probe hang up fix) |
10 | - BSR/BSF "undefined behaviour" fix | 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 | version 0.5.5: | 15 | version 0.5.5: |
13 | 16 |
Makefile.target
@@ -232,7 +232,7 @@ ifeq ($(ARCH),alpha) | @@ -232,7 +232,7 @@ ifeq ($(ARCH),alpha) | ||
232 | endif | 232 | endif |
233 | 233 | ||
234 | # must use static linking to avoid leaving stuff in virtual address space | 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 | ifeq ($(TARGET_ARCH), i386) | 237 | ifeq ($(TARGET_ARCH), i386) |
238 | # Hardware support | 238 | # Hardware support |
hw/ide.c
@@ -1433,18 +1433,14 @@ static void ide_guess_geometry(IDEState *s) | @@ -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 | static int drive_serial = 1; | 1440 | static int drive_serial = 1; |
1441 | int i, cylinders, heads, secs; | 1441 | int i, cylinders, heads, secs; |
1442 | int64_t nb_sectors; | 1442 | int64_t nb_sectors; |
1443 | 1443 | ||
1444 | - ide_state = qemu_mallocz(sizeof(IDEState) * 2); | ||
1445 | - if (!ide_state) | ||
1446 | - return; | ||
1447 | - | ||
1448 | for(i = 0; i < 2; i++) { | 1444 | for(i = 0; i < 2; i++) { |
1449 | s = ide_state + i; | 1445 | s = ide_state + i; |
1450 | if (i == 0) | 1446 | if (i == 0) |
@@ -1483,6 +1479,22 @@ void ide_init(int iobase, int iobase2, int irq, | @@ -1483,6 +1479,22 @@ void ide_init(int iobase, int iobase2, int irq, | ||
1483 | s->irq = irq; | 1479 | s->irq = irq; |
1484 | ide_reset(s); | 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 | register_ioport_write(iobase, 8, 1, ide_ioport_write, ide_state); | 1498 | register_ioport_write(iobase, 8, 1, ide_ioport_write, ide_state); |
1487 | register_ioport_read(iobase, 8, 1, ide_ioport_read, ide_state); | 1499 | register_ioport_read(iobase, 8, 1, ide_ioport_read, ide_state); |
1488 | if (iobase2) { | 1500 | if (iobase2) { |
@@ -1496,3 +1508,87 @@ void ide_init(int iobase, int iobase2, int irq, | @@ -1496,3 +1508,87 @@ void ide_init(int iobase, int iobase2, int irq, | ||
1496 | register_ioport_write(iobase, 4, 4, ide_data_writel, ide_state); | 1508 | register_ioport_write(iobase, 4, 4, ide_data_writel, ide_state); |
1497 | register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state); | 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,7 +368,7 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr) | ||
368 | } | 368 | } |
369 | 369 | ||
370 | static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr, | 370 | static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr, |
371 | - uint32_t val) | 371 | + uint32_t val) |
372 | { | 372 | { |
373 | if (addr < 32 || | 373 | if (addr < 32 || |
374 | (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { | 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,8 +382,17 @@ static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr, | ||
382 | addr &= ~1; /* XXX: check exact behaviour if not even */ | 382 | addr &= ~1; /* XXX: check exact behaviour if not even */ |
383 | if (addr < 32 || | 383 | if (addr < 32 || |
384 | (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { | 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,12 +411,23 @@ static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr) | ||
402 | addr &= ~1; /* XXX: check exact behaviour if not even */ | 411 | addr &= ~1; /* XXX: check exact behaviour if not even */ |
403 | if (addr < 32 || | 412 | if (addr < 32 || |
404 | (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) { | 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 | } else { | 415 | } else { |
407 | return 0xffff; | 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 | static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) | 431 | static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
412 | { | 432 | { |
413 | NE2000State *s = opaque; | 433 | NE2000State *s = opaque; |
@@ -468,6 +488,53 @@ static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr) | @@ -468,6 +488,53 @@ static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr) | ||
468 | return ret; | 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 | static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val) | 538 | static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
472 | { | 539 | { |
473 | /* nothing to do (end of reset pulse) */ | 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,7 +547,7 @@ static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr) | ||
480 | return 0; | 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 | NE2000State *s; | 552 | NE2000State *s; |
486 | 553 | ||
@@ -505,3 +572,78 @@ void ne2000_init(int base, int irq, NetDriverState *nd) | @@ -505,3 +572,78 @@ void ne2000_init(int base, int irq, NetDriverState *nd) | ||
505 | 572 | ||
506 | qemu_add_read_packet(nd, ne2000_can_receive, ne2000_receive, s); | 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,6 +380,11 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, | ||
380 | stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); | 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 | /* init basic PC hardware */ | 388 | /* init basic PC hardware */ |
384 | register_ioport_write(0x80, 1, 1, ioport80_write, NULL); | 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,17 +406,25 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, | ||
401 | fd = serial_open_device(); | 406 | fd = serial_open_device(); |
402 | serial_init(0x3f8, 4, fd); | 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 | kbd_init(); | 428 | kbd_init(); |
416 | DMA_init(); | 429 | DMA_init(); |
417 | 430 | ||
@@ -426,4 +439,10 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, | @@ -426,4 +439,10 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, | ||
426 | floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); | 439 | floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); |
427 | 440 | ||
428 | cmos_init(ram_size, boot_device); | 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,13 +962,13 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, | ||
962 | if (nb_nics1 > NE2000_NB_MAX) | 962 | if (nb_nics1 > NE2000_NB_MAX) |
963 | nb_nics1 = NE2000_NB_MAX; | 963 | nb_nics1 = NE2000_NB_MAX; |
964 | for(i = 0; i < nb_nics1; i++) { | 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 | #endif | 967 | #endif |
968 | 968 | ||
969 | for(i = 0; i < 2; i++) { | 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 | kbd_init(); | 973 | kbd_init(); |
974 | AUD_init(); | 974 | AUD_init(); |
vl.c
@@ -121,6 +121,7 @@ SerialState *serial_console; | @@ -121,6 +121,7 @@ SerialState *serial_console; | ||
121 | QEMUTimer *gui_timer; | 121 | QEMUTimer *gui_timer; |
122 | int vm_running; | 122 | int vm_running; |
123 | int audio_enabled = 0; | 123 | int audio_enabled = 0; |
124 | +int pci_enabled = 0; | ||
124 | 125 | ||
125 | /***********************************************************/ | 126 | /***********************************************************/ |
126 | /* x86 ISA bus support */ | 127 | /* x86 ISA bus support */ |
@@ -238,6 +239,21 @@ int register_ioport_write(int start, int length, int size, | @@ -238,6 +239,21 @@ int register_ioport_write(int start, int length, int size, | ||
238 | return 0; | 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 | void pstrcpy(char *buf, int buf_size, const char *str) | 257 | void pstrcpy(char *buf, int buf_size, const char *str) |
242 | { | 258 | { |
243 | int c; | 259 | int c; |
@@ -1973,6 +1989,7 @@ enum { | @@ -1973,6 +1989,7 @@ enum { | ||
1973 | QEMU_OPTION_hdachs, | 1989 | QEMU_OPTION_hdachs, |
1974 | QEMU_OPTION_L, | 1990 | QEMU_OPTION_L, |
1975 | QEMU_OPTION_no_code_copy, | 1991 | QEMU_OPTION_no_code_copy, |
1992 | + QEMU_OPTION_pci, | ||
1976 | }; | 1993 | }; |
1977 | 1994 | ||
1978 | typedef struct QEMUOption { | 1995 | typedef struct QEMUOption { |
@@ -1999,7 +2016,7 @@ const QEMUOption qemu_options[] = { | @@ -1999,7 +2016,7 @@ const QEMUOption qemu_options[] = { | ||
1999 | 2016 | ||
2000 | { "nics", HAS_ARG, QEMU_OPTION_nics}, | 2017 | { "nics", HAS_ARG, QEMU_OPTION_nics}, |
2001 | { "macaddr", HAS_ARG, QEMU_OPTION_macaddr}, | 2018 | { "macaddr", HAS_ARG, QEMU_OPTION_macaddr}, |
2002 | - { "n", HAS_ARG, QEMU_OPTION_d }, | 2019 | + { "n", HAS_ARG, QEMU_OPTION_n }, |
2003 | { "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd }, | 2020 | { "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd }, |
2004 | #ifdef CONFIG_SLIRP | 2021 | #ifdef CONFIG_SLIRP |
2005 | { "user-net", 0, QEMU_OPTION_user_net }, | 2022 | { "user-net", 0, QEMU_OPTION_user_net }, |
@@ -2017,6 +2034,7 @@ const QEMUOption qemu_options[] = { | @@ -2017,6 +2034,7 @@ const QEMUOption qemu_options[] = { | ||
2017 | { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, | 2034 | { "hdachs", HAS_ARG, QEMU_OPTION_hdachs }, |
2018 | { "L", HAS_ARG, QEMU_OPTION_L }, | 2035 | { "L", HAS_ARG, QEMU_OPTION_L }, |
2019 | { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, | 2036 | { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, |
2037 | + { "pci", 0, QEMU_OPTION_pci }, | ||
2020 | { NULL }, | 2038 | { NULL }, |
2021 | }; | 2039 | }; |
2022 | 2040 | ||
@@ -2286,6 +2304,9 @@ int main(int argc, char **argv) | @@ -2286,6 +2304,9 @@ int main(int argc, char **argv) | ||
2286 | case QEMU_OPTION_S: | 2304 | case QEMU_OPTION_S: |
2287 | start_emulation = 0; | 2305 | start_emulation = 0; |
2288 | break; | 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,7 +218,7 @@ typedef void QEMUTimerCB(void *opaque); | ||
218 | 218 | ||
219 | /* The real time clock should be used only for stuff which does not | 219 | /* The real time clock should be used only for stuff which does not |
220 | change the virtual machine state, as it is run even if the virtual | 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 | Hz. */ | 222 | Hz. */ |
223 | extern QEMUClock *rt_clock; | 223 | extern QEMUClock *rt_clock; |
224 | 224 | ||
@@ -360,6 +360,61 @@ int register_ioport_read(int start, int length, int size, | @@ -360,6 +360,61 @@ int register_ioport_read(int start, int length, int size, | ||
360 | IOPortReadFunc *func, void *opaque); | 360 | IOPortReadFunc *func, void *opaque); |
361 | int register_ioport_write(int start, int length, int size, | 361 | int register_ioport_write(int start, int length, int size, |
362 | IOPortWriteFunc *func, void *opaque); | 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 | /* vga.c */ | 419 | /* vga.c */ |
365 | 420 | ||
@@ -397,8 +452,9 @@ void sdl_display_init(DisplayState *ds); | @@ -397,8 +452,9 @@ void sdl_display_init(DisplayState *ds); | ||
397 | 452 | ||
398 | extern BlockDriverState *bs_table[MAX_DISKS]; | 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 | /* oss.c */ | 459 | /* oss.c */ |
404 | typedef enum { | 460 | typedef enum { |
@@ -446,7 +502,8 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); | @@ -446,7 +502,8 @@ int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num); | ||
446 | 502 | ||
447 | /* ne2000.c */ | 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 | /* pckbd.c */ | 508 | /* pckbd.c */ |
452 | 509 |