diff options
Diffstat (limited to 'hw/isa/piix4.c')
-rw-r--r-- | hw/isa/piix4.c | 143 |
1 files changed, 133 insertions, 10 deletions
diff --git a/hw/isa/piix4.c b/hw/isa/piix4.c index 890d999abf..86678e6829 100644 --- a/hw/isa/piix4.c +++ b/hw/isa/piix4.c @@ -2,6 +2,7 @@ * QEMU PIIX4 PCI Bridge Emulation * * Copyright (c) 2006 Fabrice Bellard + * Copyright (c) 2018 Hervé Poussineau * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,19 +24,34 @@ */ #include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/irq.h" #include "hw/i386/pc.h" +#include "hw/southbridge/piix.h" #include "hw/pci/pci.h" #include "hw/isa/isa.h" #include "hw/sysbus.h" +#include "hw/dma/i8257.h" +#include "hw/timer/i8254.h" +#include "hw/rtc/mc146818rtc.h" +#include "hw/ide.h" #include "migration/vmstate.h" +#include "sysemu/reset.h" +#include "sysemu/runstate.h" PCIDevice *piix4_dev; typedef struct PIIX4State { PCIDevice dev; + qemu_irq cpu_intr; + qemu_irq *isa; + + RTCState rtc; + /* Reset Control Register */ + MemoryRegion rcr_mem; + uint8_t rcr; } PIIX4State; -#define TYPE_PIIX4_PCI_DEVICE "PIIX4" #define PIIX4_PCI_DEVICE(obj) \ OBJECT_CHECK(PIIX4State, (obj), TYPE_PIIX4_PCI_DEVICE) @@ -87,24 +103,102 @@ static const VMStateDescription vmstate_piix4 = { } }; +static void piix4_request_i8259_irq(void *opaque, int irq, int level) +{ + PIIX4State *s = opaque; + qemu_set_irq(s->cpu_intr, level); +} + +static void piix4_set_i8259_irq(void *opaque, int irq, int level) +{ + PIIX4State *s = opaque; + qemu_set_irq(s->isa[irq], level); +} + +static void piix4_rcr_write(void *opaque, hwaddr addr, uint64_t val, + unsigned int len) +{ + PIIX4State *s = opaque; + + if (val & 4) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + return; + } + + s->rcr = val & 2; /* keep System Reset type only */ +} + +static uint64_t piix4_rcr_read(void *opaque, hwaddr addr, unsigned int len) +{ + PIIX4State *s = opaque; + + return s->rcr; +} + +static const MemoryRegionOps piix4_rcr_ops = { + .read = piix4_rcr_read, + .write = piix4_rcr_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 1, + .max_access_size = 1, + }, +}; + static void piix4_realize(PCIDevice *dev, Error **errp) { - PIIX4State *d = PIIX4_PCI_DEVICE(dev); + PIIX4State *s = PIIX4_PCI_DEVICE(dev); + ISABus *isa_bus; + qemu_irq *i8259_out_irq; + Error *err = NULL; - if (!isa_bus_new(DEVICE(d), pci_address_space(dev), - pci_address_space_io(dev), errp)) { + isa_bus = isa_bus_new(DEVICE(dev), pci_address_space(dev), + pci_address_space_io(dev), errp); + if (!isa_bus) { return; } - piix4_dev = &d->dev; + + qdev_init_gpio_in_named(DEVICE(dev), piix4_set_i8259_irq, + "isa", ISA_NUM_IRQS); + qdev_init_gpio_out_named(DEVICE(dev), &s->cpu_intr, + "intr", 1); + + memory_region_init_io(&s->rcr_mem, OBJECT(dev), &piix4_rcr_ops, s, + "reset-control", 1); + memory_region_add_subregion_overlap(pci_address_space_io(dev), + PIIX_RCR_IOPORT, &s->rcr_mem, 1); + + /* initialize i8259 pic */ + i8259_out_irq = qemu_allocate_irqs(piix4_request_i8259_irq, s, 1); + s->isa = i8259_init(isa_bus, *i8259_out_irq); + + /* initialize ISA irqs */ + isa_bus_irqs(isa_bus, s->isa); + + /* initialize pit */ + i8254_pit_init(isa_bus, 0x40, 0, NULL); + + /* DMA */ + i8257_dma_init(isa_bus, 0); + + /* RTC */ + qdev_set_parent_bus(DEVICE(&s->rtc), BUS(isa_bus)); + qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000); + object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + isa_init_irq(ISA_DEVICE(&s->rtc), &s->rtc.irq, RTC_ISA_IRQ); + + piix4_dev = dev; } -int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn) +static void piix4_init(Object *obj) { - PCIDevice *d; + PIIX4State *s = PIIX4_PCI_DEVICE(obj); - d = pci_create_simple_multifunction(bus, devfn, true, "PIIX4"); - *isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(d), "isa.0")); - return d->devfn; + object_initialize(&s->rtc, sizeof(s->rtc), TYPE_MC146818_RTC); } static void piix4_class_init(ObjectClass *klass, void *data) @@ -131,6 +225,7 @@ static const TypeInfo piix4_info = { .name = TYPE_PIIX4_PCI_DEVICE, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(PIIX4State), + .instance_init = piix4_init, .class_init = piix4_class_init, .interfaces = (InterfaceInfo[]) { { INTERFACE_CONVENTIONAL_PCI_DEVICE }, @@ -144,3 +239,31 @@ static void piix4_register_types(void) } type_init(piix4_register_types) + +DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus, + I2CBus **smbus, size_t ide_buses) +{ + size_t ide_drives = ide_buses * MAX_IDE_DEVS; + DriveInfo **hd; + PCIDevice *pci; + DeviceState *dev; + + pci = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(10, 0), + true, TYPE_PIIX4_PCI_DEVICE); + dev = DEVICE(pci); + if (isa_bus) { + *isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0")); + } + + hd = g_new(DriveInfo *, ide_drives); + ide_drive_get(hd, ide_drives); + pci_piix4_ide_init(pci_bus, hd, pci->devfn + 1); + g_free(hd); + pci_create_simple(pci_bus, pci->devfn + 2, "piix4-usb-uhci"); + if (smbus) { + *smbus = piix4_pm_init(pci_bus, pci->devfn + 3, 0x1100, + isa_get_irq(NULL, 9), NULL, 0, NULL); + } + + return dev; +} |