qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH 11/25] q35: Introduce q35 pc based chipset emula


From: Michael S. Tsirkin
Subject: Re: [Qemu-devel] [PATCH 11/25] q35: Introduce q35 pc based chipset emulator
Date: Sat, 15 Sep 2012 21:14:12 +0300

On Thu, Sep 13, 2012 at 04:12:42PM -0400, Jason Baron wrote:
> 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);

I wonder if it's possible for q35 to have no devices
at all in the default machine and have it
fully qualified by -device switches?

I envision -M qemu-1.3 switch that does exactly that,
so that machine type only handles things like
cross version compatibility.

-- 
MST



reply via email to

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