qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2 12/21] q35: Introduce q35 pc based chipset em


From: Michael S. Tsirkin
Subject: Re: [Qemu-devel] [PATCH v2 12/21] q35: Introduce q35 pc based chipset emulator
Date: Thu, 11 Oct 2012 16:47:43 +0200

On Mon, Oct 08, 2012 at 11:30:32PM -0400, Jason Baron wrote:
> From: Isaku Yamahata <address@hidden>
> 
> pc q35 based chipset emulator to support pci express natively.
> 
> Signed-off-by: Isaku Yamahata <address@hidden>
> Signed-off-by: Jason Baron <address@hidden>

Preferable to smash this with the next patch, this split
along historical rather than logical lines
complicates review.

> ---
>  hw/acpi_ich9.c |  315 ++++++++++++++++++++
>  hw/acpi_ich9.h |   53 ++++
>  hw/pc_q35.c    |  378 ++++++++++++++++++++++++
>  hw/pci_ids.h   |   14 +
>  hw/q35.c       |  877 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/q35.h       |  272 ++++++++++++++++++
>  hw/q35_smbus.c |  154 ++++++++++
>  7 files changed, 2063 insertions(+), 0 deletions(-)
>  create mode 100644 hw/acpi_ich9.c
>  create mode 100644 hw/acpi_ich9.h
>  create mode 100644 hw/pc_q35.c
>  create mode 100644 hw/q35.c
>  create mode 100644 hw/q35.h
>  create mode 100644 hw/q35_smbus.c
> 
> diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c
> new file mode 100644
> index 0000000..59c0807
> --- /dev/null
> +++ b/hw/acpi_ich9.c
> @@ -0,0 +1,315 @@
> +/*
> + * ACPI implementation
> + *
> + * Copyright (c) 2006 Fabrice Bellard
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License version 2 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see 
> <http://www.gnu.org/licenses/>
> + */
> +/*
> + *  Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> + *                     VA Linux Systems Japan K.K.
> + *
> + *  This is based on acpi.c.
> + */
> +#include "hw.h"
> +#include "pc.h"
> +#include "pci.h"
> +#include "qemu-timer.h"
> +#include "sysemu.h"
> +#include "acpi.h"
> +
> +#include "q35.h"
> +
> +//#define DEBUG
> +
> +#ifdef DEBUG
> +#define ICH9_DEBUG(fmt, ...) \
> +do { printf("%s "fmt, __func__, ## __VA_ARGS__); } while (0)
> +#else
> +#define ICH9_DEBUG(fmt, ...)    do { } while (0)
> +#endif
> +
> +static void pm_ioport_write_fallback(void *opaque, uint32_t addr, int len,
> +                                     uint32_t val);
> +static uint32_t pm_ioport_read_fallback(void *opaque, uint32_t addr, int 
> len);
> +
> +static void pm_update_sci(ICH9_LPCPmRegs *pm)
> +{
> +    int sci_level, pm1a_sts;
> +
> +    pm1a_sts = acpi_pm1_evt_get_sts(&pm->pm1a, pm->tmr.overflow_time);
> +
> +    sci_level = (((pm1a_sts & pm->pm1a.en) &
> +                  (ACPI_BITMASK_RT_CLOCK_ENABLE |
> +                   ACPI_BITMASK_POWER_BUTTON_ENABLE |
> +                   ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
> +                   ACPI_BITMASK_TIMER_ENABLE)) != 0);
> +    qemu_set_irq(pm->irq, sci_level);
> +
> +    /* schedule a timer interruption if needed */
> +    acpi_pm_tmr_update(&pm->tmr,
> +                       (pm->pm1a.en & ACPI_BITMASK_TIMER_ENABLE) &&
> +                       !(pm1a_sts & ACPI_BITMASK_TIMER_STATUS));
> +}
> +
> +static void ich9_pm_update_sci_fn(ACPIPMTimer *tmr)
> +{
> +    ICH9_LPCPmRegs *pm = container_of(tmr, ICH9_LPCPmRegs, tmr);
> +    pm_update_sci(pm);
> +}
> +
> +static void pm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    ICH9_LPCPmRegs *pm = opaque;
> +
> +    switch (addr & ICH9_PMIO_MASK) {
> +    case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + ICH9_PMIO_GPE0_LEN - 
> 1):
> +        acpi_gpe_ioport_writeb(&pm->gpe0, addr, val);
> +        break;
> +    default:
> +        break;
> +    }
> +
> +    ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
> +}
> +
> +static uint32_t pm_ioport_readb(void *opaque, uint32_t addr)
> +{
> +    ICH9_LPCPmRegs *pm = opaque;
> +    uint32_t val = 0;
> +
> +    switch (addr & ICH9_PMIO_MASK) {
> +    case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + ICH9_PMIO_GPE0_LEN - 
> 1):
> +        val = acpi_gpe_ioport_readb(&pm->gpe0, addr);
> +        break;
> +    default:
> +        val = 0;
> +        break;
> +    }
> +    ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
> +    return val;
> +}
> +
> +static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    ICH9_LPCPmRegs *pm = opaque;
> +
> +    switch (addr & ICH9_PMIO_MASK) {
> +    case ICH9_PMIO_PM1_STS:
> +        acpi_pm1_evt_write_sts(&pm->pm1a, &pm->tmr, val);
> +        pm_update_sci(pm);
> +        break;
> +    case ICH9_PMIO_PM1_EN:
> +        pm->pm1a.en = val;
> +        pm_update_sci(pm);
> +        break;
> +    case ICH9_PMIO_PM1_CNT:
> +        acpi_pm1_cnt_write(&pm->pm1a, &pm->pm1_cnt, val);
> +        break;
> +    default:
> +        pm_ioport_write_fallback(opaque, addr, 2, val);
> +        break;
> +    }
> +    ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
> +}
> +
> +static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
> +{
> +    ICH9_LPCPmRegs *pm = opaque;
> +    uint32_t val;
> +
> +    switch (addr & ICH9_PMIO_MASK) {
> +    case ICH9_PMIO_PM1_STS:
> +        val = acpi_pm1_evt_get_sts(&pm->pm1a, pm->tmr.overflow_time);
> +        break;
> +    case ICH9_PMIO_PM1_EN:
> +        val = pm->pm1a.en;
> +        break;
> +    case ICH9_PMIO_PM1_CNT:
> +        val = pm->pm1_cnt.cnt;
> +        break;
> +    default:
> +        val = pm_ioport_read_fallback(opaque, addr, 2);
> +        break;
> +    }
> +    ICH9_DEBUG("port=0x%04x val=0x%04x\n", addr, val);
> +    return val;
> +}
> +
> +static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    ICH9_LPCPmRegs *pm = opaque;
> +
> +    switch (addr & ICH9_PMIO_MASK) {
> +    case ICH9_PMIO_SMI_EN:
> +        pm->smi_en = val;
> +        break;
> +    default:
> +        pm_ioport_write_fallback(opaque, addr, 4, val);
> +        break;
> +    }
> +    ICH9_DEBUG("port=0x%04x val=0x%08x\n", addr, val);
> +}
> +
> +static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
> +{
> +    ICH9_LPCPmRegs *pm = opaque;
> +    uint32_t val;
> +
> +    switch (addr & ICH9_PMIO_MASK) {
> +    case ICH9_PMIO_PM1_TMR:
> +        val = acpi_pm_tmr_get(&pm->tmr);
> +        break;
> +    case ICH9_PMIO_SMI_EN:
> +        val = pm->smi_en;
> +        break;
> +
> +    default:
> +        val = pm_ioport_read_fallback(opaque, addr, 4);
> +        break;
> +    }
> +    ICH9_DEBUG("port=0x%04x val=0x%08x\n", addr, val);
> +    return val;
> +}
> +
> +static void pm_ioport_write_fallback(void *opaque, uint32_t addr, int len,
> +                                     uint32_t val)
> + {
> +    int subsize = (len == 4) ? 2 : 1;
> +    IOPortWriteFunc *ioport_write =
> +        (subsize == 2) ? pm_ioport_writew : pm_ioport_writeb;
> +
> +    int i;
> +
> +    for (i = 0; i < len; i += subsize) {
> +        ioport_write(opaque, addr, val);
> +        val >>= 8 * subsize;
> +    }
> +}
> +
> +static uint32_t pm_ioport_read_fallback(void *opaque, uint32_t addr, int len)
> +{
> +    int subsize = (len == 4) ? 2 : 1;
> +    IOPortReadFunc *ioport_read =
> +        (subsize == 2) ? pm_ioport_readw : pm_ioport_readb;
> +
> +    uint32_t val;
> +    int i;
> +
> +    val = 0;
> +    for (i = 0; i < len; i += subsize) {
> +        val <<= 8 * subsize;
> +        val |= ioport_read(opaque, addr);
> +    }
> +
> +    return val;
> +}
> +
> +void ich9_pm_iospace_update(ICH9_LPCPmRegs *pm, uint32_t pm_io_base)
> +{
> +    ICH9_DEBUG("to 0x%x\n", pm_io_base);
> +
> +    assert((pm_io_base & ICH9_PMIO_MASK) == 0);
> +
> +    if (pm->pm_io_base != 0) {
> +        isa_unassign_ioport(pm->pm_io_base, ICH9_PMIO_SIZE);
> +    }
> +
> +    /* don't map at 0 */
> +    if (pm_io_base == 0) {
> +        return;
> +    }
> +
> +    register_ioport_write(pm_io_base, ICH9_PMIO_SIZE, 1, pm_ioport_writeb, 
> pm);
> +    register_ioport_read(pm_io_base, ICH9_PMIO_SIZE, 1, pm_ioport_readb, pm);
> +    register_ioport_write(pm_io_base, ICH9_PMIO_SIZE, 2, pm_ioport_writew, 
> pm);
> +    register_ioport_read(pm_io_base, ICH9_PMIO_SIZE, 2, pm_ioport_readw, pm);
> +    register_ioport_write(pm_io_base, ICH9_PMIO_SIZE, 4, pm_ioport_writel, 
> pm);
> +    register_ioport_read(pm_io_base, ICH9_PMIO_SIZE, 4, pm_ioport_readl, pm);
> +
> +    pm->pm_io_base = pm_io_base;
> +    acpi_gpe_blk(&pm->gpe0, pm_io_base + ICH9_PMIO_GPE0_STS);
> +}
> +
> +static int ich9_pm_post_load(void *opaque, int version_id)
> +{
> +    ICH9_LPCPmRegs *pm = opaque;
> +    uint32_t pm_io_base = pm->pm_io_base;
> +    pm->pm_io_base = 0;
> +    ich9_pm_iospace_update(pm, pm_io_base);
> +    return 0;
> +}
> +
> +#define VMSTATE_GPE_ARRAY(_field, _state)                            \
> + {                                                                   \
> +     .name       = (stringify(_field)),                              \
> +     .version_id = 0,                                                \
> +     .num        = ICH9_PMIO_GPE0_LEN,                               \
> +     .info       = &vmstate_info_uint8,                              \
> +     .size       = sizeof(uint8_t),                                  \
> +     .flags      = VMS_ARRAY | VMS_POINTER,                          \
> +     .offset     = vmstate_offset_pointer(_state, _field, uint8_t),  \
> + }
> +
> +const VMStateDescription vmstate_ich9_pm = {
> +    .name = "ich9_pm",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .post_load = ich9_pm_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT16(pm1a.sts, ICH9_LPCPmRegs),
> +        VMSTATE_UINT16(pm1a.en, ICH9_LPCPmRegs),
> +        VMSTATE_UINT16(pm1_cnt.cnt, ICH9_LPCPmRegs),
> +        VMSTATE_TIMER(tmr.timer, ICH9_LPCPmRegs),
> +        VMSTATE_INT64(tmr.overflow_time, ICH9_LPCPmRegs),
> +        VMSTATE_GPE_ARRAY(gpe0.sts, ICH9_LPCPmRegs),
> +        VMSTATE_GPE_ARRAY(gpe0.en, ICH9_LPCPmRegs),
> +        VMSTATE_UINT32(smi_en, ICH9_LPCPmRegs),
> +        VMSTATE_UINT32(smi_sts, ICH9_LPCPmRegs),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void pm_reset(void *opaque)
> +{
> +    ICH9_LPCPmRegs *pm = opaque;
> +    ich9_pm_iospace_update(pm, 0);
> +
> +    acpi_pm1_evt_reset(&pm->pm1a);
> +    acpi_pm1_cnt_reset(&pm->pm1_cnt);
> +    acpi_pm_tmr_reset(&pm->tmr);
> +    acpi_gpe_reset(&pm->gpe0);
> +
> +    pm_update_sci(pm);
> +}
> +
> +static void pm_powerdown(void *opaque, int irq, int power_failing)
> +{
> +    ICH9_LPCPmRegs *pm = opaque;
> +    ACPIPM1EVT *pm1a = pm ? &pm->pm1a : NULL;
> +    ACPIPMTimer *tmr = pm ? &pm->tmr : NULL;
> +
> +    acpi_pm1_evt_power_down(pm1a, tmr);
> +}
> +
> +void ich9_pm_init(ICH9_LPCPmRegs *pm, qemu_irq sci_irq, qemu_irq cmos_s3)
> +{
> +    acpi_pm_tmr_init(&pm->tmr, ich9_pm_update_sci_fn);
> +    acpi_pm1_cnt_init(&pm->pm1_cnt, cmos_s3);
> +    acpi_gpe_init(&pm->gpe0, ICH9_PMIO_GPE0_LEN);
> +
> +    pm->irq = sci_irq;
> +    qemu_register_reset(pm_reset, pm);
> +    qemu_system_powerdown = *qemu_allocate_irqs(pm_powerdown, pm, 1);
> +}
> diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h
> new file mode 100644
> index 0000000..f55c0e9
> --- /dev/null
> +++ b/hw/acpi_ich9.h
> @@ -0,0 +1,53 @@
> +/*
> + * QEMU GMCH/ICH9 LPC PM Emulation
> + *
> + *  Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> + *                     VA Linux Systems Japan K.K.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see 
> <http://www.gnu.org/licenses/>
> + */
> +
> +#ifndef HW_ACPI_ICH9_H
> +#define HW_ACPI_ICH9_H
> +
> +#include "acpi.h"
> +
> +typedef struct ICH9_LPCPmRegs {
> +    ACPIPM1EVT pm1a;
> +
> +    /*
> +     * In ich9 spec says that pm1_cnt register is 32bit width and
> +     * that the upper 16bits are reserved and unused.
> +     * PM1a_CNT_BLK = 2 in FADT so it is defined as uint16_t.
> +     */
> +    ACPIPM1CNT pm1_cnt;
> +
> +    ACPIPMTimer tmr;
> +
> +    ACPIGPE gpe0;
> +
> +    uint32_t smi_en;
> +    uint32_t smi_sts;
> +
> +    qemu_irq irq;      /* SCI */
> +
> +    uint32_t pm_io_base;
> +} ICH9_LPCPmRegs;
> +
> +void ich9_pm_init(ICH9_LPCPmRegs *pm,
> +                  qemu_irq sci_irq, qemu_irq cmos_s3_resume);
> +void ich9_pm_iospace_update(ICH9_LPCPmRegs *pm, uint32_t pm_io_base);
> +extern const VMStateDescription vmstate_ich9_pm;
> +
> +#endif /* HW_ACPI_ICH9_H */
> diff --git a/hw/pc_q35.c b/hw/pc_q35.c
> new file mode 100644
> index 0000000..4f75d97
> --- /dev/null
> +++ b/hw/pc_q35.c
> @@ -0,0 +1,378 @@
> +/*
> + * QEMU PC System Emulator
> + *
> + * Copyright (c) 2003-2004 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.
> + */
> +/*
> + *  Q35 chipset based pc system emulator
> + *
> + *  Copyright (c) 2009, 2010
> + *                     Isaku Yamahata <yamahata at valinux co jp>
> + *                     VA Linux Systems Japan K.K.
> + *
> + *  This is based on pc.c, but heavily modified.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see 
> <http://www.gnu.org/licenses/>
> + */
> +#include "hw.h"
> +#include "arch_init.h"
> +#include "pc.h"
> +#include "fdc.h"
> +#include "pci.h"
> +#include "pci_bridge.h"
> +#include "pci_p2pbr.h"
> +#include "ioh3420.h"
> +#include "xio3130_upstream.h"
> +#include "xio3130_downstream.h"
> +#include "block.h"
> +#include "blockdev.h"
> +#include "sysemu.h"
> +#include "audio/audio.h"
> +#include "net.h"
> +#include "smbus.h"
> +#include "boards.h"
> +#include "monitor.h"
> +#include "fw_cfg.h"
> +#include "hpet_emul.h"
> +#include "watchdog.h"
> +#include "smbios.h"
> +#include "ide.h"
> +#include "usb-uhci.h"
> +
> +#include "q35.h"
> +
> +/* ICH9 AHCI has 6 ports */
> +#define MAX_SATA_PORTS     6
> +
> +#define I21154_REV            0x05
> +#define I21154_PI             0x00
> +
> +static PCIBridge *i21154_init(PCIBus *bus, int devfn, const char *bus_name,
> +                              bool multifunction)
> +{
> +    const PCIP2PBridgeInit init = {
> +        .bus = bus,
> +        .devfn = devfn,
> +        .multifunction = multifunction,
> +
> +        .bus_name = bus_name,
> +        .map_irq = pci_swizzle_map_irq_fn,
> +    };
> +    const PCIP2PBridgeProp prop = {
> +        .vendor_id = PCI_VENDOR_ID_DEC,
> +        .device_id = PCI_DEVICE_ID_DEC_21154,
> +        .revision_id = I21154_REV,
> +        .prog_interface = I21154_PI,
> +    };
> +    return pci_p2pbr_create_simple(&init, &prop);
> +}
> +
> +static void pc_q35_bridge_init(PCIBus *host_bus, PCIBus *pci_bus)
> +{
> +    uint8_t dev;
> +    uint8_t sec_bus;
> +    uint8_t port = 0;
> +    uint8_t chassis = 0;
> +    uint16_t slot = 0;
> +    uint8_t upstream_port;
> +    PCIESlot *s;
> +    uint8_t fn;
> +    PCIESlot *root_port;
> +    PCIBus *root_port_bus;
> +    char buf[16];
> +
> +    /* PCI to PCI bridge b6:d[29 - 31]:f0, 6:[1c - 1f].0 with subordinate bus
> +       of 7 - 9 on b0:d30:f0, 0.1e.0 = bus */
> +#define Q35_P2P_BRDIGE_DEV_BASE         28
> +#define Q35_P2P_BRDIGE_DEV_MAX          32
> +#define Q35_P2P_BRDIGE_SUBBUS_BASE      (ICH9_D2P_SECONDARY_DEFAULT + 1)
> +    for (dev = Q35_P2P_BRDIGE_DEV_BASE; dev < Q35_P2P_BRDIGE_DEV_MAX; dev++) 
> {
> +        PCIBridge *br;
> +        sec_bus = Q35_P2P_BRDIGE_SUBBUS_BASE + dev - Q35_P2P_BRDIGE_DEV_BASE;
> +
> +        snprintf(buf, sizeof(buf), "pci.%d", sec_bus);
> +        br = i21154_init(pci_bus, PCI_DEVFN(dev, 0), buf, true);
> +    }
> +
> +    /* PCIe root port b0:d1:f0 in GMCH.
> +     * Actually it's vid/did = 0x8086:0x29c1, but we substitute ioh for it.
> +     */
> +    sec_bus = 32;
> +    snprintf(buf, sizeof(buf), "pcie.%d", sec_bus);
> +    s = ioh3420_init(host_bus, PCI_DEVFN(GMCH_PCIE_DEV, GMCH_PCIE_FUNC), 
> true,
> +                     buf, pci_swizzle_map_irq_fn, port, chassis, slot);
> +
> +
> +    /* more slots. ICH9 doesn't have those, but many slots are wanted. */
> +//#define Q35_MANY_SLOTS
> +#undef Q35_MANY_SLOTS
> +
> +#ifdef Q35_MANY_SLOTS
> +#define Q35_NR_ROOTPORT         6
> +#define Q35_NR_UPSTREAM         8
> +#define Q35_NR_DOWNSTREAM       16
> +#else
> +#define Q35_NR_ROOTPORT         1
> +#define Q35_NR_UPSTREAM         1
> +#define Q35_NR_DOWNSTREAM       1
> +#endif
> +
> +    /* PCIe root port b0:d23:f[0-5], 0.17.[0-5] */
> +    for (fn = 0; fn < Q35_NR_ROOTPORT; fn++) {
> +        sec_bus++;
> +        port++;
> +        slot++;
> +
> +        snprintf(buf, sizeof(buf), "pcie.%d", sec_bus);
> +        s = ioh3420_init(host_bus, PCI_DEVFN(23, fn), true,
> +                         buf, pci_swizzle_map_irq_fn, port, chassis, slot);
> +    }
> +
> +    /* PCIe root port b0:d24:f0 */
> +    sec_bus++;
> +    port++;
> +    slot++;
> +    snprintf(buf, sizeof(buf), "pcie.%d", sec_bus);
> +    root_port = ioh3420_init(host_bus, PCI_DEVFN(24, 0), true,
> +                             buf, pci_swizzle_map_irq_fn, port, chassis, 
> slot);
> +    root_port_bus = pci_bridge_get_sec_bus(&root_port->port.br);
> +
> +    /* 8 * 16 = 128 slots */
> +    upstream_port = 0;
> +    for (fn = 0; fn < Q35_NR_UPSTREAM; fn++) {
> +        PCIEPort *upstream;
> +        PCIBus *upstream_bus;
> +        uint16_t downstream_port;
> +
> +        uint8_t ds_dev_max;
> +        uint8_t ds_dev;
> +        uint8_t ds_fn_max;
> +        uint8_t ds_fn;
> +
> +        /* PCIe upstream port d0:f[0-7] */
> +        sec_bus++;
> +        snprintf(buf, sizeof(buf), "pcie.%d", sec_bus);
> +        upstream = xio3130_upstream_init(root_port_bus, PCI_DEVFN(0, fn),
> +                                         true, buf, pci_swizzle_map_irq_fn,
> +                                         upstream_port);
> +
> +        upstream_bus = pci_bridge_get_sec_bus(&upstream->br);
> +        upstream_port++;
> +
> +        /* PCIe downstream port */
> +        downstream_port = 0;
> +        ds_fn_max = MIN(Q35_NR_DOWNSTREAM / PCI_SLOT_MAX, PCI_FUNC_MAX);
> +        ds_dev_max = MIN(Q35_NR_DOWNSTREAM / (ds_fn_max + 1), PCI_SLOT_MAX);
> +
> +        for (ds_dev = 0; ds_dev <= ds_dev_max &&
> +                 downstream_port < Q35_NR_DOWNSTREAM; ds_dev++) {
> +            for (ds_fn = 0; ds_fn <= ds_fn_max &&
> +                     downstream_port < Q35_NR_DOWNSTREAM; ds_fn++) {
> +                sec_bus++;
> +                slot++;
> +                snprintf(buf, sizeof(buf), "pcie.%d", sec_bus);
> +
> +                xio3130_downstream_init(upstream_bus, PCI_DEVFN(ds_dev, 
> ds_fn),
> +                                        true, buf, pci_swizzle_map_irq_fn,
> +                                        downstream_port, chassis, slot);
> +                downstream_port++;
> +            }
> +        }
> +    }
> +
> +    /* PCIe root port b0:d28:f[0-6] in ICH9.
> +     * Actually it's vid/did = 0x8086:0x294[02468A], but we substitute ioh
> +     * for them.
> +     */
> +    for (fn = 0; fn < ICH9_PCIE_FUNC_MAX; fn++) {
> +        sec_bus++;
> +        port++;
> +        slot++;
> +
> +        snprintf(buf, sizeof(buf), "pcie.%d", sec_bus);
> +        s = ioh3420_init(host_bus, PCI_DEVFN(ICH9_PCIE_DEV, fn), true,
> +                         buf, pci_swizzle_map_irq_fn,
> +                         port, chassis, slot);
> +    }
> +}
> +
> +static void pc_q35_init_early(qemu_irq *isa_irq, IsaIrqState *isa_irq_state,
> +                              DeviceState **gmch_host_p,
> +                              PCIBus **host_bus_p, PCIBus **pci_bus_p,
> +                              PCIDevice **lpc_p)
> +{
> +    DeviceState *gmch_host;
> +    PCIBus *host_bus;
> +    PCIBus *pci_bus;
> +
> +    PCIDevice *gmch_state;
> +    PCIDevice *lpc;
> +
> +    /* create pci host bus */
> +    host_bus = gmch_host_init(&gmch_host, isa_irq, isa_irq_state->ioapic);
> +    gmch_state = gmch_init(gmch_host, host_bus);
> +
> +    /* create conventional pci bus: pcie2pci bridge */
> +    pci_bus = ich9_d2pbr_init(host_bus, PCI_DEVFN(ICH9_D2P_BRIDGE_DEV,
> +                                                  ICH9_D2P_BRIDGE_FUNC),
> +                              ICH9_D2P_SECONDARY_DEFAULT);
> +
> +    /* create child pci/pcie buses */
> +    pc_q35_bridge_init(host_bus, pci_bus);
> +
> +    /* create ISA bus */
> +    lpc = gmch_lpc_init(gmch_host, host_bus);
> +
> +    *gmch_host_p = gmch_host;
> +    *host_bus_p = host_bus;
> +    *pci_bus_p = pci_bus;
> +    *lpc_p = lpc;
> +}
> +
> +static void pc_q35_init_late(BusState **idebus, ISADevice *rtc_state,
> +                             DeviceState *gmch_host,
> +                             PCIBus *host_bus, PCIBus *pci_bus,
> +                             PCIDevice *lpc)
> +{
> +    qemu_irq *cmos_s3;
> +    PCIDevice *ahci;
> +    DriveInfo *hd[MAX_SATA_PORTS * MAX_IDE_DEVS];
> +
> +    /* connect pm stuff to lpc */
> +    cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
> +    ich9_lpc_pm_init(gmch_host, lpc, *cmos_s3);
> +
> +    /* ahci and SATA device */
> +    ide_drive_get(hd, MAX_SATA_PORTS);
> +    ahci = pci_create_simple_multifunction(host_bus,
> +                                           PCI_DEVFN(ICH9_SATA1_DEV,
> +                                                     ICH9_SATA1_FUNC),
> +                                           true, "ich9-ahci");
> +    pci_ahci_ide_create_devs(ahci, hd);
> +    idebus[0] = qdev_get_child_bus(&ahci->qdev, "ide.0");
> +    idebus[1] = qdev_get_child_bus(&ahci->qdev, "ide.1");
> +
> +    if (usb_enabled) {
> +        /* Should we create 6 UHCI according to ich9 spec? */
> +        pci_create_simple_multifunction(
> +            host_bus, PCI_DEVFN(ICH9_USB_UHCI1_DEV, ICH9_USB_UHCI1_FUNC),
> +            true, "ich9-usb-uhci1");
> +        /* XXX: EHCI */
> +    }
> +
> +    /* TODO: Populate SPD eeprom data.  */
> +    smbus_eeprom_init(ich9_smb_init(host_bus,
> +                                    PCI_DEVFN(ICH9_SMB_DEV, ICH9_SMB_FUNC),
> +                                    0xb100),
> +                      8, NULL, 0);
> +}
> +
> +/* PC hardware initialisation */
> +static void pc_q35_init(ram_addr_t ram_size,
> +                        const char *boot_device,
> +                        const char *kernel_filename,
> +                        const char *kernel_cmdline,
> +                        const char *initrd_filename,
> +                        const char *cpu_model)
> +{
> +    ram_addr_t below_4g_mem_size, above_4g_mem_size;
> +    DeviceState *gmch_host;
> +    PCIBus *host_bus;
> +    PCIBus *pci_bus;
> +    PCIDevice *lpc;
> +    qemu_irq *isa_irq;
> +    IsaIrqState *isa_irq_state;
> +    BusState *idebus[MAX_SATA_PORTS];
> +    ISADevice *rtc_state;
> +    MemoryRegion *pci_memory;
> +    MemoryRegion *rom_memory;
> +    MemoryRegion *ram_memory;
> +
> +    pc_cpus_init(cpu_model);
> +
> +    /* FIXME: add kvm clock ? */
> +
> +    if (ram_size >= 0xe0000000) {
> +        above_4g_mem_size = ram_size - 0xe0000000;
> +        below_4g_mem_size = 0xe0000000;
> +    } else {
> +        above_4g_mem_size = 0;
> +        below_4g_mem_size = ram_size;
> +    }
> +
> +    /* pci enabled */
> +    pci_memory = g_new(MemoryRegion, 1);
> +    memory_region_init(pci_memory, "pci", INT64_MAX);
> +    rom_memory = pci_memory;
> +
> +    /* allocate ram and load rom/bios */
> +    pc_memory_init(get_system_memory(), kernel_filename, kernel_cmdline,
> +                   initrd_filename, below_4g_mem_size, above_4g_mem_size,
> +                   rom_memory, &ram_memory);
> +
> +    /* irq lines */
> +    isa_irq = pc_isa_irq(&isa_irq_state);
> +    ioapic_init(isa_irq_state);
> +
> +    pc_q35_init_early(isa_irq, isa_irq_state,
> +                      &gmch_host, &host_bus, &pci_bus, &lpc);
> +    isa_bus_irqs(isa_irq);
> +    pc_register_ferr_irq(isa_get_irq(13));
> +
> +    /* init basic PC hardware */
> +    pc_basic_device_init(isa_irq, &rtc_state, false);
> +
> +    pc_q35_init_late(idebus, rtc_state, gmch_host, host_bus, pci_bus, lpc);
> +
> +    pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device,
> +                 idebus[0], idebus[1], rtc_state);
> +
> +    /* the rest devices to which pci devfn is automatically assigned */
> +    pc_vga_init(host_bus);
> +    audio_init(isa_irq, pci_bus);
> +    pc_nic_init(pci_bus);
> +    pc_pci_device_init(pci_bus);
> +}
> +
> +static QEMUMachine pc_q35_machine = {
> +    .name = "pc_q35",
> +    .desc = "Q35 chipset PC",
> +    .init = pc_q35_init,
> +    .max_cpus = 255,
> +};
> +
> +static void pc_q35_machine_init(void)
> +{
> +    qemu_register_machine(&pc_q35_machine);
> +}
> +
> +machine_init(pc_q35_machine_init);
> diff --git a/hw/pci_ids.h b/hw/pci_ids.h
> index 6deeac0..50744dd 100644
> --- a/hw/pci_ids.h
> +++ b/hw/pci_ids.h
> @@ -36,6 +36,7 @@
>  #define PCI_CLASS_BRIDGE_HOST            0x0600
>  #define PCI_CLASS_BRIDGE_ISA             0x0601
>  #define PCI_CLASS_BRIDGE_PCI             0x0604
> +#define  PCI_CLASS_BRDIGE_PCI_INF_SUB    0x01
>  #define PCI_CLASS_BRIDGE_OTHER           0x0680
>  
>  #define PCI_CLASS_COMMUNICATION_OTHER    0x0780
> @@ -115,6 +116,17 @@
>  #define PCI_DEVICE_ID_INTEL_82371AB      0x7111
>  #define PCI_DEVICE_ID_INTEL_82371AB_2    0x7112
>  #define PCI_DEVICE_ID_INTEL_82371AB_3    0x7113
> +
> +#define PCI_DEVICE_ID_INTEL_ICH9_0       0x2910
> +#define PCI_DEVICE_ID_INTEL_ICH9_1       0x2917
> +#define PCI_DEVICE_ID_INTEL_ICH9_2       0x2912
> +#define PCI_DEVICE_ID_INTEL_ICH9_3       0x2913
> +#define PCI_DEVICE_ID_INTEL_ICH9_4       0x2914
> +#define PCI_DEVICE_ID_INTEL_ICH9_5       0x2919
> +#define PCI_DEVICE_ID_INTEL_ICH9_6       0x2930
> +#define PCI_DEVICE_ID_INTEL_ICH9_7       0x2916
> +#define PCI_DEVICE_ID_INTEL_ICH9_8       0x2918
> +
>  #define PCI_DEVICE_ID_INTEL_82801I_UHCI1 0x2934
>  #define PCI_DEVICE_ID_INTEL_82801I_UHCI2 0x2935
>  #define PCI_DEVICE_ID_INTEL_82801I_UHCI3 0x2936
> @@ -125,6 +137,8 @@
>  #define PCI_DEVICE_ID_INTEL_82801I_EHCI2 0x293c
>  #define PCI_DEVICE_ID_INTEL_82599_SFP_VF 0x10ed
>  
> +#define PCI_DEVICE_ID_INTEL_Q35_MCH      0x29c0
> +
>  #define PCI_VENDOR_ID_XEN               0x5853
>  #define PCI_DEVICE_ID_XEN_PLATFORM      0x0001
>  
> diff --git a/hw/q35.c b/hw/q35.c
> new file mode 100644
> index 0000000..1776ac3
> --- /dev/null
> +++ b/hw/q35.c
> @@ -0,0 +1,877 @@
> +/*
> + * 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.
> + */
> +/*
> + * QEMU GMCH/ICH9 PCI Bridge Emulation
> + *
> + *  Copyright (c) 2009, 2010, 2011
> + *                Isaku Yamahata <yamahata at valinux co jp>
> + *                VA Linux Systems Japan K.K.
> + *
> + *  This is based on piix_pci.c, but heavily modified.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see 
> <http://www.gnu.org/licenses/>
> + */
> +
> +#include "hw.h"
> +#include "range.h"
> +#include "isa.h"
> +#include "sysbus.h"
> +#include "pc.h"
> +#include "apm.h"
> +#include "apic.h"
> +#include "pci.h"
> +#include "pcie_host.h"
> +#include "pci_bridge.h"
> +#include "pci_p2pbr.h"
> +#include "q35.h"
> +#include "acpi.h"
> +#include "acpi_ich9.h"
> +#include "pam.h"
> +
> +
> +struct ICH9_LPCState;
> +
> +typedef struct ICH9_LPCIrqState {
> +    struct ICH9_LPCState *lpc;
> +    qemu_irq *pic;
> +    qemu_irq *ioapic;
> +} ICH9_LPCIrqState;
> +
> +typedef struct GMCH_PCIHost {
> +    PCIExpressHost      host;
> +
> +    PCIDevice    *dev;
> +    ICH9_LPCIrqState irq_state;
> +} GMCH_PCIHost;
> +
> +typedef struct GMCH_PCIState {
> +    PCIDevice   d;
> +    /*
> +     * GMCH_PCIHost   *gmch_host;
> +     * In order to get GMCH_PCIHost
> +     *  PCIDevice -> qdev -> parent_bus -> qdev -upcast-> GMCH_PCIHost
> +     */
> +
> +    PAM pam;
> +} GMCH_PCIState;
> +
> +typedef struct ICH9_LPCState {
> +    /* ICH9 LPC PCI to ISA bridge */
> +    PCIDevice d;
> +
> +    /* (pci device, intx) -> pirq
> +     * In real chipset case, the unused slots are never used
> +     * as ICH9 supports only D25-D32 irq routing.
> +     * On the other hand in qemu case, any slot/function can be populated
> +     * via command line option.
> +     * So fallback interrupt routing for any devices in any slots is 
> necessary.
> +     */
> +    uint8_t irr[PCI_SLOT_MAX][PCI_NUM_PINS];
> +
> +    APMState apm;
> +    ICH9_LPCPmRegs pm;
> +    uint32_t sci_level; /* track sci level */
> +
> +    /* 10.1 Chipset Configuration registers(Memory Space)
> +       which is pointed by RCBA */
> +    uint8_t chip_config[ICH9_CC_SIZE];
> +    int rbca_index;
> +} ICH9_LPCState;
> +
> +
> +/****************************************************************************
> + * GMCH PCI host
> + */
> +/* ich9 irq */
> +static int ich9_lpc_map_irq(void *opaque, PCIDevice *pci_dev, int intx);
> +static void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
> +static int ich9_lpc_sci_irq(ICH9_LPCState *lpc);
> +
> +static GMCH_PCIHost *gmch_pcihost_from_qdev(DeviceState *gmch_host_qdev)
> +{
> +    SysBusDevice *sysdev = sysbus_from_qdev(gmch_host_qdev);
> +    PCIHostState *pci = FROM_SYSBUS(PCIHostState, sysdev);
> +    PCIExpressHost *pcie = DO_UPCAST(PCIExpressHost, pci, pci);
> +    return DO_UPCAST(GMCH_PCIHost, host, pcie);
> +}
> +
> +static int gmch_pcihost_initfn(SysBusDevice *dev)
> +{
> +    GMCH_PCIHost *s = gmch_pcihost_from_qdev(&dev->qdev);
> +
> +    pci_host_conf_register_ioport(GMCH_HOST_BRIDGE_CONFIG_ADDR, 
> &s->host.pci);
> +    pci_host_data_register_ioport(GMCH_HOST_BRIDGE_CONFIG_DATA, 
> &s->host.pci);
> +
> +    if (pcie_host_init(&s->host) < 0) {
> +        abort();
> +    }
> +
> +    return 0;
> +}
> +
> +static SysBusDeviceInfo gmch_pcihost_info = {
> +    .init         = gmch_pcihost_initfn,
> +    .qdev.name    = "gmch-pcihost",
> +    .qdev.size    = sizeof(GMCH_PCIHost),
> +    .qdev.no_user = 1,
> +    .qdev.props = (Property[]) {
> +        {
> +            .name = "MCFG",
> +            .info = &qdev_prop_uint64,
> +            .offset = offsetof(GMCH_PCIHost, host.base_addr),
> +            .defval = (uint64_t[]){ GMCH_HOST_BRIDGE_PCIEXBAR_DEFAULT },
> +        },
> +        DEFINE_PROP_END_OF_LIST(),
> +    },
> +};
> +
> +/* host bridge */
> +PCIBus *gmch_host_init(DeviceState **gmch_hostp,
> +                       qemu_irq *pic, qemu_irq *ioapic)
> +{
> +    DeviceState *dev;
> +    GMCH_PCIHost *s;
> +    PCIBus *b;
> +
> +    dev = qdev_create(NULL, "gmch-pcihost");
> +    s = gmch_pcihost_from_qdev(dev);
> +    s->irq_state.pic = pic;
> +    s->irq_state.ioapic = ioapic;
> +
> +    b = pci_bus_new(dev, "pcie.0", 0);
> +    pci_bus_irqs(b, ich9_lpc_set_irq, ich9_lpc_map_irq, &s->irq_state,
> +                 ICH9_LPC_NB_PIRQS);
> +    s->host.pci.bus = b;
> +    qdev_init_nofail(dev);
> +
> +    *gmch_hostp = dev;
> +    return b;
> +}
> +
> +
> +/****************************************************************************
> + * GMCH
> + */
> +static GMCH_PCIState *gmch_from_pci(PCIDevice *gmch_pci)
> +{
> +    return DO_UPCAST(GMCH_PCIState, d, gmch_pci);
> +}
> +
> +/* PCIE MMCFG */
> +static void gmch_update_pciexbar(GMCH_PCIState *gs)
> +{
> +    PCIDevice *pci_dev = &gs->d;
> +    BusState *bus = qdev_get_parent_bus(&pci_dev->qdev);
> +    DeviceState *qdev = bus->parent;
> +    GMCH_PCIHost *s = gmch_pcihost_from_qdev(qdev);
> +
> +    uint64_t pciexbar;
> +    int enable;
> +    uint64_t addr;
> +    uint64_t addr_mask;
> +    uint32_t length;
> +
> +    pciexbar = pci_get_quad(pci_dev->config + GMCH_HOST_BRIDGE_PCIEXBAR);
> +    enable = pciexbar & GMCH_HOST_BRIDGE_PCIEXBAREN;
> +
> +    addr_mask = GMCH_HOST_BRIDGE_PCIEXBAR_ADMSK;
> +    switch (pciexbar & GMCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK) {
> +    case GMCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M:
> +        length = 256 * 1024 * 1024;
> +        break;
> +    case GMCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M:
> +        length = 128 * 1024 * 1024;
> +        addr_mask |= GMCH_HOST_BRIDGE_PCIEXBAR_128ADMSK |
> +            GMCH_HOST_BRIDGE_PCIEXBAR_64ADMSK;
> +        break;
> +    case GMCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M:
> +        length = 64 * 1024 * 1024;
> +        addr_mask |= GMCH_HOST_BRIDGE_PCIEXBAR_64ADMSK;
> +        break;
> +    case GMCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD:
> +    default:
> +        enable = 0;
> +        length = 0;
> +        abort();
> +        break;
> +    }
> +    addr = pciexbar & addr_mask;
> +
> +    pcie_host_mmcfg_update(&s->host, enable, addr, length);
> +}
> +
> +/* PAM */
> +static void gmch_update_pam(GMCH_PCIState *gs)
> +{
> +    int i;
> +    for (i = 0; i <= PAM_IDX_MAX; i++) {
> +        pam_update(&gs->pam, i, gs->d.config[GMCH_HOST_BRIDGE_PAM0 + i]);
> +    }
> +}
> +
> +/* SMRAM */
> +static void gmch_update_smram(GMCH_PCIState *gs)
> +{
> +    smram_update(&gs->pam, gs->d.config[GMCH_HOST_BRDIGE_SMRAM]);
> +}
> +
> +static void gmch_set_smm(int smm, void *arg)
> +{
> +    GMCH_PCIState *gs = arg;
> +    smram_set_smm(&gs->pam, smm, gs->d.config[GMCH_HOST_BRDIGE_SMRAM]);
> +}
> +
> +static void gmch_write_config(PCIDevice *d,
> +                              uint32_t address, uint32_t val, int len)
> +{
> +    GMCH_PCIState *gs = gmch_from_pci(d);
> +
> +    /* XXX: implement SMRAM.D_LOCK */
> +    pci_default_write_config(d, address, val, len);
> +
> +    if (ranges_overlap(address, len, GMCH_HOST_BRIDGE_PAM0,
> +                       GMCH_HOST_BRIDGE_PAM_SIZE)) {
> +        gmch_update_pam(gs);
> +    }
> +
> +    if (ranges_overlap(address, len, GMCH_HOST_BRIDGE_PCIEXBAR,
> +                       GMCH_HOST_BRIDGE_PCIEXBAR_SIZE)) {
> +        gmch_update_pciexbar(gs);
> +    }
> +
> +    if (ranges_overlap(address, len, GMCH_HOST_BRDIGE_SMRAM,
> +                       GMCH_HOST_BRDIGE_SMRAM_SIZE)) {
> +        gmch_update_smram(gs);
> +    }
> +}
> +
> +static void gmch_update(GMCH_PCIState *gs)
> +{
> +    gmch_update_pciexbar(gs);
> +    gmch_update_pam(gs);
> +    gmch_update_smram(gs);
> +}
> +
> +static int gmch_post_load(void *opaque, int version_id)
> +{
> +    GMCH_PCIState *gs = opaque;
> +    gmch_update(gs);
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_gmch = {
> +    .name = "gmch",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .post_load = gmch_post_load,
> +    .fields = (VMStateField []) {
> +        VMSTATE_PCI_DEVICE(d, GMCH_PCIState),
> +        VMSTATE_UINT8(pam.smm_enabled, GMCH_PCIState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void gmch_reset(DeviceState *qdev)
> +{
> +    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
> +    GMCH_PCIState *gs = gmch_from_pci(d);
> +
> +    pci_set_quad(d->config + GMCH_HOST_BRIDGE_PCIEXBAR,
> +                 GMCH_HOST_BRIDGE_PCIEXBAR_DEFAULT);
> +
> +    d->config[GMCH_HOST_BRDIGE_SMRAM] = GMCH_HOST_BRIDGE_SMRAM_DEFAULT;
> +
> +    gmch_update(gs);
> +}
> +
> +static int gmch_initfn(PCIDevice *d)
> +{
> +    GMCH_PCIState *gs = gmch_from_pci(d);
> +
> +    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
> +    pci_config_set_device_id(d->config, PCI_DEVICE_ID_INTEL_Q35_MCH);
> +    pci_config_set_revision(d->config, GMCH_HOST_BRIDGE_REVISION_DEFUALT);
> +    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
> +
> +    cpu_smm_register(&gmch_set_smm, gs);
> +    pam_init_memory_mappings(&gs->pam);
> +
> +    return 0;
> +}
> +
> +static PCIDeviceInfo gmch_info = {
> +    .qdev.name    = "gmch",
> +    .qdev.desc    = "Host bridge",
> +    .qdev.size    = sizeof(GMCH_PCIState),
> +    .qdev.vmsd    = &vmstate_gmch,
> +    .qdev.no_user = 1,
> +    .init         = gmch_initfn,
> +    .config_write = gmch_write_config,
> +    .qdev.reset   = gmch_reset,
> +};
> +
> +/* host bridge */
> +PCIDevice *gmch_init(DeviceState *gmch_host, PCIBus *b)
> +{
> +    GMCH_PCIHost *s = gmch_pcihost_from_qdev(gmch_host);
> +    PCIDevice *d;
> +
> +    d = pci_create_simple_multifunction(b, 0, false, "gmch");
> +    s->dev = d;
> +
> +    return d;
> +}
> +
> +/*****************************************************************************/
> +/* ICH9 DMI-to-PCI bridge */
> +#define I82801ba_SSVID_OFFSET   0x50
> +#define I82801ba_SSVID_SVID     0
> +#define I82801ba_SSVID_SSID     0
> +
> +static PCIBridge *i82801ba11_init(PCIBus *bus, int devfn, const char 
> *bus_name,
> +                                  bool multifunction)
> +{
> +    const PCIP2PBridgeInit init = {
> +        .bus = bus,
> +        .devfn = devfn,
> +        .multifunction = multifunction,
> +
> +        .bus_name = bus_name,
> +        .map_irq = pci_swizzle_map_irq_fn,
> +    };
> +    const PCIP2PBridgeProp prop = {
> +        .vendor_id = PCI_VENDOR_ID_INTEL,
> +        .device_id = PCI_DEVICE_ID_INTEL_82801BA_11,
> +        .revision_id = ICH9_D2P_A2_REVISION,
> +        .prog_interface = PCI_CLASS_BRDIGE_PCI_INF_SUB,
> +
> +        .ssvid_cap = I82801ba_SSVID_OFFSET,
> +        .svid = I82801ba_SSVID_SVID,
> +        .ssid = I82801ba_SSVID_SSID,
> +    };
> +    return pci_p2pbr_create_simple(&init, &prop);
> +}
> +
> +PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus)
> +{
> +    PCIBridge *br;
> +    char buf[16];
> +
> +    snprintf(buf, sizeof(buf), "pci.%d", sec_bus);
> +    br = i82801ba11_init(bus, devfn, buf, true);
> +    if (br == NULL) {
> +        return NULL;
> +    }
> +    return pci_bridge_get_sec_bus(br);
> +}
> +
> +
> +/*****************************************************************************/
> +/* ICH9 LPC PCI to ISA bridge */
> +
> +static void ich9_lpc_reset(DeviceState *qdev);
> +
> +static ICH9_LPCState *ich9_lpc_from_pci(PCIDevice *lpc_pci)
> +{
> +    return DO_UPCAST(ICH9_LPCState, d, lpc_pci);
> +}
> +
> +/* chipset configuration register
> + * to access chipset configuration registers, pci_[sg]et_{byte, word, long}
> + * are used.
> + * Although it's not pci configuration space, it's little endian as Intel.
> + */
> +
> +static void ich9_cc_update_ir(uint8_t irr[PCI_NUM_PINS], uint32_t ir)
> +{
> +    int intx;
> +    for (intx = 0; intx < PCI_NUM_PINS; intx++) {
> +        irr[intx] = (ir >> (intx * ICH9_CC_DIR_SHIFT)) & ICH9_CC_DIR_MASK;
> +    }
> +}
> +
> +static void ich9_cc_update(ICH9_LPCState *lpc)
> +{
> +    int slot;
> +    int reg_offset;
> +    int intx;
> +
> +    /* D{25 - 31}IR, but D30IR is read only to 0. */
> +    for (slot = 25, reg_offset = 0; slot < 32; slot++, reg_offset++) {
> +        if (slot != 30) {
> +            ich9_cc_update_ir(lpc->irr[slot],
> +                              lpc->chip_config[ICH9_CC_D31IR + reg_offset]);
> +        }
> +    }
> +
> +    /*
> +     * D30: DMI2PCI bridge
> +     * It is arbitrarily decided how INTx lines of PCI devicesbehind the 
> bridge
> +     * are connected to pirq lines. Our choice is PIRQ[E-H].
> +     * INT[A-D] are connected to PIRQ[E-H]
> +     */
> +    for (intx = 0; intx < PCI_NUM_PINS; intx++) {
> +        lpc->irr[30][intx] = intx + 4;
> +    }
> +}
> +
> +static void ich9_cc_init(ICH9_LPCState *lpc)
> +{
> +    int slot;
> +    int intx;
> +
> +    /* the default irq routing is arbitrary as long as it matches with
> +     * acpi irq routing table.
> +     * The one that is incompatible with piix_pci(= bochs) one is
> +     * intentionally chosen to let the users know that the different
> +     * board is used.
> +     *
> +     * int[A-D] -> pirq[E-F]
> +     * avoid pirq A-D because they are used for pci express port
> +     */
> +    for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
> +        for (intx = 0; intx < PCI_NUM_PINS; intx++) {
> +            lpc->irr[slot][intx] = (slot + intx) % 4 + 4;
> +        }
> +    }
> +    ich9_cc_update(lpc);
> +}
> +
> +static void ich9_cc_reset(ICH9_LPCState *lpc)
> +{
> +    uint8_t *c = lpc->chip_config;
> +
> +    memset(lpc->chip_config, 0, sizeof(lpc->chip_config));
> +
> +    pci_set_long(c + ICH9_CC_D31IR, ICH9_CC_DIR_DEFAULT);
> +    pci_set_long(c + ICH9_CC_D30IR, ICH9_CC_D30IR_DEFAULT);
> +    pci_set_long(c + ICH9_CC_D29IR, ICH9_CC_DIR_DEFAULT);
> +    pci_set_long(c + ICH9_CC_D28IR, ICH9_CC_DIR_DEFAULT);
> +    pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT);
> +    pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT);
> +    pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT);
> +
> +    ich9_cc_update(lpc);
> +}
> +
> +static void ich9_cc_addr_len(uint32_t *addr, int *len)
> +{
> +    *addr &= ICH9_CC_ADDR_MASK;
> +    if (*addr + *len >= ICH9_CC_SIZE) {
> +        *len = ICH9_CC_SIZE - *addr;
> +    }
> +}
> +
> +/* val: little endian */
> +static void ich9_cc_write(ICH9_LPCState *lpc, uint32_t addr,
> +                          uint32_t val, int len)
> +{
> +    ich9_cc_addr_len(&addr, &len);
> +    memcpy(lpc->chip_config + addr, &val, len);
> +}
> +
> +/* return value: little endian */
> +static uint32_t ich9_cc_read(ICH9_LPCState *lpc, uint32_t addr, int len)
> +{
> +    uint32_t val = 0;
> +    ich9_cc_addr_len(&addr, &len);
> +    memcpy(&val, lpc->chip_config + addr, len);
> +    return val;
> +}
> +
> +#define ICH9_CC_MMIO_WRITE(type, len)                           \
> +    static void ich9_cc_mmio_write ## type                      \
> +    (void *opaque, target_phys_addr_t addr, uint32_t val)       \
> +    {                                                           \
> +        ich9_cc_write(opaque, addr, val, len);                  \
> +    }
> +
> +#define ICH9_CC_MMIO_READ(type, len)            \
> +    static uint32_t ich9_cc_mmio_read ## type   \
> +    (void *opaque, target_phys_addr_t addr)     \
> +    {                                           \
> +        return ich9_cc_read(opaque, addr, len); \
> +    }
> +
> +ICH9_CC_MMIO_WRITE(b, 1)
> +ICH9_CC_MMIO_WRITE(w, 2)
> +ICH9_CC_MMIO_WRITE(l, 4)
> +
> +ICH9_CC_MMIO_READ(b, 1)
> +ICH9_CC_MMIO_READ(w, 2)
> +ICH9_CC_MMIO_READ(l, 4)
> +
> +static CPUWriteMemoryFunc * const ich9_cc_mmio_write[] = {
> +    ich9_cc_mmio_writeb,
> +    ich9_cc_mmio_writew,
> +    ich9_cc_mmio_writel,
> +};
> +
> +static CPUReadMemoryFunc * const ich9_cc_mmio_read[] = {
> +    ich9_cc_mmio_readb,
> +    ich9_cc_mmio_readw,
> +    ich9_cc_mmio_readl,
> +};
> +
> +/* IRQ routing */
> +/* */
> +static void ich9_lpc_rout(uint8_t pirq_rout, int *pic_irq, int *pic_dis)
> +{
> +    *pic_irq = pirq_rout & ICH9_LPC_PIRQ_ROUT_MASK;
> +    *pic_dis = pirq_rout & ICH9_LPC_PIRQ_ROUT_IRQEN;
> +}
> +
> +static void ich9_lpc_pic_irq(ICH9_LPCState *lpc, int irq_num,
> +                             int *pic_irq, int *pic_dis)
> +{
> +    switch (irq_num) {
> +    case 0 ... 3: /* A-D */
> +        ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQA_ROUT + irq_num],
> +                      pic_irq, pic_dis);
> +        return;
> +    case 4 ... 7: /* E-H */
> +        ich9_lpc_rout(lpc->d.config[ICH9_LPC_PIRQE_ROUT + (irq_num - 4)],
> +                      pic_irq, pic_dis);
> +        return;
> +    default:
> +        break;
> +    }
> +    abort();
> +}
> +
> +/* pic_irq: i8254 irq 0-15 */
> +static void ich9_lpc_update_pic(ICH9_LPCIrqState *irq_state, int pic_irq)
> +{
> +    GMCH_PCIHost *s = container_of(irq_state, GMCH_PCIHost, irq_state);
> +    ICH9_LPCState *lpc = irq_state->lpc;
> +    int i, pic_level;
> +
> +    /* The pic level is the logical OR of all the PCI irqs mapped to it */
> +    pic_level = 0;
> +    for (i = 0; i < ICH9_LPC_NB_PIRQS; i++) {
> +        int tmp_irq;
> +        int tmp_dis;
> +        ich9_lpc_pic_irq(lpc, i, &tmp_irq, &tmp_dis);
> +        if (!tmp_dis && pic_irq == tmp_irq) {
> +            pic_level |= pci_bus_get_irq_level(s->host.pci.bus, i);
> +        }
> +    }
> +    if (pic_irq == ich9_lpc_sci_irq(lpc)) {
> +        pic_level |= lpc->sci_level;
> +    }
> +
> +    qemu_set_irq(irq_state->pic[pic_irq], pic_level);
> +}
> +
> +/* pirq: pirq[A-H] 0-7*/
> +static void ich9_lpc_update_by_pirq(ICH9_LPCIrqState *irq_state, int pirq)
> +{
> +    ICH9_LPCState *lpc = irq_state->lpc;
> +    int pic_irq;
> +    int pic_dis;
> +
> +    ich9_lpc_pic_irq(lpc, pirq, &pic_irq, &pic_dis);
> +    assert(pic_irq < ICH9_LPC_PIC_NUM_PINS);
> +    if (pic_dis) {
> +        return;
> +    }
> +
> +    ich9_lpc_update_pic(irq_state, pic_irq);
> +}
> +
> +/* APIC mode: GSIx: PIRQ[A-H] -> GSI 16, ... no pirq shares same APIC pins. 
> */
> +static int ich9_pirq_to_gsi(int pirq)
> +{
> +    return pirq + ICH9_LPC_PIC_NUM_PINS;
> +}
> +
> +static int ich9_gsi_to_pirq(int gsi)
> +{
> +    return gsi - ICH9_LPC_PIC_NUM_PINS;
> +}
> +
> +static void ich9_lpc_update_apic(ICH9_LPCIrqState *irq_state, int gsi)
> +{
> +    GMCH_PCIHost *s = container_of(irq_state, GMCH_PCIHost, irq_state);
> +    ICH9_LPCState *lpc = irq_state->lpc;
> +    int level;
> +
> +    level = pci_bus_get_irq_level(s->host.pci.bus, ich9_gsi_to_pirq(gsi));
> +    if (gsi == ich9_lpc_sci_irq(lpc)) {
> +        level |= lpc->sci_level;
> +    }
> +
> +    qemu_set_irq(irq_state->ioapic[gsi], level);
> +}
> +
> +/* return the pirq number (PIRQ[A-H]:0-7) corresponding to
> +   a given device irq pin. */
> +static int ich9_lpc_map_irq(void *opaque, PCIDevice *pci_dev, int intx)
> +{
> +    ICH9_LPCIrqState *irq_state = opaque;
> +    return irq_state->lpc->irr[PCI_SLOT(pci_dev->devfn)][intx];
> +}
> +
> +static void ich9_lpc_set_irq(void *opaque, int pirq, int level)
> +{
> +    ICH9_LPCIrqState *irq_state = opaque;
> +
> +    assert(0 <= pirq);
> +    assert(pirq < ICH9_LPC_NB_PIRQS);
> +
> +    ich9_lpc_update_apic(irq_state, ich9_pirq_to_gsi(pirq));
> +    ich9_lpc_update_by_pirq(irq_state, pirq);
> +}
> +
> +static int ich9_lpc_sci_irq(ICH9_LPCState *lpc)
> +{
> +    switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
> +            ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK) {
> +    case ICH9_LPC_ACPI_CTRL_9:
> +        return 9;
> +    case ICH9_LPC_ACPI_CTRL_10:
> +        return 10;
> +    case ICH9_LPC_ACPI_CTRL_11:
> +        return 11;
> +    case ICH9_LPC_ACPI_CTRL_20:
> +        return 20;
> +    case ICH9_LPC_ACPI_CTRL_21:
> +        return 21;
> +    default:
> +        /* reserved */
> +        break;
> +    }
> +    return -1;
> +}
> +
> +static void ich9_set_sci(void *opaque, int irq_num, int level)
> +{
> +    ICH9_LPCIrqState *irq_state = opaque;
> +    ICH9_LPCState *lpc = irq_state->lpc;
> +    int irq;
> +
> +    assert(irq_num == 0);
> +    level = !!level;
> +    if (level == lpc->sci_level) {
> +        return;
> +    }
> +    lpc->sci_level = level;
> +
> +    irq = ich9_lpc_sci_irq(lpc);
> +    if (irq < 0) {
> +        return;
> +    }
> +
> +    ich9_lpc_update_apic(irq_state, irq);
> +    if (irq < ICH9_LPC_PIC_NUM_PINS) {
> +        ich9_lpc_update_pic(irq_state, irq);
> +    }
> +}
> +
> +void ich9_lpc_pm_init(DeviceState *gmch_host, PCIDevice *lpc_pci,
> +                      qemu_irq cmos_s3)
> +{
> +    GMCH_PCIHost *s = gmch_pcihost_from_qdev(gmch_host);
> +    ICH9_LPCState *lpc = ich9_lpc_from_pci(lpc_pci);
> +    qemu_irq *sci_irq;
> +
> +    sci_irq = qemu_allocate_irqs(ich9_set_sci, &s->irq_state, 1);
> +    ich9_pm_init(&lpc->pm, sci_irq[0], cmos_s3);
> +
> +    ich9_lpc_reset(&lpc->d.qdev);
> +}
> +
> +/* APM */
> +static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
> +{
> +    ICH9_LPCState *lpc = arg;
> +
> +    /* ACPI specs 3.0, 4.7.2.5 */
> +    acpi_pm1_cnt_update(&lpc->pm.pm1_cnt,
> +                        val == ICH9_APM_ACPI_ENABLE,
> +                        val == ICH9_APM_ACPI_DISABLE);
> +
> +    /* SMI_EN = PMBASE + 30. SMI control and enable register */
> +    if (lpc->pm.smi_en & ICH9_PMIO_SMI_EN_APMC_EN) {
> +        cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
> +    }
> +}
> +
> +/* config:PMBASE */
> +static void
> +ich9_lpc_pmbase_update(ICH9_LPCState *lpc)
> +{
> +    uint32_t pm_io_base = pci_get_long(lpc->d.config + ICH9_LPC_PMBASE);
> +    pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK;
> +
> +    ich9_pm_iospace_update(&lpc->pm, pm_io_base);
> +}
> +
> +/* config:RBCA */
> +static void ich9_lpc_rcba_update(ICH9_LPCState *lpc, uint32_t rbca_old)
> +{
> +    uint32_t rbca = pci_get_long(lpc->d.config + ICH9_LPC_RCBA);
> +
> +    if (rbca_old & ICH9_LPC_RCBA_EN) {
> +        cpu_register_physical_memory(rbca_old & ICH9_LPC_RCBA_BA_MASK,
> +                                     ICH9_CC_SIZE, IO_MEM_UNASSIGNED);
> +    }
> +    if (rbca & ICH9_LPC_RCBA_EN) {
> +        cpu_register_physical_memory(rbca & ICH9_LPC_RCBA_BA_MASK,
> +                                     ICH9_CC_SIZE, lpc->rbca_index);
> +    }
> +}
> +
> +static int ich9_lpc_post_load(void *opaque, int version_id)
> +{
> +    ICH9_LPCState *lpc = opaque;
> +
> +    ich9_lpc_pmbase_update(lpc);
> +    ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RBCA_EN */);
> +    return 0;
> +}
> +
> +static void ich9_lpc_config_write(PCIDevice *d,
> +                                  uint32_t addr, uint32_t val, int len)
> +{
> +    ICH9_LPCState *lpc = ich9_lpc_from_pci(d);
> +    uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA);
> +
> +    pci_default_write_config(d, addr, val, len);
> +    if (ranges_overlap(addr, len, ICH9_LPC_PMBASE, 4)) {
> +        ich9_lpc_pmbase_update(lpc);
> +    }
> +    if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) {
> +        ich9_lpc_rcba_update(lpc, rbca_old);
> +    }
> +}
> +
> +static void ich9_lpc_reset(DeviceState *qdev)
> +{
> +    PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
> +    ICH9_LPCState *lpc = ich9_lpc_from_pci(d);
> +    uint32_t rbca_old = pci_get_long(d->config + ICH9_LPC_RCBA);
> +    int i;
> +
> +    for (i = 0; i < 4; i++) {
> +        pci_set_byte(d->config + ICH9_LPC_PIRQA_ROUT + i,
> +                     ICH9_LPC_PIRQ_ROUT_DEFAULT);
> +    }
> +    for (i = 0; i < 4; i++) {
> +        pci_set_byte(d->config + ICH9_LPC_PIRQE_ROUT + i,
> +                     ICH9_LPC_PIRQ_ROUT_DEFAULT);
> +    }
> +    pci_set_byte(d->config + ICH9_LPC_ACPI_CTRL, ICH9_LPC_ACPI_CTRL_DEFAULT);
> +
> +    pci_set_long(d->config + ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_DEFAULT);
> +    pci_set_long(d->config + ICH9_LPC_RCBA, ICH9_LPC_RCBA_DEFAULT);
> +
> +    ich9_cc_reset(lpc);
> +
> +    ich9_lpc_pmbase_update(lpc);
> +    ich9_lpc_rcba_update(lpc, rbca_old);
> +
> +    lpc->sci_level = 0;
> +}
> +
> +static int ich9_lpc_initfn(PCIDevice *d)
> +{
> +    ICH9_LPCState *lpc = ich9_lpc_from_pci(d);
> +
> +    isa_bus_new(&d->qdev);
> +    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
> +    pci_config_set_device_id(d->config, PCI_DEVICE_ID_INTEL_ICH9_8); /* ICH9 
> LPC */
> +    pci_config_set_revision(d->config, ICH9_A2_LPC_REVISION);
> +    pci_config_set_class(d->config, PCI_CLASS_BRIDGE_ISA);
> +
> +    pci_set_long(d->wmask + ICH9_LPC_PMBASE,
> +                 ICH9_LPC_PMBASE_BASE_ADDRESS_MASK);
> +
> +    lpc->rbca_index = cpu_register_io_memory(ich9_cc_mmio_read,
> +                                             ich9_cc_mmio_write,
> +                                             lpc, DEVICE_LITTLE_ENDIAN);
> +
> +    ich9_cc_init(lpc);
> +    apm_init(&lpc->apm, ich9_apm_ctrl_changed, lpc);
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_ich9_lpc = {
> +    .name = "ICH9LPC",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .post_load = ich9_lpc_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PCI_DEVICE(d, ICH9_LPCState),
> +        VMSTATE_STRUCT(apm, ICH9_LPCState, 0, vmstate_apm, APMState),
> +        VMSTATE_STRUCT(pm, ICH9_LPCState, 0, vmstate_ich9_pm, 
> ICH9_LPCPmRegs),
> +        VMSTATE_UINT8_ARRAY(chip_config, ICH9_LPCState, ICH9_CC_SIZE),
> +        VMSTATE_UINT32(sci_level, ICH9_LPCState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +PCIDevice *gmch_lpc_init(DeviceState *gmch_host, PCIBus *bus)
> +{
> +    GMCH_PCIHost *s = gmch_pcihost_from_qdev(gmch_host);
> +    PCIDevice *d;
> +    ICH9_LPCState *lpc;
> +
> +    d = pci_create_simple_multifunction(bus, PCI_DEVFN(ICH9_LPC_DEV,
> +                                                       ICH9_LPC_FUNC),
> +                                        true, "ICH9 LPC");
> +    lpc = ich9_lpc_from_pci(d);
> +    s->irq_state.lpc = lpc;
> +    return &lpc->d;
> +}
> +
> +static PCIDeviceInfo ich9_lpc_info = {
> +    .qdev.name    = "ICH9 LPC",
> +    .qdev.desc    = "ICH9 LPC bridge",
> +    .qdev.size    = sizeof(ICH9_LPCState),
> +    .qdev.vmsd    = &vmstate_ich9_lpc,
> +    .qdev.no_user = 1,
> +    .init         = ich9_lpc_initfn,
> +    .config_write = ich9_lpc_config_write,
> +    .qdev.reset   = ich9_lpc_reset,
> +};
> +
> +static void q35_register(void)
> +{
> +    sysbus_register_withprop(&gmch_pcihost_info);
> +    pci_qdev_register(&gmch_info);
> +    pci_qdev_register(&ich9_lpc_info);
> +}
> +device_init(q35_register);
> diff --git a/hw/q35.h b/hw/q35.h
> new file mode 100644
> index 0000000..be2e96b
> --- /dev/null
> +++ b/hw/q35.h
> @@ -0,0 +1,272 @@
> +/*
> + * q35.h
> + *
> + * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> + *                    VA Linux Systems Japan K.K.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see 
> <http://www.gnu.org/licenses/>
> + */
> +
> +#ifndef HW_Q35_H
> +#define HW_Q35_H
> +
> +#include "sysbus.h"
> +#include "acpi_ich9.h"
> +
> +PCIBus *gmch_host_init(DeviceState **gmch_hostp,
> +                       qemu_irq *pic, qemu_irq *ioapic);
> +
> +PCIDevice *gmch_init(DeviceState *gmch_host, PCIBus *b);
> +PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus);
> +PCIDevice *gmch_lpc_init(DeviceState *gmch_host, PCIBus *bus);
> +void ich9_lpc_pm_init(DeviceState *gmch_host, PCIDevice *pci_lpc,
> +                      qemu_irq cmos_s3);
> +
> +i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
> +
> +#define Q35_MASK(bit, ms_bit, ls_bit) \
> +((uint##bit##_t)(((1ULL << ((ms_bit) + 1)) - 1) & ~((1ULL << ls_bit) - 1)))
> +
> +/*
> + * gmch part
> + */
> +
> +/* PCI configuration */
> +#define GMCH_HOST_BRIDGE                        "GMCH"
> +
> +#define GMCH_HOST_BRIDGE_CONFIG_ADDR            0xcf8
> +#define GMCH_HOST_BRIDGE_CONFIG_DATA            0xcfc
> +
> +/* D0:F0 configuration space */
> +#define  GMCH_HOST_BRIDGE_REVISION_DEFUALT      0x0
> +
> +#define GMCH_HOST_BRIDGE_PCIEXBAR               0x60    /* 64bit register */
> +#define  GMCH_HOST_BRIDGE_PCIEXBAR_SIZE         8       /* 64bit register */
> +#define  GMCH_HOST_BRIDGE_PCIEXBAR_DEFAULT      0xe0000000
> +#define  GMCH_HOST_BRIDGE_PCIEXBAR_ADMSK        Q35_MASK(64, 35, 25) /* bit 
> 35:28 */
> +#define  GMCH_HOST_BRIDGE_PCIEXBAR_128ADMSK     ((uint64_t)(1 << 26))
> +#define  GMCH_HOST_BRIDGE_PCIEXBAR_64ADMSK      ((uint64_t)(1 << 25))
> +#define  GMCH_HOST_BRIDGE_PCIEXBAR_LENGTH_MASK  ((uint64_t)(0x3 << 1))
> +#define  GMCH_HOST_BRIDGE_PCIEXBAR_LENGTH_256M  ((uint64_t)(0x0 << 1))
> +#define  GMCH_HOST_BRIDGE_PCIEXBAR_LENGTH_128M  ((uint64_t)(0x1 << 1))
> +#define  GMCH_HOST_BRIDGE_PCIEXBAR_LENGTH_64M   ((uint64_t)(0x2 << 1))
> +#define  GMCH_HOST_BRIDGE_PCIEXBAR_LENGTH_RVD   ((uint64_t)(0x3 << 1))
> +#define  GMCH_HOST_BRIDGE_PCIEXBAREN            ((uint64_t)1)
> +
> +#define GMCH_HOST_BRIDGE_PAM_NB                 7
> +#define GMCH_HOST_BRIDGE_PAM_SIZE               7
> +#define GMCH_HOST_BRIDGE_PAM0                   0x90
> +#define  GMCH_HOST_BRIDGE_PAM_BIOS_AREA         0xf0000
> +#define  GMCH_HOST_BRIDGE_PAM_AREA_SIZE         0x10000 /* 16KB */
> +#define GMCH_HOST_BRIDGE_PAM1                   0x91
> +#define  GMCH_HOST_BRIDGE_PAM_EXPAN_AREA        0xc0000
> +#define  GMCH_HOST_BRIDGE_PAM_EXPAN_SIZE        0x04000
> +#define GMCH_HOST_BRIDGE_PAM2                   0x92
> +#define GMCH_HOST_BRIDGE_PAM3                   0x93
> +#define GMCH_HOST_BRIDGE_PAM4                   0x94
> +#define  GMCH_HOST_BRIDGE_PAM_EXBIOS_AREA       0xe0000
> +#define  GMCH_HOST_BRIDGE_PAM_EXBIOS_SIZE       0x04000
> +#define GMCH_HOST_BRIDGE_PAM5                   0x95
> +#define GMCH_HOST_BRIDGE_PAM6                   0x96
> +#define  GMCH_HOST_BRIDGE_PAM_WE_HI             ((uint8_t)(0x2 << 4))
> +#define  GMCH_HOST_BRIDGE_PAM_RE_HI             ((uint8_t)(0x1 << 4))
> +#define  GMCH_HOST_BRIDGE_PAM_HI_MASK           ((uint8_t)(0x3 << 4))
> +#define  GMCH_HOST_BRIDGE_PAM_WE_LO             ((uint8_t)0x2)
> +#define  GMCH_HOST_BRIDGE_PAM_RE_LO             ((uint8_t)0x1)
> +#define  GMCH_HOST_BRIDGE_PAM_LO_MASK           ((uint8_t)0x3)
> +#define  GMCH_HOST_BRIDGE_PAM_WE                ((uint8_t)0x2)
> +#define  GMCH_HOST_BRIDGE_PAM_RE                ((uint8_t)0x1)
> +#define  GMCH_HOST_BRIDGE_PAM_MASK              ((uint8_t)0x3)
> +
> +#define GMCH_HOST_BRDIGE_SMRAM                  0x9d
> +#define GMCH_HOST_BRDIGE_SMRAM_SIZE             1
> +#define  GMCH_HOST_BRIDGE_SMRAM_DEFAULT         ((uint8_t)0x2)
> +#define  GMCH_HOST_BRIDGE_SMRAM_D_OPEN          ((uint8_t)(1 << 6))
> +#define  GMCH_HOST_BRIDGE_SMRAM_D_CLS           ((uint8_t)(1 << 5))
> +#define  GMCH_HOST_BRIDGE_SMRAM_D_LCK           ((uint8_t)(1 << 4))
> +#define  GMCH_HOST_BRIDGE_SMRAM_G_SMRAME        ((uint8_t)(1 << 3))
> +#define  GMCH_HOST_BRIDGE_SMRAM_C_BASE_SEG_MASK ((uint8_t)0x7)
> +#define  GMCH_HOST_BRIDGE_SMRAM_C_BASE_SEG      ((uint8_t)0x2)  /* hardwired 
> to b010 */
> +#define   GMCH_HOST_BRIDGE_SMRAM_C_BASE         0xa0000
> +#define   GMCH_HOST_BRIDGE_SMRAM_C_END          0xc0000
> +#define   GMCH_HOST_BRIDGE_SMRAM_C_SIZE         0x20000
> +#define GMCH_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END  0x100000
> +
> +#define GMCH_HOST_BRIDGE_ESMRAMC                0x9e
> +#define  GMCH_HOST_BRDIGE_ESMRAMC_H_SMRAME      ((uint8_t)(1 << 6))
> +#define  GMCH_HOST_BRDIGE_ESMRAMC_E_SMERR       ((uint8_t)(1 << 5))
> +#define  GMCH_HOST_BRDIGE_ESMRAMC_SM_CACHE      ((uint8_t)(1 << 4))
> +#define  GMCH_HOST_BRDIGE_ESMRAMC_SM_L1         ((uint8_t)(1 << 3))
> +#define  GMCH_HOST_BRDIGE_ESMRAMC_SM_L2         ((uint8_t)(1 << 2))
> +#define  GMCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_MASK  ((uint8_t)(0x3 << 1))
> +#define   GMCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_1MB  ((uint8_t)(0x0 << 1))
> +#define   GMCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_2MB  ((uint8_t)(0x1 << 1))
> +#define   GMCH_HOST_BRDIGE_ESMRAMC_TSEG_SZ_8MB  ((uint8_t)(0x2 << 1))
> +#define  GMCH_HOST_BRDIGE_ESMRAMC_T_EN          ((uint8_t)1)
> +
> +/* D1:F0 PCIE* port*/
> +#define GMCH_PCIE_DEV                           1
> +#define GMCH_PCIE_FUNC                          0
> +
> +/*
> + * ich9 part
> + */
> +
> +/* ICH9: Chipset Configuration Registers */
> +#define ICH9_CC_SIZE                            (16 * 1024)     /* 16KB */
> +#define ICH9_CC_ADDR_MASK                       (ICH9_CC_SIZE - 1)
> +
> +#define ICH9_CC
> +#define ICH9_CC_D28IP                           0x310C
> +#define  ICH9_CC_D28IP_SHIFT                    4
> +#define  ICH9_CC_D28IP_MASK                     0xf
> +#define  ICH9_CC_D28IP_DEFAULT                  0x00214321
> +#define ICH9_CC_D31IR                           0x3140
> +#define ICH9_CC_D30IR                           0x3142
> +#define ICH9_CC_D29IR                           0x3144
> +#define ICH9_CC_D28IR                           0x3146
> +#define ICH9_CC_D27IR                           0x3148
> +#define ICH9_CC_D26IR                           0x314C
> +#define ICH9_CC_D25IR                           0x3150
> +#define  ICH9_CC_DIR_DEFAULT                    0x3210
> +#define  ICH9_CC_D30IR_DEFAULT                  0x0
> +#define  ICH9_CC_DIR_SHIFT                      4
> +#define  ICH9_CC_DIR_MASK                       0x7
> +#define ICH9_CC_OIC                             0x31FF
> +#define  ICH9_CC_OIC_AEN                        0x1
> +
> +/* D28:F[0-5] */
> +#define ICH9_PCIE_DEV                           28
> +#define ICH9_PCIE_FUNC_MAX                      6
> +
> +
> +/* D29:F0 USB UHCI Controller #1 */
> +#define ICH9_USB_UHCI1_DEV                      29
> +#define ICH9_USB_UHCI1_FUNC                     0
> +
> +/* D30:F0 DMI-to-PCI brdige */
> +#define ICH9_D2P_BRIDGE                         "ICH9 D2P BRIDGE"
> +#define ICH9_D2P_BRIDGE_SAVEVM_VERSION          0
> +
> +#define ICH9_D2P_BRIDGE_DEV                     30
> +#define ICH9_D2P_BRIDGE_FUNC                    0
> +
> +#define ICH9_D2P_SECONDARY_DEFAULT              (256 - 8)
> +
> +#define ICH9_D2P_A2_REVISION                    0x92
> +
> +
> +/* D31:F1 LPC controller */
> +#define ICH9_A2_LPC                             "ICH9 A2 LPC"
> +#define ICH9_A2_LPC_SAVEVM_VERSION              0
> +
> +#define ICH9_LPC_DEV                            31
> +#define ICH9_LPC_FUNC                           0
> +
> +#define ICH9_A2_LPC_REVISION                    0x2
> +#define ICH9_LPC_NB_PIRQS                       8       /* PCI A-H */
> +
> +#define ICH9_LPC_PMBASE                         0x40
> +#define  ICH9_LPC_PMBASE_BASE_ADDRESS_MASK      Q35_MASK(32, 15, 7)
> +#define  ICH9_LPC_PMBASE_RTE                    0x1
> +#define  ICH9_LPC_PMBASE_DEFAULT                0x1
> +#define ICH9_LPC_ACPI_CTRL                      0x44
> +#define  ICH9_LPC_ACPI_CTRL_ACPI_EN             0x80
> +#define  ICH9_LPC_ACPI_CTRL_SCI_IRQ_SEL_MASK    Q35_MASK(8, 2, 0)
> +#define  ICH9_LPC_ACPI_CTRL_9                   0x0
> +#define  ICH9_LPC_ACPI_CTRL_10                  0x1
> +#define  ICH9_LPC_ACPI_CTRL_11                  0x2
> +#define  ICH9_LPC_ACPI_CTRL_20                  0x4
> +#define  ICH9_LPC_ACPI_CTRL_21                  0x5
> +#define  ICH9_LPC_ACPI_CTRL_DEFAULT             0x0
> +
> +#define ICH9_LPC_PIRQA_ROUT                     0x60
> +#define ICH9_LPC_PIRQB_ROUT                     0x61
> +#define ICH9_LPC_PIRQC_ROUT                     0x62
> +#define ICH9_LPC_PIRQD_ROUT                     0x63
> +
> +#define ICH9_LPC_PIRQE_ROUT                     0x68
> +#define ICH9_LPC_PIRQF_ROUT                     0x69
> +#define ICH9_LPC_PIRQG_ROUT                     0x6a
> +#define ICH9_LPC_PIRQH_ROUT                     0x6b
> +
> +#define  ICH9_LPC_PIRQ_ROUT_IRQEN               0x80
> +#define  ICH9_LPC_PIRQ_ROUT_MASK                Q35_MASK(8, 3, 0)
> +#define  ICH9_LPC_PIRQ_ROUT_DEFAULT             0x80
> +
> +#define ICH9_LPC_RCBA                           0xf0
> +#define  ICH9_LPC_RCBA_BA_MASK                  Q35_MASK(32, 31, 14)
> +#define  ICH9_LPC_RCBA_EN                       0x1
> +#define  ICH9_LPC_RCBA_DEFAULT                  0x0
> +
> +#define ICH9_LPC_PIC_NUM_PINS                   16
> +#define ICH9_LPC_IOAPIC_NUM_PINS                24
> +
> +/* D31:F2 SATA Controller #1 */
> +#define ICH9_SATA1_DEV                          31
> +#define ICH9_SATA1_FUNC                         2
> +
> +/* D30:F1 power management I/O registers
> +   offset from the address ICH9_LPC_PMBASE */
> +
> +/* ICH9 LPC PM I/O registers are 128 ports and 128-aligned */
> +#define ICH9_PMIO_SIZE                          128
> +#define ICH9_PMIO_MASK                          (ICH9_PMIO_SIZE - 1)
> +
> +#define ICH9_PMIO_PM1_STS                       0x00
> +#define ICH9_PMIO_PM1_EN                        0x02
> +#define ICH9_PMIO_PM1_CNT                       0x04
> +#define ICH9_PMIO_PM1_TMR                       0x08
> +#define ICH9_PMIO_GPE0_STS                      0x20
> +#define ICH9_PMIO_GPE0_EN                       0x28
> +#define  ICH9_PMIO_GPE0_LEN                     16
> +#define ICH9_PMIO_SMI_EN                        0x30
> +#define  ICH9_PMIO_SMI_EN_APMC_EN               (1 << 5)
> +#define ICH9_PMIO_SMI_STS                       0x34
> +
> +/* FADT ACPI_ENABLE/ACPI_DISABLE */
> +#define ICH9_APM_ACPI_ENABLE                    0x2
> +#define ICH9_APM_ACPI_DISABLE                   0x3
> +
> +
> +/* D31:F3 SMBus controller */
> +#define ICH9_A2_SMB_REVISION                    0x02
> +#define ICH9_SMB_PI                             0x00
> +
> +#define ICH9_SMB_SMBMBAR0                       0x10
> +#define ICH9_SMB_SMBMBAR1                       0x14
> +#define  ICH9_SMB_SMBM_BAR                      0
> +#define  ICH9_SMB_SMBM_SIZE                     (1 << 8)
> +#define ICH9_SMB_SMB_BASE                       0x20
> +#define  ICH9_SMB_SMB_BASE_BAR                  4
> +#define  ICH9_SMB_SMB_BASE_SIZE                 (1 << 5)
> +#define ICH9_SMB_HOSTC                          0x40
> +#define  ICH9_SMB_HOSTC_SSRESET                 ((uint8_t)(1 << 3))
> +#define  ICH9_SMB_HOSTC_I2C_EN                  ((uint8_t)(1 << 2))
> +#define  ICH9_SMB_HOSTC_SMB_SMI_EN              ((uint8_t)(1 << 1))
> +#define  ICH9_SMB_HOSTC_HST_EN                  ((uint8_t)(1 << 0))
> +
> +/* D31:F3 SMBus I/O and memory mapped I/O registers */
> +#define ICH9_SMB_DEV                            31
> +#define ICH9_SMB_FUNC                           3
> +
> +#define ICH9_SMB_HST_STS                        0x00
> +#define ICH9_SMB_HST_CNT                        0x02
> +#define ICH9_SMB_HST_CMD                        0x03
> +#define ICH9_SMB_XMIT_SLVA                      0x04
> +#define ICH9_SMB_HST_D0                         0x05
> +#define ICH9_SMB_HST_D1                         0x06
> +#define ICH9_SMB_HOST_BLOCK_DB                  0x07
> +
> +#endif /* HW_Q35_H */
> diff --git a/hw/q35_smbus.c b/hw/q35_smbus.c
> new file mode 100644
> index 0000000..fe445ac
> --- /dev/null
> +++ b/hw/q35_smbus.c
> @@ -0,0 +1,154 @@
> +/*
> + * ACPI implementation
> + *
> + * Copyright (c) 2006 Fabrice Bellard
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License version 2 as published by the Free Software Foundation.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see 
> <http://www.gnu.org/licenses/>
> + */
> +/*
> + *  Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
> + *                     VA Linux Systems Japan K.K.
> + *
> + *  This is based on acpi.c, but heavily rewritten.
> + */
> +#include "hw.h"
> +#include "pc.h"
> +#include "pm_smbus.h"
> +#include "pci.h"
> +#include "sysemu.h"
> +#include "i2c.h"
> +#include "smbus.h"
> +
> +#include "q35.h"
> +
> +typedef struct ICH9_SMBState {
> +    PCIDevice dev;
> +
> +    PMSMBus smb;
> +} ICH9_SMBState;
> +
> +static ICH9_SMBState *ich9_pci_to_smb(PCIDevice* pci_dev)
> +{
> +    return DO_UPCAST(ICH9_SMBState, dev, pci_dev);
> +}
> +
> +static const VMStateDescription vmstate_ich9_smbus = {
> +    .name = "ich9_smb",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .minimum_version_id_old = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PCI_DEVICE(dev, struct ICH9_SMBState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void ich9_smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
> +{
> +    ICH9_SMBState *s = opaque;
> +    uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
> +
> +    if ((hostc & ICH9_SMB_HOSTC_HST_EN) && !(hostc & ICH9_SMB_HOSTC_I2C_EN)) 
> {
> +        uint64_t offset = addr - 
> s->dev.io_regions[ICH9_SMB_SMB_BASE_BAR].addr;
> +        smb_ioport_writeb(&s->smb, offset, val);
> +    }
> +}
> +
> +static uint32_t ich9_smb_ioport_readb(void *opaque, uint32_t addr)
> +{
> +    ICH9_SMBState *s = opaque;
> +    uint8_t hostc = s->dev.config[ICH9_SMB_HOSTC];
> +
> +    if ((hostc & ICH9_SMB_HOSTC_HST_EN) && !(hostc & ICH9_SMB_HOSTC_I2C_EN)) 
> {
> +        uint64_t offset = addr - 
> s->dev.io_regions[ICH9_SMB_SMB_BASE_BAR].addr;
> +        return smb_ioport_readb(&s->smb, offset);
> +    }
> +
> +    return 0xff;
> +}
> +
> +static void ich9_smb_map_ioport(PCIDevice *dev, int region_num,
> +                                uint64_t addr, uint64_t size, int type)
> +{
> +    ICH9_SMBState *s = ich9_pci_to_smb(dev);
> +
> +    assert(size == ICH9_SMB_SMB_BASE_SIZE);
> +    assert(type == PCI_BASE_ADDRESS_SPACE_IO);
> +
> +    register_ioport_write(addr, 64, 1, ich9_smb_ioport_writeb, s);
> +    register_ioport_read(addr, 64, 1, ich9_smb_ioport_readb, s);
> +}
> +
> +static int ich9_smb_initfn(PCIDevice *d)
> +{
> +    ICH9_SMBState *s = ich9_pci_to_smb(d);
> +
> +    pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
> +    pci_config_set_device_id(d->config, PCI_DEVICE_ID_INTEL_ICH9_6);
> +
> +    pci_set_word(d->wmask + PCI_STATUS,
> +                 PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
> +
> +    pci_config_set_revision(d->config, ICH9_A2_SMB_REVISION);
> +    pci_config_set_prog_interface(d->config, ICH9_SMB_PI);
> +    pci_config_set_class(d->config, PCI_CLASS_SERIAL_SMBUS);
> +
> +    /* TODO? D31IP.SMIP in chipset configuration space */
> +    pci_config_set_interrupt_pin(d->config, 0x01); /* interrupt pin 1 */
> +
> +    pci_set_byte(d->config + ICH9_SMB_HOSTC, 0);
> +
> +    /*
> +     * update parameters based on
> +     * paralell_hds[0]
> +     * serial_hds[0]
> +     * serial_hds[0]
> +     * fdc
> +     *
> +     * Is there any OS that depends on them?
> +     */
> +
> +    /* TODO smb_io_base */
> +    pci_set_byte(d->config + ICH9_SMB_HOSTC, 0);
> +    /* TODO bar0, bar1: 64bit BAR support*/
> +    pci_register_bar(d, ICH9_SMB_SMB_BASE_BAR,
> +                     ICH9_SMB_SMB_BASE_SIZE, PCI_BASE_ADDRESS_SPACE_IO,
> +                     &ich9_smb_map_ioport);
> +
> +    pm_smbus_init(&d->qdev, &s->smb);
> +    return 0;
> +}
> +
> +i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
> +{
> +    PCIDevice *d =
> +        pci_create_simple_multifunction(bus, devfn, true, "ICH9 SMB");
> +    ICH9_SMBState *s = ich9_pci_to_smb(d);
> +    return s->smb.smbus;
> +}
> +
> +static PCIDeviceInfo ich9_smb_info = {
> +    .qdev.name = "ICH9 SMB",
> +    .qdev.desc = "ICH9 SMBUS Bridge",
> +    .qdev.size = sizeof(ICH9_SMBState),
> +    .qdev.vmsd = &vmstate_ich9_smbus,
> +    .qdev.no_user = 1,
> +    .init = ich9_smb_initfn,
> +};
> +
> +static void ich9_smb_register(void)
> +{
> +    pci_qdev_register(&ich9_smb_info);
> +}
> +
> +device_init(ich9_smb_register);
> -- 
> 1.7.1



reply via email to

[Prev in Thread] Current Thread [Next in Thread]