From patchwork Wed Jul 18 13:19:01 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wanpeng Li X-Patchwork-Id: 171673 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 23EF42C037E for ; Wed, 18 Jul 2012 23:21:27 +1000 (EST) Received: from localhost ([::1]:44496 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SrUBw-0007kj-VV for incoming@patchwork.ozlabs.org; Wed, 18 Jul 2012 09:21:24 -0400 Received: from eggs.gnu.org ([208.118.235.92]:60018) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SrUAx-0005vR-SN for qemu-devel@nongnu.org; Wed, 18 Jul 2012 09:20:59 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1SrUAN-0007Gt-0x for qemu-devel@nongnu.org; Wed, 18 Jul 2012 09:20:23 -0400 Received: from e28smtp09.in.ibm.com ([122.248.162.9]:54124) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1SrUAL-000702-5y for qemu-devel@nongnu.org; Wed, 18 Jul 2012 09:19:46 -0400 Received: from /spool/local by e28smtp09.in.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 18 Jul 2012 18:49:18 +0530 Received: from d28relay03.in.ibm.com (9.184.220.60) by e28smtp09.in.ibm.com (192.168.1.139) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 18 Jul 2012 18:49:16 +0530 Received: from d28av05.in.ibm.com (d28av05.in.ibm.com [9.184.220.67]) by d28relay03.in.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id q6IDJFhp15073700 for ; Wed, 18 Jul 2012 18:49:15 +0530 Received: from d28av05.in.ibm.com (loopback [127.0.0.1]) by d28av05.in.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id q6IInn7v004768 for ; Thu, 19 Jul 2012 04:49:50 +1000 Received: from localhost ([9.123.247.28]) by d28av05.in.ibm.com (8.14.4/8.13.1/NCO v10.0 AVin) with ESMTP id q6IInm3E004737; Thu, 19 Jul 2012 04:49:48 +1000 From: Wanpeng Li To: Anthony Liguori Date: Wed, 18 Jul 2012 21:19:01 +0800 Message-Id: <1342617545-9261-2-git-send-email-liwanp@linux.vnet.ibm.com> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1342617545-9261-1-git-send-email-liwanp@linux.vnet.ibm.com> References: <1342617545-9261-1-git-send-email-liwanp@linux.vnet.ibm.com> x-cbid: 12071813-2674-0000-0000-0000054B331C X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 122.248.162.9 Cc: Ram Pai , Gavin Shan , "Michael S. Tsirkin" , Jan Kiszka , qemu-devel@nongnu.org, Liu Ping Fan , Blue Swirl , Stefan Weil , Avi Kivity , Paolo Bonzini , Wanpeng Li Subject: [Qemu-devel] [PATCH v4 1/5] eliminate piix_pci.c and module i440fx and piix3 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org [CCing ML] From: Anthony Liguori The big picture about the patch is shown as follows: 1) pc_init creates an I440FX, any bus devices (ISA serial port, PCI vga and nics, etc.), sets properties appropriately, and realizes the devices. 2) I440FX is-a PCIHost, has-a I440FX-PMC, has-a PIIX3 3) PIIX3 has-a RTC, has-a I8042, has-a DMAController, etc. i440fx-pcihost => i440fx i440fx => i440fx-pmc i440fx_pmc is Programmable Memory Controller which integrated in I440FX chipset, and move ram initialization into i440fx-pmc. It might seem like a small change, but it better reflects the fact that the PMC is contained within the i440fx which we will now reflect in composition in the next few changesets. Signed-off-by: Anthony Liguori Signed-off-by: Wanpeng Li --- hw/i386/Makefile.objs | 2 +- hw/i440fx.c | 434 +++++++++++++++++++++++++++++++++++ hw/i440fx.h | 77 +++++++ hw/piix3.c | 292 ++++++++++++++++++++++++ hw/piix3.h | 79 +++++++ hw/piix_pci.c | 599 ------------------------------------------------- 6 files changed, 883 insertions(+), 600 deletions(-) create mode 100644 hw/i440fx.c create mode 100644 hw/i440fx.h create mode 100644 hw/piix3.c create mode 100644 hw/piix3.h delete mode 100644 hw/piix_pci.c diff --git a/hw/i386/Makefile.objs b/hw/i386/Makefile.objs index 8c764bb..49b32d0 100644 --- a/hw/i386/Makefile.objs +++ b/hw/i386/Makefile.objs @@ -1,6 +1,6 @@ obj-y += mc146818rtc.o pc.o obj-y += apic_common.o apic.o kvmvapic.o -obj-y += sga.o ioapic_common.o ioapic.o piix_pci.o +obj-y += sga.o ioapic_common.o ioapic.o i440fx.o piix3.o obj-y += vmport.o obj-y += pci-hotplug.o smbios.o wdt_ib700.o obj-y += debugcon.o multiboot.o diff --git a/hw/i440fx.c b/hw/i440fx.c new file mode 100644 index 0000000..8c4408f --- /dev/null +++ b/hw/i440fx.c @@ -0,0 +1,434 @@ +/* + * QEMU i440FX PCI Host Bridge Emulation + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "i440fx.h" +#include "range.h" +#include "xen.h" +#include "loader.h" +#include "pc.h" + +#define BIOS_FILENAME "bios.bin" + +/* + * I440FX chipset data sheet. + * http://download.intel.com/design/chipsets/datashts/29054901.pdf + * + * The I440FX is a package that contains an integrated PCI Host controller, + * memory controller, and is usually packaged with a PCI-ISA bus and super I/O + * chipset. + * + * The "i440FX" device is the PCI host controller. On function 0.0, there is a + * memory controller called the Programmable Memory Controller (PMC). On + * function 1.0, there is the PCI-ISA bus/super I/O chip called the PIIX3. + */ + +#define I440FX_PMC_PCI_HOLE 0xE0000000ULL +#define I440FX_PMC_PCI_HOLE_END 0x100000000ULL + +#define I440FX_PAM 0x59 +#define I440FX_PAM_SIZE 7 +#define I440FX_SMRAM 0x72 + +static void piix3_set_irq(void *opaque, int pirq, int level) +{ + PIIX3State *piix3 = opaque; + piix3_set_irq_level(piix3, pirq, level); +} + +/* + * return the global irq number corresponding to a given device irq + * pin. We could also use the bus number to have a more precise + * mapping. + */ +static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx) +{ + int slot_addend; + slot_addend = (pci_dev->devfn >> 3) - 1; + return (pci_intx + slot_addend) & 3; +} + +static void update_pam(I440FXPMCState *d, uint32_t start, uint32_t end, int r, + PAMMemoryRegion *mem) +{ + if (mem->initialized) { + memory_region_del_subregion(d->system_memory, &mem->mem); + memory_region_destroy(&mem->mem); + } + + switch (r) { + case 3: + /* RAM */ + memory_region_init_alias(&mem->mem, "pam-ram", d->ram_memory, + start, end - start); + break; + case 1: + /* ROM (XXX: not quite correct) */ + memory_region_init_alias(&mem->mem, "pam-rom", d->ram_memory, + start, end - start); + memory_region_set_readonly(&mem->mem, true); + break; + case 2: + case 0: + /* XXX: should distinguish read/write cases */ + memory_region_init_alias(&mem->mem, "pam-pci", d->pci_address_space, + start, end - start); + break; + } + memory_region_add_subregion_overlap(d->system_memory, + start, &mem->mem, 1); + mem->initialized = true; +} + +static void i440fx_pmc_update_memory_mappings(I440FXPMCState *d) +{ + int i, r; + uint32_t smram; + bool smram_enabled; + + memory_region_transaction_begin(); + update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3, + &d->pam_regions[0]); + for (i = 0; i < 12; i++) { + r = (d->dev.config[(i >> 1) + (I440FX_PAM + 1)] >> ((i & 1) * 4)) & 3; + update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r, + &d->pam_regions[i+1]); + } + smram = d->dev.config[I440FX_SMRAM]; + smram_enabled = (d->smm_enabled && (smram & 0x08)) || (smram & 0x40); + memory_region_set_enabled(&d->smram_region, !smram_enabled); + memory_region_transaction_commit(); +} + +static void i440fx_pmc_set_smm(int val, void *arg) +{ + I440FXPMCState *d = arg; + + val = (val != 0); + if (d->smm_enabled != val) { + d->smm_enabled = val; + i440fx_pmc_update_memory_mappings(d); + } +} + + +static void i440fx_pmc_write_config(PCIDevice *dev, + uint32_t address, uint32_t val, int len) +{ + I440FXPMCState *d = DO_UPCAST(I440FXPMCState, dev, dev); + + /* XXX: implement SMRAM.D_LOCK */ + pci_default_write_config(dev, address, val, len); + if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) || + range_covers_byte(address, len, I440FX_SMRAM)) { + i440fx_pmc_update_memory_mappings(d); + } +} + +static int i440fx_pmc_load_old(QEMUFile *f, void *opaque, int version_id) +{ + I440FXPMCState *d = opaque; + int ret, i; + + ret = pci_device_load(&d->dev, f); + if (ret < 0) { + return ret; + } + i440fx_pmc_update_memory_mappings(d); + qemu_get_8s(f, &d->smm_enabled); + + if (version_id == 2) { + for (i = 0; i < PIIX_NUM_PIRQS; i++) { + qemu_get_be32(f); /* dummy load for compatibility */ + } + } + + return 0; +} + +static int i440fx_pmc_post_load(void *opaque, int version_id) +{ + I440FXPMCState *d = opaque; + + i440fx_pmc_update_memory_mappings(d); + return 0; +} + +static const VMStateDescription vmstate_i440fx_pmc = { + .name = "I440FX", /* this is wrong but we can't change it */ + .version_id = 3, + .minimum_version_id = 3, + .minimum_version_id_old = 1, + .load_state_old = i440fx_pmc_load_old, + .post_load = i440fx_pmc_post_load, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, I440FXPMCState), + VMSTATE_UINT8(smm_enabled, I440FXPMCState), + VMSTATE_END_OF_LIST() + } +}; + +static int i440fx_realize(SysBusDevice *dev) +{ + I440FXState *s = I440FX(dev); + PCIHostState *h = PCI_HOST(s); + int bios_size, isa_bios_size; + char *filename; + int ret; + + g_assert(h->address_space != NULL); + g_assert(s->address_space_io != NULL); + + h->bus = pci_bus_new(DEVICE(s), NULL, &s->pci_address_space, + s->address_space_io, 0); + + memory_region_init_io(&h->conf_mem, &pci_host_conf_le_ops, s, + "pci-conf-idx", 4); + sysbus_add_io(dev, 0xcf8, &h->conf_mem); + sysbus_init_ioports(&h->busdev, 0xcf8, 4); + + memory_region_init_io(&h->data_mem, &pci_host_data_le_ops, s, + "pci-conf-data", 4); + sysbus_add_io(dev, 0xcfc, &h->data_mem); + sysbus_init_ioports(&h->busdev, 0xcfc, 4); + + s->pmc.system_memory = h->address_space; + s->pmc.pci_address_space = &s->pci_address_space; + + qdev_set_parent_bus(DEVICE(&s->pmc), &(h->bus->qbus)); + qdev_init_nofail(DEVICE(&s->pmc)); + + qdev_set_parent_bus(DEVICE(&s->piix3), &(h->bus->qbus)); + qdev_init_nofail(DEVICE(&s->piix3)); + + if (xen_enabled()) { + pci_bus_irqs(h->bus, xen_piix3_set_irq, xen_pci_slot_get_pirq, + &s->piix3, XEN_PIIX_NUM_PIRQS); + } else { + pci_bus_irqs(h->bus, piix3_set_irq, pci_slot_get_pirq, &s->piix3, + PIIX_NUM_PIRQS); + } + + /* BIOS load */ + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, s->bios_name); + if (filename) { + bios_size = get_image_size(filename); + } else { + bios_size = -1; + } + if (bios_size <= 0 || + (bios_size % 65536) != 0) { + goto bios_error; + } + memory_region_init_ram(&s->bios, "pc.bios", bios_size); + vmstate_register_ram_global(&s->bios); + memory_region_set_readonly(&s->bios, true); + ret = rom_add_file_fixed(s->bios_name, (uint32_t)(-bios_size), -1); + if (ret != 0) { + bios_error: + fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", s->bios_name); + exit(1); + } + if (filename) { + g_free(filename); + } + + /* map the last 128KB of the BIOS in ISA space */ + isa_bios_size = bios_size; + if (isa_bios_size > (128 * 1024)) { + isa_bios_size = 128 * 1024; + } + memory_region_init_alias(&s->isa_bios, "isa-bios", &s->bios, + bios_size - isa_bios_size, isa_bios_size); + memory_region_add_subregion_overlap(&s->pci_address_space, + 0x100000 - isa_bios_size, + &s->isa_bios, + 1); + memory_region_set_readonly(&s->isa_bios, true); + + memory_region_init_ram(&s->option_roms, "pc.rom", PC_ROM_SIZE); + vmstate_register_ram_global(&s->option_roms); + memory_region_add_subregion_overlap(&s->pci_address_space, + PC_ROM_MIN_VGA, + &s->option_roms, + 1); + + /* map all the bios at the top of memory */ + memory_region_add_subregion(&s->pci_address_space, + (uint32_t)(-bios_size), + &s->bios); + + return 0; +} + +static void i440fx_initfn(Object *obj) +{ + I440FXState *s = I440FX(obj); + + object_initialize(&s->pmc, TYPE_I440FX_PMC); + object_property_add_child(obj, "pmc", OBJECT(&s->pmc), NULL); + qdev_prop_set_uint32(DEVICE(&s->pmc), "addr", PCI_DEVFN(0, 0)); + + /* Xen supports additional interrupt routes from the PCI devices to + * the IOAPIC: the four pins of each PCI device on the bus are also + * connected to the IOAPIC directly. + * These additional routes can be discovered through ACPI. */ + if (xen_enabled()) { + object_initialize(&s->piix3, "PIIX3-xen"); + } else { + object_initialize(&s->piix3, "PIIX3"); + } + object_property_add_child(OBJECT(s), "piix3", OBJECT(&s->piix3), NULL); + + s->bios_name = g_strdup(BIOS_FILENAME); + + memory_region_init(&s->pci_address_space, "pci", INT64_MAX); +} + +static int i440fx_pmc_realize(PCIDevice *dev) +{ + I440FXPMCState *d = DO_UPCAST(I440FXPMCState, dev, dev); + ram_addr_t ram_size; + uint64_t below_4g_mem_size, above_4g_mem_size; + uint64_t pci_hole_start, pci_hole_size; + uint64_t pci_hole64_start, pci_hole64_size; + + g_assert(d->ram_size != 0); + g_assert(d->system_memory != NULL); + g_assert(d->pci_address_space != NULL); + + /* Calculate memory geometry from RAM size */ + if (d->ram_size > I440FX_PMC_PCI_HOLE) { + below_4g_mem_size = I440FX_PMC_PCI_HOLE; + above_4g_mem_size = d->ram_size - I440FX_PMC_PCI_HOLE; + } else { + below_4g_mem_size = d->ram_size; + above_4g_mem_size = 0; + } + + /* Allocate RAM. We allocate it as a single memory region and use + * aliases to address portions of it, mostly for backwards compatibility + * with older qemus that used qemu_ram_alloc(). + */ + memory_region_init_ram(&d->ram, "pc.ram", + below_4g_mem_size + above_4g_mem_size); + vmstate_register_ram_global(&d->ram); + + memory_region_init_alias(&d->ram_below_4g, "ram-below-4g", &d->ram, + 0, below_4g_mem_size); + memory_region_add_subregion(d->system_memory, 0, &d->ram_below_4g); + if (above_4g_mem_size > 0) { + memory_region_init_alias(&d->ram_above_4g, "ram-above-4g", &d->ram, + below_4g_mem_size, above_4g_mem_size); + memory_region_add_subregion(d->system_memory, 0x100000000ULL, + &d->ram_above_4g); + } + + pci_hole_start = below_4g_mem_size; + pci_hole_size = I440FX_PMC_PCI_HOLE_END - pci_hole_start; + + pci_hole64_start = I440FX_PMC_PCI_HOLE_END + d->ram_size - pci_hole_start; + if (sizeof(target_phys_addr_t) == 4) { + pci_hole64_size = 0; + } else { + pci_hole64_size = (1ULL << 62); + } + + memory_region_init_alias(&d->pci_hole, "pci-hole", d->pci_address_space, + pci_hole_start, pci_hole_size); + memory_region_add_subregion(d->system_memory, pci_hole_start, &d->pci_hole); + memory_region_init_alias(&d->pci_hole_64bit, "pci-hole64", + d->pci_address_space, + pci_hole64_start, pci_hole64_size); + if (pci_hole64_size) { + memory_region_add_subregion(d->system_memory, pci_hole64_start, + &d->pci_hole_64bit); + } + memory_region_init_alias(&d->smram_region, "smram-region", + d->pci_address_space, 0xa0000, 0x20000); + memory_region_add_subregion_overlap(d->system_memory, 0xa0000, + &d->smram_region, 1); + memory_region_set_enabled(&d->smram_region, false); + + ram_size = d->ram_size / 8 / 1024 / 1024; + if (ram_size > 255) { + ram_size = 255; + } + d->dev.config[0x57] = ram_size; + + i440fx_pmc_update_memory_mappings(d); + + d->dev.config[I440FX_SMRAM] = 0x02; + + cpu_smm_register(&i440fx_pmc_set_smm, d); + return 0; +} + +static void i440fx_pmc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->no_hotplug = 1; + k->init = i440fx_pmc_realize; + k->config_write = i440fx_pmc_write_config; + k->vendor_id = PCI_VENDOR_ID_INTEL; + k->device_id = PCI_DEVICE_ID_INTEL_82441; + k->class_id = PCI_CLASS_BRIDGE_HOST; + k->revision = 0x02; + dc->desc = "Host bridge"; + dc->no_user = 1; + dc->vmsd = &vmstate_i440fx_pmc; +} + +static TypeInfo i440fx_pmc_info = { + .name = TYPE_I440FX_PMC, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(I440FXPMCState), + .class_init = i440fx_pmc_class_init, +}; + +static void i440fx_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); + + k->init = i440fx_realize; + dc->fw_name = "pci"; + dc->no_user = 1; +} + +static TypeInfo i440fx_info = { + .name = TYPE_I440FX, + .parent = TYPE_PCI_HOST, + .instance_size = sizeof(I440FXState), + .instance_init = i440fx_initfn, + .class_init = i440fx_class_init, +}; + +static void register_devices(void) +{ + type_register_static(&i440fx_info); + type_register_static(&i440fx_pmc_info); +} +type_init(register_devices); diff --git a/hw/i440fx.h b/hw/i440fx.h new file mode 100644 index 0000000..ae1e58e --- /dev/null +++ b/hw/i440fx.h @@ -0,0 +1,77 @@ +/* + * QEMU i440FX PCI Host Bridge Emulation + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef QEMU_I440FX_H +#define QEMU_I440FX_H + +#include "pci_host.h" +#include "piix3.h" +#include "pci_internals.h" + +#define TYPE_I440FX_PMC "i440FX-PMC" +#define I440FX_PMC(obj) OBJECT_CHECK(I440FXPMCState, (obj), TYPE_I440FX_PMC) + +typedef struct PAMMemoryRegion { + MemoryRegion mem; + bool initialized; +} PAMMemoryRegion; + +typedef struct I440FXPMCState { + PCIDevice dev; + MemoryRegion *system_memory; + MemoryRegion *pci_address_space; + MemoryRegion *ram_memory; + MemoryRegion pci_hole; + MemoryRegion pci_hole_64bit; + PAMMemoryRegion pam_regions[13]; + MemoryRegion smram_region; + uint8_t smm_enabled; + + ram_addr_t ram_size; + MemoryRegion ram; + MemoryRegion ram_below_4g; + MemoryRegion ram_above_4g; +} I440FXPMCState; + +#define TYPE_I440FX "i440FX" +#define I440FX(obj) OBJECT_CHECK(I440FXState, (obj), TYPE_I440FX) + +typedef struct I440FXState { + PCIHostState parent; + + MemoryRegion *address_space_io; + MemoryRegion pci_address_space; + + I440FXPMCState pmc; + PIIX3State piix3; + + /* Is this more appropriate for the PMC? */ + MemoryRegion bios; + MemoryRegion isa_bios; + MemoryRegion option_roms; + + char *bios_name; +} I440FXState; + +#endif diff --git a/hw/piix3.c b/hw/piix3.c new file mode 100644 index 0000000..418c7ee --- /dev/null +++ b/hw/piix3.c @@ -0,0 +1,292 @@ +/* + * QEMU PIIX3 PCI-ISA Bridge Emulation + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright IBM, Corp. 2012 + * + * Authors: + * Anthony Liguori + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "piix3.h" +#include "range.h" +#include "kvm.h" +#include "xen.h" +#include "pc.h" +#include "pcspk.h" + +/* PIIX3 PCI to ISA bridge */ +static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq) +{ + qemu_set_irq(piix3->pic[pic_irq], + !!(piix3->pic_levels & + (((1ULL << PIIX_NUM_PIRQS) - 1) << + (pic_irq * PIIX_NUM_PIRQS)))); +} + +void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level) +{ + int pic_irq; + uint64_t mask; + + pic_irq = piix3->dev.config[PIIX_PIRQC + pirq]; + if (pic_irq >= PIIX_NUM_PIC_IRQS) { + return; + } + + mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq); + piix3->pic_levels &= ~mask; + piix3->pic_levels |= mask * !!level; + + piix3_set_irq_pic(piix3, pic_irq); +} + +/* irq routing is changed. so rebuild bitmap */ +static void piix3_update_irq_levels(PIIX3State *piix3) +{ + int pirq; + + piix3->pic_levels = 0; + for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) { + piix3_set_irq_level(piix3, pirq, + pci_bus_get_irq_level(piix3->dev.bus, pirq)); + } +} + +static void piix3_write_config(PCIDevice *dev, + uint32_t address, uint32_t val, int len) +{ + pci_default_write_config(dev, address, val, len); + if (ranges_overlap(address, len, PIIX_PIRQC, 4)) { + PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev); + int pic_irq; + piix3_update_irq_levels(piix3); + for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) { + piix3_set_irq_pic(piix3, pic_irq); + } + } +} + +static void piix3_write_config_xen(PCIDevice *dev, + uint32_t address, uint32_t val, int len) +{ + xen_piix_pci_write_config_client(address, val, len); + piix3_write_config(dev, address, val, len); +} + +static void piix3_reset(DeviceState *dev) +{ + PIIX3State *d = PIIX3(dev); + uint8_t *pci_conf = d->dev.config; + + /* master, memory and I/O */ + pci_conf[0x04] = 0x07; + pci_conf[0x05] = 0x00; + pci_conf[0x06] = 0x00; + /* PCI_status_devsel_medium */ + pci_conf[0x07] = 0x02; + pci_conf[0x4c] = 0x4d; + pci_conf[0x4e] = 0x03; + pci_conf[0x4f] = 0x00; + pci_conf[0x60] = 0x80; + pci_conf[0x61] = 0x80; + pci_conf[0x62] = 0x80; + pci_conf[0x63] = 0x80; + pci_conf[0x69] = 0x02; + pci_conf[0x70] = 0x80; + pci_conf[0x76] = 0x0c; + pci_conf[0x77] = 0x0c; + pci_conf[0x78] = 0x02; + pci_conf[0x79] = 0x00; + pci_conf[0x80] = 0x00; + pci_conf[0x82] = 0x00; + pci_conf[0xa0] = 0x08; + pci_conf[0xa2] = 0x00; + pci_conf[0xa3] = 0x00; + pci_conf[0xa4] = 0x00; + pci_conf[0xa5] = 0x00; + pci_conf[0xa6] = 0x00; + pci_conf[0xa7] = 0x00; + pci_conf[0xa8] = 0x0f; + pci_conf[0xaa] = 0x00; + pci_conf[0xab] = 0x00; + pci_conf[0xac] = 0x00; + pci_conf[0xae] = 0x00; + + d->pic_levels = 0; +} + +static int piix3_post_load(void *opaque, int version_id) +{ + PIIX3State *piix3 = opaque; + piix3_update_irq_levels(piix3); + return 0; +} + +static void piix3_pre_save(void *opaque) +{ + int i; + PIIX3State *piix3 = opaque; + + for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) { + piix3->pci_irq_levels_vmstate[i] = + pci_bus_get_irq_level(piix3->dev.bus, i); + } +} + +static const VMStateDescription vmstate_piix3 = { + .name = TYPE_PIIX3, + .version_id = 3, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .post_load = piix3_post_load, + .pre_save = piix3_pre_save, + .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(dev, PIIX3State), + VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State, + PIIX_NUM_PIRQS, 3), + VMSTATE_END_OF_LIST() + } +}; + +static int piix3_realize(PCIDevice *dev) +{ + PIIX3State *s = PIIX3(dev); + qemu_irq rtc_irq; + + /* Initialize ISA Bus */ + s->bus = isa_bus_new(DEVICE(dev), pci_address_space_io(dev)); + isa_bus_irqs(s->bus, s->pic); + + /* Realize the RTC */ + qdev_set_parent_bus(DEVICE(&s->rtc), &(s->bus->qbus)); + qdev_init_nofail(DEVICE(&s->rtc)); + + /* + * Check if an HPET shall be created + * + * Without KVM_CAP_PIT_STATE2, we cannot switch off the in-kernel PIT + * when the HPET wants to take over, Thus we have to disable the latter. + */ + if (!no_hpet && (!kvm_irqchip_in_kernel() || kvm_has_pit_state2())) { + int i; + + /* We need to introduce a proper IRQ and Memory QOM infrastructure + * so that the HPET isn't a sysbus device */ + qdev_set_parent_bus(DEVICE(&s->hpet), sysbus_get_default()); + qdev_init_nofail(DEVICE(&s->hpet)); + + sysbus_mmio_map(SYS_BUS_DEVICE(&s->hpet), 0, HPET_BASE); + for (i = 0; i < GSI_NUM_PINS; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->hpet), i, s->pic[i]); + } + + rtc_irq = qdev_get_gpio_in(DEVICE(&s->hpet), HPET_LEGACY_RTC_INT); + } else { + isa_init_irq(ISA_DEVICE(&s->rtc), &rtc_irq, RTC_ISA_IRQ); + } + + /* Setup the RTC IRQ */ + s->rtc.irq = rtc_irq; + + /* Realize the PIT */ + qdev_set_parent_bus(DEVICE(&s->pit), &(s->bus->qbus)); + qdev_init_nofail(DEVICE(&s->pit)); + if (!xen_enabled()) { + if (!kvm_irqchip_in_kernel()) { + qdev_connect_gpio_out(DEVICE(&s->pit), + 0, qdev_get_gpio_in(DEVICE(&s->hpet), HPET_LEGACY_PIT_INT)); + } + qdev_connect_gpio_out(DEVICE(&s->hpet), 0, + qdev_get_gpio_in(DEVICE(&s->pit), 0)); + } + + /* FIXME this should be refactored */ + /* pcspk_init(s->bus, ISA_DEVICE(&s->pit)); */ + + return 0; +} + +static void piix3_initfn(Object *obj) +{ + PIIX3State *s = PIIX3(obj); + + qdev_prop_set_int32(DEVICE(s), "addr", PCI_DEVFN(1, 0)); + qdev_prop_set_bit(DEVICE(s), "multifunction", true); + + object_initialize(&s->hpet, TYPE_HPET); + object_property_add_child(obj, "hpet", OBJECT(&s->hpet), NULL); + + object_initialize(&s->rtc, TYPE_RTC); + object_property_add_child(obj, "rtc", OBJECT(&s->rtc), NULL); + qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000); + + object_initialize(&s->pit, TYPE_PIT); + object_property_add_child(obj, "pit", OBJECT(&s->pit), NULL); + qdev_prop_set_int32(DEVICE(&s->pit), "iobase", 0x40); +} + +static void piix3_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + dc->desc = "ISA bridge"; + dc->vmsd = &vmstate_piix3; + dc->no_user = 1; + dc->reset = piix3_reset; + k->no_hotplug = 1; + k->init = piix3_realize; + k->config_write = piix3_write_config; + k->vendor_id = PCI_VENDOR_ID_INTEL; + /* 82371SB PIIX3 PCI-to-ISA bridge (Step A1) */ + k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; + k->class_id = PCI_CLASS_BRIDGE_ISA; +} + +static TypeInfo piix3_info = { + .name = TYPE_PIIX3, + .parent = TYPE_PCI_DEVICE, + .instance_size = sizeof(PIIX3State), + .instance_init = piix3_initfn, + .class_init = piix3_class_init, +}; + +static void piix3_xen_class_init(ObjectClass *klass, void *data) +{ + PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); + + k->config_write = piix3_write_config_xen; +}; + +static TypeInfo piix3_xen_info = { + .name = "PIIX3-xen", + .parent = TYPE_PIIX3, + .instance_size = sizeof(PIIX3State), + .class_init = piix3_xen_class_init, +}; + +static void register_devices(void) +{ + type_register_static(&piix3_info); + type_register_static(&piix3_xen_info); +} +type_init(register_devices) diff --git a/hw/piix3.h b/hw/piix3.h new file mode 100644 index 0000000..18f08ec --- /dev/null +++ b/hw/piix3.h @@ -0,0 +1,79 @@ +/* + * QEMU PIIX3 PCI-ISA Bridge Emulation + * + * Copyright (c) 2006 Fabrice Bellard + * Copyright IBM, Corp. 2012 + * + * Authors: + * Anthony Liguori + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef QEMU_PIIX3_H +#define QEMU_PIIX3_H + +#include "pci.h" +#include "hpet_emul.h" +#include "mc146818rtc.h" +#include "i8254.h" +#include "i8254_internal.h" + +#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */ +#define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */ +#define XEN_PIIX_NUM_PIRQS 128ULL +#define PIIX_PIRQC 0x60 + +#define TYPE_PIIX3 "PIIX3" +#define PIIX3(obj) OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3) + +typedef struct PIIX3State { + PCIDevice dev; + + /* + * bitmap to track pic levels. + * The pic level is the logical OR of all the PCI irqs mapped to it + * So one PIC level is tracked by PIIX_NUM_PIRQS bits. + * + * PIRQ is mapped to PIC pins, we track it by + * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with + * pic_irq * PIIX_NUM_PIRQS + pirq + */ +#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64 +#error "unable to encode pic state in 64bit in pic_levels." +#endif + uint64_t pic_levels; + + bool hpet_enable; + + HPETState hpet; + RTCState rtc; + PITCommonState pit; + + ISABus *bus; + + qemu_irq *pic; + + /* This member isn't used. Just for save/load compatibility */ + int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS]; +} PIIX3State; + +void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level); + +#endif diff --git a/hw/piix_pci.c b/hw/piix_pci.c deleted file mode 100644 index 09e84f5..0000000 --- a/hw/piix_pci.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - * QEMU i440FX/PIIX3 PCI Bridge Emulation - * - * Copyright (c) 2006 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "hw.h" -#include "pc.h" -#include "pci.h" -#include "pci_host.h" -#include "isa.h" -#include "sysbus.h" -#include "range.h" -#include "xen.h" - -/* - * I440FX chipset data sheet. - * http://download.intel.com/design/chipsets/datashts/29054901.pdf - */ - -typedef PCIHostState I440FXState; - -#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */ -#define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */ -#define XEN_PIIX_NUM_PIRQS 128ULL -#define PIIX_PIRQC 0x60 - -typedef struct PIIX3State { - PCIDevice dev; - - /* - * bitmap to track pic levels. - * The pic level is the logical OR of all the PCI irqs mapped to it - * So one PIC level is tracked by PIIX_NUM_PIRQS bits. - * - * PIRQ is mapped to PIC pins, we track it by - * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with - * pic_irq * PIIX_NUM_PIRQS + pirq - */ -#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64 -#error "unable to encode pic state in 64bit in pic_levels." -#endif - uint64_t pic_levels; - - qemu_irq *pic; - - /* This member isn't used. Just for save/load compatibility */ - int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS]; -} PIIX3State; - -typedef struct PAMMemoryRegion { - MemoryRegion mem; - bool initialized; -} PAMMemoryRegion; - -struct PCII440FXState { - PCIDevice dev; - MemoryRegion *system_memory; - MemoryRegion *pci_address_space; - MemoryRegion *ram_memory; - MemoryRegion pci_hole; - MemoryRegion pci_hole_64bit; - PAMMemoryRegion pam_regions[13]; - MemoryRegion smram_region; - uint8_t smm_enabled; -}; - - -#define I440FX_PAM 0x59 -#define I440FX_PAM_SIZE 7 -#define I440FX_SMRAM 0x72 - -static void piix3_set_irq(void *opaque, int pirq, int level); -static void piix3_write_config_xen(PCIDevice *dev, - uint32_t address, uint32_t val, int len); - -/* return the global irq number corresponding to a given device irq - pin. We could also use the bus number to have a more precise - mapping. */ -static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx) -{ - int slot_addend; - slot_addend = (pci_dev->devfn >> 3) - 1; - return (pci_intx + slot_addend) & 3; -} - -static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r, - PAMMemoryRegion *mem) -{ - if (mem->initialized) { - memory_region_del_subregion(d->system_memory, &mem->mem); - memory_region_destroy(&mem->mem); - } - - // printf("ISA mapping %08x-0x%08x: %d\n", start, end, r); - switch(r) { - case 3: - /* RAM */ - memory_region_init_alias(&mem->mem, "pam-ram", d->ram_memory, - start, end - start); - break; - case 1: - /* ROM (XXX: not quite correct) */ - memory_region_init_alias(&mem->mem, "pam-rom", d->ram_memory, - start, end - start); - memory_region_set_readonly(&mem->mem, true); - break; - case 2: - case 0: - /* XXX: should distinguish read/write cases */ - memory_region_init_alias(&mem->mem, "pam-pci", d->pci_address_space, - start, end - start); - break; - } - memory_region_add_subregion_overlap(d->system_memory, - start, &mem->mem, 1); - mem->initialized = true; -} - -static void i440fx_update_memory_mappings(PCII440FXState *d) -{ - int i, r; - uint32_t smram; - bool smram_enabled; - - memory_region_transaction_begin(); - update_pam(d, 0xf0000, 0x100000, (d->dev.config[I440FX_PAM] >> 4) & 3, - &d->pam_regions[0]); - for(i = 0; i < 12; i++) { - r = (d->dev.config[(i >> 1) + (I440FX_PAM + 1)] >> ((i & 1) * 4)) & 3; - update_pam(d, 0xc0000 + 0x4000 * i, 0xc0000 + 0x4000 * (i + 1), r, - &d->pam_regions[i+1]); - } - smram = d->dev.config[I440FX_SMRAM]; - smram_enabled = (d->smm_enabled && (smram & 0x08)) || (smram & 0x40); - memory_region_set_enabled(&d->smram_region, !smram_enabled); - memory_region_transaction_commit(); -} - -static void i440fx_set_smm(int val, void *arg) -{ - PCII440FXState *d = arg; - - val = (val != 0); - if (d->smm_enabled != val) { - d->smm_enabled = val; - i440fx_update_memory_mappings(d); - } -} - - -static void i440fx_write_config(PCIDevice *dev, - uint32_t address, uint32_t val, int len) -{ - PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev); - - /* XXX: implement SMRAM.D_LOCK */ - pci_default_write_config(dev, address, val, len); - if (ranges_overlap(address, len, I440FX_PAM, I440FX_PAM_SIZE) || - range_covers_byte(address, len, I440FX_SMRAM)) { - i440fx_update_memory_mappings(d); - } -} - -static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id) -{ - PCII440FXState *d = opaque; - int ret, i; - - ret = pci_device_load(&d->dev, f); - if (ret < 0) - return ret; - i440fx_update_memory_mappings(d); - qemu_get_8s(f, &d->smm_enabled); - - if (version_id == 2) { - for (i = 0; i < PIIX_NUM_PIRQS; i++) { - qemu_get_be32(f); /* dummy load for compatibility */ - } - } - - return 0; -} - -static int i440fx_post_load(void *opaque, int version_id) -{ - PCII440FXState *d = opaque; - - i440fx_update_memory_mappings(d); - return 0; -} - -static const VMStateDescription vmstate_i440fx = { - .name = "I440FX", - .version_id = 3, - .minimum_version_id = 3, - .minimum_version_id_old = 1, - .load_state_old = i440fx_load_old, - .post_load = i440fx_post_load, - .fields = (VMStateField []) { - VMSTATE_PCI_DEVICE(dev, PCII440FXState), - VMSTATE_UINT8(smm_enabled, PCII440FXState), - VMSTATE_END_OF_LIST() - } -}; - -static int i440fx_pcihost_initfn(SysBusDevice *dev) -{ - I440FXState *s = FROM_SYSBUS(I440FXState, dev); - - memory_region_init_io(&s->conf_mem, &pci_host_conf_le_ops, s, - "pci-conf-idx", 4); - sysbus_add_io(dev, 0xcf8, &s->conf_mem); - sysbus_init_ioports(&s->busdev, 0xcf8, 4); - - memory_region_init_io(&s->data_mem, &pci_host_data_le_ops, s, - "pci-conf-data", 4); - sysbus_add_io(dev, 0xcfc, &s->data_mem); - sysbus_init_ioports(&s->busdev, 0xcfc, 4); - - return 0; -} - -static int i440fx_initfn(PCIDevice *dev) -{ - PCII440FXState *d = DO_UPCAST(PCII440FXState, dev, dev); - - d->dev.config[I440FX_SMRAM] = 0x02; - - cpu_smm_register(&i440fx_set_smm, d); - return 0; -} - -static PCIBus *i440fx_common_init(const char *device_name, - PCII440FXState **pi440fx_state, - int *piix3_devfn, - ISABus **isa_bus, qemu_irq *pic, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - ram_addr_t ram_size, - target_phys_addr_t pci_hole_start, - target_phys_addr_t pci_hole_size, - target_phys_addr_t pci_hole64_start, - target_phys_addr_t pci_hole64_size, - MemoryRegion *pci_address_space, - MemoryRegion *ram_memory) -{ - DeviceState *dev; - PCIBus *b; - PCIDevice *d; - I440FXState *s; - PIIX3State *piix3; - PCII440FXState *f; - - dev = qdev_create(NULL, "i440FX-pcihost"); - s = FROM_SYSBUS(I440FXState, sysbus_from_qdev(dev)); - s->address_space = address_space_mem; - b = pci_bus_new(&s->busdev.qdev, NULL, pci_address_space, - address_space_io, 0); - s->bus = b; - object_property_add_child(qdev_get_machine(), "i440fx", OBJECT(dev), NULL); - qdev_init_nofail(dev); - - d = pci_create_simple(b, 0, device_name); - *pi440fx_state = DO_UPCAST(PCII440FXState, dev, d); - f = *pi440fx_state; - f->system_memory = address_space_mem; - f->pci_address_space = pci_address_space; - f->ram_memory = ram_memory; - memory_region_init_alias(&f->pci_hole, "pci-hole", f->pci_address_space, - pci_hole_start, pci_hole_size); - memory_region_add_subregion(f->system_memory, pci_hole_start, &f->pci_hole); - memory_region_init_alias(&f->pci_hole_64bit, "pci-hole64", - f->pci_address_space, - pci_hole64_start, pci_hole64_size); - if (pci_hole64_size) { - memory_region_add_subregion(f->system_memory, pci_hole64_start, - &f->pci_hole_64bit); - } - memory_region_init_alias(&f->smram_region, "smram-region", - f->pci_address_space, 0xa0000, 0x20000); - memory_region_add_subregion_overlap(f->system_memory, 0xa0000, - &f->smram_region, 1); - memory_region_set_enabled(&f->smram_region, false); - - /* Xen supports additional interrupt routes from the PCI devices to - * the IOAPIC: the four pins of each PCI device on the bus are also - * connected to the IOAPIC directly. - * These additional routes can be discovered through ACPI. */ - if (xen_enabled()) { - piix3 = DO_UPCAST(PIIX3State, dev, - pci_create_simple_multifunction(b, -1, true, "PIIX3-xen")); - pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq, - piix3, XEN_PIIX_NUM_PIRQS); - } else { - piix3 = DO_UPCAST(PIIX3State, dev, - pci_create_simple_multifunction(b, -1, true, "PIIX3")); - pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, - PIIX_NUM_PIRQS); - } - piix3->pic = pic; - *isa_bus = DO_UPCAST(ISABus, qbus, - qdev_get_child_bus(&piix3->dev.qdev, "isa.0")); - - *piix3_devfn = piix3->dev.devfn; - - ram_size = ram_size / 8 / 1024 / 1024; - if (ram_size > 255) - ram_size = 255; - (*pi440fx_state)->dev.config[0x57]=ram_size; - - i440fx_update_memory_mappings(f); - - return b; -} - -PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, - ISABus **isa_bus, qemu_irq *pic, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io, - ram_addr_t ram_size, - target_phys_addr_t pci_hole_start, - target_phys_addr_t pci_hole_size, - target_phys_addr_t pci_hole64_start, - target_phys_addr_t pci_hole64_size, - MemoryRegion *pci_memory, MemoryRegion *ram_memory) - -{ - PCIBus *b; - - b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, isa_bus, pic, - address_space_mem, address_space_io, ram_size, - pci_hole_start, pci_hole_size, - pci_hole64_start, pci_hole64_size, - pci_memory, ram_memory); - return b; -} - -/* PIIX3 PCI to ISA bridge */ -static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq) -{ - qemu_set_irq(piix3->pic[pic_irq], - !!(piix3->pic_levels & - (((1ULL << PIIX_NUM_PIRQS) - 1) << - (pic_irq * PIIX_NUM_PIRQS)))); -} - -static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level) -{ - int pic_irq; - uint64_t mask; - - pic_irq = piix3->dev.config[PIIX_PIRQC + pirq]; - if (pic_irq >= PIIX_NUM_PIC_IRQS) { - return; - } - - mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq); - piix3->pic_levels &= ~mask; - piix3->pic_levels |= mask * !!level; - - piix3_set_irq_pic(piix3, pic_irq); -} - -static void piix3_set_irq(void *opaque, int pirq, int level) -{ - PIIX3State *piix3 = opaque; - piix3_set_irq_level(piix3, pirq, level); -} - -/* irq routing is changed. so rebuild bitmap */ -static void piix3_update_irq_levels(PIIX3State *piix3) -{ - int pirq; - - piix3->pic_levels = 0; - for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) { - piix3_set_irq_level(piix3, pirq, - pci_bus_get_irq_level(piix3->dev.bus, pirq)); - } -} - -static void piix3_write_config(PCIDevice *dev, - uint32_t address, uint32_t val, int len) -{ - pci_default_write_config(dev, address, val, len); - if (ranges_overlap(address, len, PIIX_PIRQC, 4)) { - PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev); - int pic_irq; - piix3_update_irq_levels(piix3); - for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) { - piix3_set_irq_pic(piix3, pic_irq); - } - } -} - -static void piix3_write_config_xen(PCIDevice *dev, - uint32_t address, uint32_t val, int len) -{ - xen_piix_pci_write_config_client(address, val, len); - piix3_write_config(dev, address, val, len); -} - -static void piix3_reset(void *opaque) -{ - PIIX3State *d = opaque; - uint8_t *pci_conf = d->dev.config; - - pci_conf[0x04] = 0x07; // master, memory and I/O - pci_conf[0x05] = 0x00; - pci_conf[0x06] = 0x00; - pci_conf[0x07] = 0x02; // PCI_status_devsel_medium - pci_conf[0x4c] = 0x4d; - pci_conf[0x4e] = 0x03; - pci_conf[0x4f] = 0x00; - pci_conf[0x60] = 0x80; - pci_conf[0x61] = 0x80; - pci_conf[0x62] = 0x80; - pci_conf[0x63] = 0x80; - pci_conf[0x69] = 0x02; - pci_conf[0x70] = 0x80; - pci_conf[0x76] = 0x0c; - pci_conf[0x77] = 0x0c; - pci_conf[0x78] = 0x02; - pci_conf[0x79] = 0x00; - pci_conf[0x80] = 0x00; - pci_conf[0x82] = 0x00; - pci_conf[0xa0] = 0x08; - pci_conf[0xa2] = 0x00; - pci_conf[0xa3] = 0x00; - pci_conf[0xa4] = 0x00; - pci_conf[0xa5] = 0x00; - pci_conf[0xa6] = 0x00; - pci_conf[0xa7] = 0x00; - pci_conf[0xa8] = 0x0f; - pci_conf[0xaa] = 0x00; - pci_conf[0xab] = 0x00; - pci_conf[0xac] = 0x00; - pci_conf[0xae] = 0x00; - - d->pic_levels = 0; -} - -static int piix3_post_load(void *opaque, int version_id) -{ - PIIX3State *piix3 = opaque; - piix3_update_irq_levels(piix3); - return 0; -} - -static void piix3_pre_save(void *opaque) -{ - int i; - PIIX3State *piix3 = opaque; - - for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) { - piix3->pci_irq_levels_vmstate[i] = - pci_bus_get_irq_level(piix3->dev.bus, i); - } -} - -static const VMStateDescription vmstate_piix3 = { - .name = "PIIX3", - .version_id = 3, - .minimum_version_id = 2, - .minimum_version_id_old = 2, - .post_load = piix3_post_load, - .pre_save = piix3_pre_save, - .fields = (VMStateField []) { - VMSTATE_PCI_DEVICE(dev, PIIX3State), - VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State, - PIIX_NUM_PIRQS, 3), - VMSTATE_END_OF_LIST() - } -}; - -static int piix3_initfn(PCIDevice *dev) -{ - PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev); - - isa_bus_new(&d->dev.qdev, pci_address_space_io(dev)); - qemu_register_reset(piix3_reset, d); - return 0; -} - -static void piix3_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - dc->desc = "ISA bridge"; - dc->vmsd = &vmstate_piix3; - dc->no_user = 1, - k->no_hotplug = 1; - k->init = piix3_initfn; - k->config_write = piix3_write_config; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) - k->class_id = PCI_CLASS_BRIDGE_ISA; -} - -static TypeInfo piix3_info = { - .name = "PIIX3", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PIIX3State), - .class_init = piix3_class_init, -}; - -static void piix3_xen_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - dc->desc = "ISA bridge"; - dc->vmsd = &vmstate_piix3; - dc->no_user = 1; - k->no_hotplug = 1; - k->init = piix3_initfn; - k->config_write = piix3_write_config_xen; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82371SB_0; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1) - k->class_id = PCI_CLASS_BRIDGE_ISA; -}; - -static TypeInfo piix3_xen_info = { - .name = "PIIX3-xen", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PIIX3State), - .class_init = piix3_xen_class_init, -}; - -static void i440fx_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - - k->no_hotplug = 1; - k->init = i440fx_initfn; - k->config_write = i440fx_write_config; - k->vendor_id = PCI_VENDOR_ID_INTEL; - k->device_id = PCI_DEVICE_ID_INTEL_82441; - k->revision = 0x02; - k->class_id = PCI_CLASS_BRIDGE_HOST; - dc->desc = "Host bridge"; - dc->no_user = 1; - dc->vmsd = &vmstate_i440fx; -} - -static TypeInfo i440fx_info = { - .name = "i440FX", - .parent = TYPE_PCI_DEVICE, - .instance_size = sizeof(PCII440FXState), - .class_init = i440fx_class_init, -}; - -static void i440fx_pcihost_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - - k->init = i440fx_pcihost_initfn; - dc->fw_name = "pci"; - dc->no_user = 1; -} - -static TypeInfo i440fx_pcihost_info = { - .name = "i440FX-pcihost", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(I440FXState), - .class_init = i440fx_pcihost_class_init, -}; - -static void i440fx_register_types(void) -{ - type_register_static(&i440fx_info); - type_register_static(&piix3_info); - type_register_static(&piix3_xen_info); - type_register_static(&i440fx_pcihost_info); -} - -type_init(i440fx_register_types)