The i440FX northbridge is only used by the PC machine, while the
PIIX southbridge is also used by the Malta MIPS machine. Split the PIIX3 southbridge from i440FX northbridge. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEicHnj2Ae6GyGdJXLoqP9bt6twN4FAl3B/CwACgkQoqP9bt6t wN5frA/9FNpyolvQu5bEUAPsNv8wpWH/+XAxoHhdhAVZYPTMot6Iv2liwAav9GsU 9M4JK8qjcwvbN0yqkt6ZUjzhIZoXGnNVOEXVz/gUuk2EDr7EwXymsTwWDErIt0Ap 0IUEDfaISntxgf4vq7aPjXEk9644uZOn1MYuIm+oI8rEP6xj/fCj18TDQtGNlJRr sgY5S9jbv+qxK402QB9B8gpXxcP2IO5WN6jAwgOsMOOqxALwAzPNqRbMEBsuGbwk Aoj0jrC9h0Y8puAwl8DHbEOFAmf7YBskH2fyOjasUT1t7p1FreGNW7Esf7Oq34Ui 9G3CSUMN6rDVn0yVUd9qdv34imfa7eq9ci1gfzBYRg5VtQkC3vC2Tn5XrT7ZVABp 721KtCl701O+lSn3AyBcl9/lbBLdEaHDq/OPR/08vkmJBJ1hUP13KwvdFtYYwxPT BCq6ZxTKNmPNNJCSEHYhkJ7J4lkPobipN8bNnAZB9xq58vjPXcmZmDKo0R1VanHN JXLGw/ZM3wEaVEWi/P3qydo3Vshr1g/vr7ZB+xjgnfr+/bTfjWZ3UkMHvFW18HOP n5VT2Hqnf9qZrBRaoDVy3dPCXDoXmBZx0urAKcP+J6/6UacvOS9G+e/cEFuNDGTe SVqtALilkfAhuJBKUHw2gH3pb22fatDHYJ6hDMDHs3PvCcEGffg= =cQ/y -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/philmd-gitlab/tags/mips-next-20191105' into staging The i440FX northbridge is only used by the PC machine, while the PIIX southbridge is also used by the Malta MIPS machine. Split the PIIX3 southbridge from i440FX northbridge. # gpg: Signature made Tue 05 Nov 2019 22:48:12 GMT # gpg: using RSA key 89C1E78F601EE86C867495CBA2A3FD6EDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (Phil) <philmd@redhat.com>" [marginal] # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 89C1 E78F 601E E86C 8674 95CB A2A3 FD6E DEAD C0DE * remotes/philmd-gitlab/tags/mips-next-20191105: (21 commits) hw/pci-host/i440fx: Remove the last PIIX3 traces hw/pci-host: Rename incorrectly named 'piix' as 'i440fx' hw/pci-host/piix: Extract PIIX3 functions to hw/isa/piix3.c hw/pci-host/piix: Fix code style issues hw/pci-host/piix: Move i440FX declarations to hw/pci-host/i440fx.h hw/pci-host/piix: Define and use the PIIX IRQ Route Control Registers hw/pci-host/piix: Move RCR_IOPORT register definition hw/pci-host/piix: Extract piix3_create() hw/i386: Remove obsolete LoadStateHandler::load_state_old handlers hw/isa/piix4: Move piix4_create() to hw/isa/piix4.c hw/mips/mips_malta: Extract the PIIX4 creation code as piix4_create() hw/mips/mips_malta: Create IDE hard drive array dynamically piix4: Add a MC146818 RTC Controller as specified in datasheet piix4: Add an i8254 PIT Controller as specified in datasheet piix4: Add an i8257 DMA Controller as specified in datasheet piix4: Rename PIIX4 object to piix4-isa Revert "irq: introduce qemu_irq_proxy()" piix4: Add an i8259 Interrupt Controller as specified in datasheet piix4: Add the Reset Control Register MAINTAINERS: Keep PIIX4 South Bridge separate from PC Chipsets ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
80d1c10b22
14
MAINTAINERS
14
MAINTAINERS
@ -1241,18 +1241,19 @@ M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
|
||||
S: Supported
|
||||
F: include/hw/i386/
|
||||
F: hw/i386/
|
||||
F: hw/pci-host/piix.c
|
||||
F: hw/pci-host/i440fx.c
|
||||
F: hw/pci-host/q35.c
|
||||
F: hw/pci-host/pam.c
|
||||
F: include/hw/pci-host/i440fx.h
|
||||
F: include/hw/pci-host/q35.h
|
||||
F: include/hw/pci-host/pam.h
|
||||
F: hw/isa/piix4.c
|
||||
F: hw/isa/piix3.c
|
||||
F: hw/isa/lpc_ich9.c
|
||||
F: hw/i2c/smbus_ich9.c
|
||||
F: hw/acpi/piix4.c
|
||||
F: hw/acpi/ich9.c
|
||||
F: include/hw/acpi/ich9.h
|
||||
F: include/hw/acpi/piix4.h
|
||||
F: include/hw/southbridge/piix.h
|
||||
F: hw/misc/sga.c
|
||||
F: hw/isa/apm.c
|
||||
F: include/hw/isa/apm.h
|
||||
@ -1753,6 +1754,13 @@ F: hw/display/edid*
|
||||
F: include/hw/display/edid.h
|
||||
F: qemu-edid.c
|
||||
|
||||
PIIX4 South Bridge (i82371AB)
|
||||
M: Hervé Poussineau <hpoussin@reactos.org>
|
||||
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||
S: Maintained
|
||||
F: hw/isa/piix4.c
|
||||
F: include/hw/southbridge/piix.h
|
||||
|
||||
Firmware configuration (fw_cfg)
|
||||
M: Philippe Mathieu-Daudé <philmd@redhat.com>
|
||||
R: Laszlo Ersek <lersek@redhat.com>
|
||||
|
3
Makefile
3
Makefile
@ -390,7 +390,8 @@ MINIKCONF_ARGS = \
|
||||
CONFIG_LINUX=$(CONFIG_LINUX) \
|
||||
CONFIG_PVRDMA=$(CONFIG_PVRDMA)
|
||||
|
||||
MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig
|
||||
MINIKCONF_INPUTS = $(SRC_PATH)/Kconfig.host $(SRC_PATH)/hw/Kconfig \
|
||||
$(wildcard $(SRC_PATH)/hw/*/Kconfig)
|
||||
MINIKCONF = $(PYTHON) $(SRC_PATH)/scripts/minikconf.py \
|
||||
|
||||
$(SUBDIR_DEVICES_MAK): %/config-devices.mak: default-configs/%.mak $(MINIKCONF_INPUTS) $(BUILD_DIR)/config-host.mak
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/acpi/pcihp.h"
|
||||
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/pci-host/i440fx.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_bridge.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/southbridge/piix.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/isa/apm.h"
|
||||
#include "hw/i2c/pm_smbus.h"
|
||||
@ -32,7 +33,6 @@
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/range.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/acpi/piix4.h"
|
||||
#include "hw/acpi/pcihp.h"
|
||||
#include "hw/acpi/cpu_hotplug.h"
|
||||
#include "hw/acpi/cpu.h"
|
||||
@ -41,7 +41,6 @@
|
||||
#include "hw/acpi/memory_hotplug.h"
|
||||
#include "hw/acpi/acpi_dev_interface.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "migration/qemu-file-types.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/core/cpu.h"
|
||||
#include "trace.h"
|
||||
@ -204,43 +203,6 @@ static const VMStateDescription vmstate_pci_status = {
|
||||
}
|
||||
};
|
||||
|
||||
static int acpi_load_old(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
int ret, i;
|
||||
uint16_t temp;
|
||||
|
||||
ret = pci_device_load(PCI_DEVICE(s), f);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
qemu_get_be16s(f, &s->ar.pm1.evt.sts);
|
||||
qemu_get_be16s(f, &s->ar.pm1.evt.en);
|
||||
qemu_get_be16s(f, &s->ar.pm1.cnt.cnt);
|
||||
|
||||
ret = vmstate_load_state(f, &vmstate_apm, &s->apm, 1);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
timer_get(f, s->ar.tmr.timer);
|
||||
qemu_get_sbe64s(f, &s->ar.tmr.overflow_time);
|
||||
|
||||
qemu_get_be16s(f, (uint16_t *)s->ar.gpe.sts);
|
||||
for (i = 0; i < 3; i++) {
|
||||
qemu_get_be16s(f, &temp);
|
||||
}
|
||||
|
||||
qemu_get_be16s(f, (uint16_t *)s->ar.gpe.en);
|
||||
for (i = 0; i < 3; i++) {
|
||||
qemu_get_be16s(f, &temp);
|
||||
}
|
||||
|
||||
ret = vmstate_load_state(f, &vmstate_pci_status,
|
||||
&s->acpi_pci_hotplug.acpi_pcihp_pci_status[ACPI_PCIHP_BSEL_DEFAULT], 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool vmstate_test_use_acpi_pci_hotplug(void *opaque, int version_id)
|
||||
{
|
||||
PIIX4PMState *s = opaque;
|
||||
@ -312,8 +274,6 @@ static const VMStateDescription vmstate_acpi = {
|
||||
.name = "piix4_pm",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 3,
|
||||
.minimum_version_id_old = 1,
|
||||
.load_state_old = acpi_load_old,
|
||||
.post_load = vmstate_acpi_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(parent_obj, PIIX4PMState),
|
||||
|
@ -120,20 +120,6 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2)
|
||||
return qemu_allocate_irq(qemu_splitirq, s, 0);
|
||||
}
|
||||
|
||||
static void proxy_irq_handler(void *opaque, int n, int level)
|
||||
{
|
||||
qemu_irq **target = opaque;
|
||||
|
||||
if (*target) {
|
||||
qemu_set_irq((*target)[n], level);
|
||||
}
|
||||
}
|
||||
|
||||
qemu_irq *qemu_irq_proxy(qemu_irq **target, int n)
|
||||
{
|
||||
return qemu_allocate_irqs(proxy_irq_handler, target, n);
|
||||
}
|
||||
|
||||
void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n)
|
||||
{
|
||||
int i;
|
||||
|
@ -60,7 +60,8 @@ config I440FX
|
||||
select PC_PCI
|
||||
select PC_ACPI
|
||||
select ACPI_SMBUS
|
||||
select PCI_PIIX
|
||||
select PCI_I440FX
|
||||
select PIIX3
|
||||
select IDE_PIIX
|
||||
select DIMM
|
||||
select SMBIOS
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include "hw/acpi/acpi-defs.h"
|
||||
#include "hw/acpi/acpi.h"
|
||||
#include "hw/acpi/cpu.h"
|
||||
#include "hw/acpi/piix4.h"
|
||||
#include "hw/nvram/fw_cfg.h"
|
||||
#include "hw/acpi/bios-linker-loader.h"
|
||||
#include "hw/isa/isa.h"
|
||||
@ -52,7 +51,7 @@
|
||||
#include "sysemu/reset.h"
|
||||
|
||||
/* Supported chipsets: */
|
||||
#include "hw/acpi/piix4.h"
|
||||
#include "hw/southbridge/piix.h"
|
||||
#include "hw/acpi/pcihp.h"
|
||||
#include "hw/i386/ich9.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
@ -210,7 +209,7 @@ static void acpi_get_pm_info(MachineState *machine, AcpiPmInfo *pm)
|
||||
|
||||
/* The above need not be conditional on machine type because the reset port
|
||||
* happens to be the same on PIIX (pc) and ICH9 (q35). */
|
||||
QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != RCR_IOPORT);
|
||||
QEMU_BUILD_BUG_ON(ICH9_RST_CNT_IOPORT != PIIX_RCR_IOPORT);
|
||||
|
||||
/* Fill in optional s3/s4 related properties */
|
||||
o = object_property_get_qobject(obj, ACPI_PM_PROP_S3_DISABLED, NULL);
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include "hw/i386/x86.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/i386/apic.h"
|
||||
#include "hw/pci-host/i440fx.h"
|
||||
#include "hw/southbridge/piix.h"
|
||||
#include "hw/display/ramfb.h"
|
||||
#include "hw/firmware/smbios.h"
|
||||
#include "hw/pci/pci.h"
|
||||
@ -190,14 +192,20 @@ static void pc_init1(MachineState *machine,
|
||||
gsi_state = pc_gsi_create(&x86ms->gsi, pcmc->pci_enabled);
|
||||
|
||||
if (pcmc->pci_enabled) {
|
||||
PIIX3State *piix3;
|
||||
|
||||
pci_bus = i440fx_init(host_type,
|
||||
pci_type,
|
||||
&i440fx_state, &piix3_devfn, &isa_bus, x86ms->gsi,
|
||||
&i440fx_state,
|
||||
system_memory, system_io, machine->ram_size,
|
||||
x86ms->below_4g_mem_size,
|
||||
x86ms->above_4g_mem_size,
|
||||
pci_memory, ram_memory);
|
||||
pcms->bus = pci_bus;
|
||||
|
||||
piix3 = piix3_create(pci_bus, &isa_bus);
|
||||
piix3->pic = x86ms->gsi;
|
||||
piix3_devfn = piix3->dev.devfn;
|
||||
} else {
|
||||
pci_bus = NULL;
|
||||
i440fx_state = NULL;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_host.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/southbridge/piix.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/i386/apic-msidef.h"
|
||||
@ -156,8 +157,8 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
|
||||
v = 0;
|
||||
}
|
||||
v &= 0xf;
|
||||
if (((address + i) >= 0x60) && ((address + i) <= 0x63)) {
|
||||
xen_set_pci_link_route(xen_domid, address + i - 0x60, v);
|
||||
if (((address + i) >= PIIX_PIRQCA) && ((address + i) <= PIIX_PIRQCD)) {
|
||||
xen_set_pci_link_route(xen_domid, address + i - PIIX_PIRQCA, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "sysemu/kvm.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "migration/qemu-file-types.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
static int apic_irq_delivered;
|
||||
@ -262,52 +261,6 @@ static void apic_reset_common(DeviceState *dev)
|
||||
apic_init_reset(dev);
|
||||
}
|
||||
|
||||
/* This function is only used for old state version 1 and 2 */
|
||||
static int apic_load_old(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
APICCommonState *s = opaque;
|
||||
APICCommonClass *info = APIC_COMMON_GET_CLASS(s);
|
||||
int i;
|
||||
|
||||
if (version_id > 2) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* XXX: what if the base changes? (registered memory regions) */
|
||||
qemu_get_be32s(f, &s->apicbase);
|
||||
qemu_get_8s(f, &s->id);
|
||||
qemu_get_8s(f, &s->arb_id);
|
||||
qemu_get_8s(f, &s->tpr);
|
||||
qemu_get_be32s(f, &s->spurious_vec);
|
||||
qemu_get_8s(f, &s->log_dest);
|
||||
qemu_get_8s(f, &s->dest_mode);
|
||||
for (i = 0; i < 8; i++) {
|
||||
qemu_get_be32s(f, &s->isr[i]);
|
||||
qemu_get_be32s(f, &s->tmr[i]);
|
||||
qemu_get_be32s(f, &s->irr[i]);
|
||||
}
|
||||
for (i = 0; i < APIC_LVT_NB; i++) {
|
||||
qemu_get_be32s(f, &s->lvt[i]);
|
||||
}
|
||||
qemu_get_be32s(f, &s->esr);
|
||||
qemu_get_be32s(f, &s->icr[0]);
|
||||
qemu_get_be32s(f, &s->icr[1]);
|
||||
qemu_get_be32s(f, &s->divide_conf);
|
||||
s->count_shift = qemu_get_be32(f);
|
||||
qemu_get_be32s(f, &s->initial_count);
|
||||
s->initial_count_load_time = qemu_get_be64(f);
|
||||
s->next_time = qemu_get_be64(f);
|
||||
|
||||
if (version_id >= 2) {
|
||||
s->timer_expiry = qemu_get_be64(f);
|
||||
}
|
||||
|
||||
if (info->post_load) {
|
||||
info->post_load(s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_apic_common;
|
||||
|
||||
static void apic_common_realize(DeviceState *dev, Error **errp)
|
||||
@ -408,8 +361,6 @@ static const VMStateDescription vmstate_apic_common = {
|
||||
.name = "apic",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 3,
|
||||
.minimum_version_id_old = 1,
|
||||
.load_state_old = apic_load_old,
|
||||
.pre_load = apic_pre_load,
|
||||
.pre_save = apic_dispatch_pre_save,
|
||||
.post_load = apic_dispatch_post_load,
|
||||
|
@ -29,6 +29,10 @@ config PC87312
|
||||
select FDC
|
||||
select IDE_ISA
|
||||
|
||||
config PIIX3
|
||||
bool
|
||||
select ISA_BUS
|
||||
|
||||
config PIIX4
|
||||
bool
|
||||
# For historical reasons, SuperIO devices are created in the board
|
||||
|
@ -3,6 +3,7 @@ common-obj-$(CONFIG_ISA_SUPERIO) += isa-superio.o
|
||||
common-obj-$(CONFIG_APM) += apm.o
|
||||
common-obj-$(CONFIG_I82378) += i82378.o
|
||||
common-obj-$(CONFIG_PC87312) += pc87312.o
|
||||
common-obj-$(CONFIG_PIIX3) += piix3.o
|
||||
common-obj-$(CONFIG_PIIX4) += piix4.o
|
||||
common-obj-$(CONFIG_VT82C686) += vt82c686.o
|
||||
common-obj-$(CONFIG_SMC37C669) += smc37c669-superio.o
|
||||
|
399
hw/isa/piix3.c
Normal file
399
hw/isa/piix3.c
Normal file
@ -0,0 +1,399 @@
|
||||
/*
|
||||
* QEMU PIIX PCI ISA 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 "qemu/osdep.h"
|
||||
#include "qemu/range.h"
|
||||
#include "hw/southbridge/piix.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
#define XEN_PIIX_NUM_PIRQS 128ULL
|
||||
|
||||
#define TYPE_PIIX3_PCI_DEVICE "pci-piix3"
|
||||
#define PIIX3_PCI_DEVICE(obj) \
|
||||
OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3_PCI_DEVICE)
|
||||
|
||||
#define TYPE_PIIX3_DEVICE "PIIX3"
|
||||
#define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen"
|
||||
|
||||
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_internal(PIIX3State *piix3, int pirq, int level)
|
||||
{
|
||||
int pic_irq;
|
||||
uint64_t mask;
|
||||
|
||||
pic_irq = piix3->dev.config[PIIX_PIRQCA + 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;
|
||||
}
|
||||
|
||||
static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
|
||||
{
|
||||
int pic_irq;
|
||||
|
||||
pic_irq = piix3->dev.config[PIIX_PIRQCA + pirq];
|
||||
if (pic_irq >= PIIX_NUM_PIC_IRQS) {
|
||||
return;
|
||||
}
|
||||
|
||||
piix3_set_irq_level_internal(piix3, pirq, 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);
|
||||
}
|
||||
|
||||
static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
|
||||
{
|
||||
PIIX3State *piix3 = opaque;
|
||||
int irq = piix3->dev.config[PIIX_PIRQCA + pin];
|
||||
PCIINTxRoute route;
|
||||
|
||||
if (irq < PIIX_NUM_PIC_IRQS) {
|
||||
route.mode = PCI_INTX_ENABLED;
|
||||
route.irq = irq;
|
||||
} else {
|
||||
route.mode = PCI_INTX_DISABLED;
|
||||
route.irq = -1;
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
/* irq routing is changed. so rebuild bitmap */
|
||||
static void piix3_update_irq_levels(PIIX3State *piix3)
|
||||
{
|
||||
PCIBus *bus = pci_get_bus(&piix3->dev);
|
||||
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(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_PIRQCA, 4)) {
|
||||
PIIX3State *piix3 = PIIX3_PCI_DEVICE(dev);
|
||||
int pic_irq;
|
||||
|
||||
pci_bus_fire_intx_routing_notifier(pci_get_bus(&piix3->dev));
|
||||
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;
|
||||
d->rcr = 0;
|
||||
}
|
||||
|
||||
static int piix3_post_load(void *opaque, int version_id)
|
||||
{
|
||||
PIIX3State *piix3 = opaque;
|
||||
int pirq;
|
||||
|
||||
/*
|
||||
* Because the i8259 has not been deserialized yet, qemu_irq_raise
|
||||
* might bring the system to a different state than the saved one;
|
||||
* for example, the interrupt could be masked but the i8259 would
|
||||
* not know that yet and would trigger an interrupt in the CPU.
|
||||
*
|
||||
* Here, we update irq levels without raising the interrupt.
|
||||
* Interrupt state will be deserialized separately through the i8259.
|
||||
*/
|
||||
piix3->pic_levels = 0;
|
||||
for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
|
||||
piix3_set_irq_level_internal(piix3, pirq,
|
||||
pci_bus_get_irq_level(pci_get_bus(&piix3->dev), pirq));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int 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(pci_get_bus(&piix3->dev), i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool piix3_rcr_needed(void *opaque)
|
||||
{
|
||||
PIIX3State *piix3 = opaque;
|
||||
|
||||
return (piix3->rcr != 0);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_piix3_rcr = {
|
||||
.name = "PIIX3/rcr",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = piix3_rcr_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(rcr, PIIX3State),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_piix3 = {
|
||||
.name = "PIIX3",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 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()
|
||||
},
|
||||
.subsections = (const VMStateDescription*[]) {
|
||||
&vmstate_piix3_rcr,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len)
|
||||
{
|
||||
PIIX3State *d = opaque;
|
||||
|
||||
if (val & 4) {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
return;
|
||||
}
|
||||
d->rcr = val & 2; /* keep System Reset type only */
|
||||
}
|
||||
|
||||
static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len)
|
||||
{
|
||||
PIIX3State *d = opaque;
|
||||
|
||||
return d->rcr;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps rcr_ops = {
|
||||
.read = rcr_read,
|
||||
.write = rcr_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN
|
||||
};
|
||||
|
||||
static void piix3_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
PIIX3State *d = PIIX3_PCI_DEVICE(dev);
|
||||
|
||||
if (!isa_bus_new(DEVICE(d), get_system_memory(),
|
||||
pci_address_space_io(dev), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_init_io(&d->rcr_mem, OBJECT(dev), &rcr_ops, d,
|
||||
"piix3-reset-control", 1);
|
||||
memory_region_add_subregion_overlap(pci_address_space_io(dev),
|
||||
PIIX_RCR_IOPORT, &d->rcr_mem, 1);
|
||||
|
||||
qemu_register_reset(piix3_reset, d);
|
||||
}
|
||||
|
||||
static void pci_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->hotpluggable = false;
|
||||
k->realize = piix3_realize;
|
||||
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;
|
||||
/*
|
||||
* Reason: part of PIIX3 southbridge, needs to be wired up by
|
||||
* pc_piix.c's pc_init1()
|
||||
*/
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo piix3_pci_type_info = {
|
||||
.name = TYPE_PIIX3_PCI_DEVICE,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(PIIX3State),
|
||||
.abstract = true,
|
||||
.class_init = pci_piix3_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static void piix3_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->config_write = piix3_write_config;
|
||||
}
|
||||
|
||||
static const TypeInfo piix3_info = {
|
||||
.name = TYPE_PIIX3_DEVICE,
|
||||
.parent = TYPE_PIIX3_PCI_DEVICE,
|
||||
.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 const TypeInfo piix3_xen_info = {
|
||||
.name = TYPE_PIIX3_XEN_DEVICE,
|
||||
.parent = TYPE_PIIX3_PCI_DEVICE,
|
||||
.class_init = piix3_xen_class_init,
|
||||
};
|
||||
|
||||
static void piix3_register_types(void)
|
||||
{
|
||||
type_register_static(&piix3_pci_type_info);
|
||||
type_register_static(&piix3_info);
|
||||
type_register_static(&piix3_xen_info);
|
||||
}
|
||||
|
||||
type_init(piix3_register_types)
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
PIIX3State *piix3_create(PCIBus *pci_bus, ISABus **isa_bus)
|
||||
{
|
||||
PIIX3State *piix3;
|
||||
PCIDevice *pci_dev;
|
||||
|
||||
/*
|
||||
* 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()) {
|
||||
pci_dev = pci_create_simple_multifunction(pci_bus, -1, true,
|
||||
TYPE_PIIX3_XEN_DEVICE);
|
||||
piix3 = PIIX3_PCI_DEVICE(pci_dev);
|
||||
pci_bus_irqs(pci_bus, xen_piix3_set_irq, xen_pci_slot_get_pirq,
|
||||
piix3, XEN_PIIX_NUM_PIRQS);
|
||||
} else {
|
||||
pci_dev = pci_create_simple_multifunction(pci_bus, -1, true,
|
||||
TYPE_PIIX3_DEVICE);
|
||||
piix3 = PIIX3_PCI_DEVICE(pci_dev);
|
||||
pci_bus_irqs(pci_bus, piix3_set_irq, pci_slot_get_pirq,
|
||||
piix3, PIIX_NUM_PIRQS);
|
||||
pci_bus_set_route_irq_fn(pci_bus, piix3_route_intx_pin_to_irq);
|
||||
}
|
||||
*isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0"));
|
||||
|
||||
return piix3;
|
||||
}
|
151
hw/isa/piix4.c
151
hw/isa/piix4.c
@ -2,6 +2,7 @@
|
||||
* QEMU PIIX4 PCI Bridge Emulation
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
* Copyright (c) 2018 Hervé Poussineau
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
@ -23,19 +24,34 @@
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/southbridge/piix.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/dma/i8257.h"
|
||||
#include "hw/timer/i8254.h"
|
||||
#include "hw/rtc/mc146818rtc.h"
|
||||
#include "hw/ide.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/runstate.h"
|
||||
|
||||
PCIDevice *piix4_dev;
|
||||
|
||||
typedef struct PIIX4State {
|
||||
PCIDevice dev;
|
||||
qemu_irq cpu_intr;
|
||||
qemu_irq *isa;
|
||||
|
||||
RTCState rtc;
|
||||
/* Reset Control Register */
|
||||
MemoryRegion rcr_mem;
|
||||
uint8_t rcr;
|
||||
} PIIX4State;
|
||||
|
||||
#define TYPE_PIIX4_PCI_DEVICE "PIIX4"
|
||||
#define PIIX4_PCI_DEVICE(obj) \
|
||||
OBJECT_CHECK(PIIX4State, (obj), TYPE_PIIX4_PCI_DEVICE)
|
||||
|
||||
@ -87,24 +103,102 @@ static const VMStateDescription vmstate_piix4 = {
|
||||
}
|
||||
};
|
||||
|
||||
static void piix4_realize(PCIDevice *dev, Error **errp)
|
||||
static void piix4_request_i8259_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
PIIX4State *d = PIIX4_PCI_DEVICE(dev);
|
||||
|
||||
if (!isa_bus_new(DEVICE(d), pci_address_space(dev),
|
||||
pci_address_space_io(dev), errp)) {
|
||||
return;
|
||||
}
|
||||
piix4_dev = &d->dev;
|
||||
PIIX4State *s = opaque;
|
||||
qemu_set_irq(s->cpu_intr, level);
|
||||
}
|
||||
|
||||
int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn)
|
||||
static void piix4_set_i8259_irq(void *opaque, int irq, int level)
|
||||
{
|
||||
PCIDevice *d;
|
||||
PIIX4State *s = opaque;
|
||||
qemu_set_irq(s->isa[irq], level);
|
||||
}
|
||||
|
||||
d = pci_create_simple_multifunction(bus, devfn, true, "PIIX4");
|
||||
*isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(d), "isa.0"));
|
||||
return d->devfn;
|
||||
static void piix4_rcr_write(void *opaque, hwaddr addr, uint64_t val,
|
||||
unsigned int len)
|
||||
{
|
||||
PIIX4State *s = opaque;
|
||||
|
||||
if (val & 4) {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
return;
|
||||
}
|
||||
|
||||
s->rcr = val & 2; /* keep System Reset type only */
|
||||
}
|
||||
|
||||
static uint64_t piix4_rcr_read(void *opaque, hwaddr addr, unsigned int len)
|
||||
{
|
||||
PIIX4State *s = opaque;
|
||||
|
||||
return s->rcr;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps piix4_rcr_ops = {
|
||||
.read = piix4_rcr_read,
|
||||
.write = piix4_rcr_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.impl = {
|
||||
.min_access_size = 1,
|
||||
.max_access_size = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static void piix4_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
PIIX4State *s = PIIX4_PCI_DEVICE(dev);
|
||||
ISABus *isa_bus;
|
||||
qemu_irq *i8259_out_irq;
|
||||
Error *err = NULL;
|
||||
|
||||
isa_bus = isa_bus_new(DEVICE(dev), pci_address_space(dev),
|
||||
pci_address_space_io(dev), errp);
|
||||
if (!isa_bus) {
|
||||
return;
|
||||
}
|
||||
|
||||
qdev_init_gpio_in_named(DEVICE(dev), piix4_set_i8259_irq,
|
||||
"isa", ISA_NUM_IRQS);
|
||||
qdev_init_gpio_out_named(DEVICE(dev), &s->cpu_intr,
|
||||
"intr", 1);
|
||||
|
||||
memory_region_init_io(&s->rcr_mem, OBJECT(dev), &piix4_rcr_ops, s,
|
||||
"reset-control", 1);
|
||||
memory_region_add_subregion_overlap(pci_address_space_io(dev),
|
||||
PIIX_RCR_IOPORT, &s->rcr_mem, 1);
|
||||
|
||||
/* initialize i8259 pic */
|
||||
i8259_out_irq = qemu_allocate_irqs(piix4_request_i8259_irq, s, 1);
|
||||
s->isa = i8259_init(isa_bus, *i8259_out_irq);
|
||||
|
||||
/* initialize ISA irqs */
|
||||
isa_bus_irqs(isa_bus, s->isa);
|
||||
|
||||
/* initialize pit */
|
||||
i8254_pit_init(isa_bus, 0x40, 0, NULL);
|
||||
|
||||
/* DMA */
|
||||
i8257_dma_init(isa_bus, 0);
|
||||
|
||||
/* RTC */
|
||||
qdev_set_parent_bus(DEVICE(&s->rtc), BUS(isa_bus));
|
||||
qdev_prop_set_int32(DEVICE(&s->rtc), "base_year", 2000);
|
||||
object_property_set_bool(OBJECT(&s->rtc), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
return;
|
||||
}
|
||||
isa_init_irq(ISA_DEVICE(&s->rtc), &s->rtc.irq, RTC_ISA_IRQ);
|
||||
|
||||
piix4_dev = dev;
|
||||
}
|
||||
|
||||
static void piix4_init(Object *obj)
|
||||
{
|
||||
PIIX4State *s = PIIX4_PCI_DEVICE(obj);
|
||||
|
||||
object_initialize(&s->rtc, sizeof(s->rtc), TYPE_MC146818_RTC);
|
||||
}
|
||||
|
||||
static void piix4_class_init(ObjectClass *klass, void *data)
|
||||
@ -131,6 +225,7 @@ static const TypeInfo piix4_info = {
|
||||
.name = TYPE_PIIX4_PCI_DEVICE,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(PIIX4State),
|
||||
.instance_init = piix4_init,
|
||||
.class_init = piix4_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
||||
@ -144,3 +239,31 @@ static void piix4_register_types(void)
|
||||
}
|
||||
|
||||
type_init(piix4_register_types)
|
||||
|
||||
DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus,
|
||||
I2CBus **smbus, size_t ide_buses)
|
||||
{
|
||||
size_t ide_drives = ide_buses * MAX_IDE_DEVS;
|
||||
DriveInfo **hd;
|
||||
PCIDevice *pci;
|
||||
DeviceState *dev;
|
||||
|
||||
pci = pci_create_simple_multifunction(pci_bus, PCI_DEVFN(10, 0),
|
||||
true, TYPE_PIIX4_PCI_DEVICE);
|
||||
dev = DEVICE(pci);
|
||||
if (isa_bus) {
|
||||
*isa_bus = ISA_BUS(qdev_get_child_bus(dev, "isa.0"));
|
||||
}
|
||||
|
||||
hd = g_new(DriveInfo *, ide_drives);
|
||||
ide_drive_get(hd, ide_drives);
|
||||
pci_piix4_ide_init(pci_bus, hd, pci->devfn + 1);
|
||||
g_free(hd);
|
||||
pci_create_simple(pci_bus, pci->devfn + 2, "piix4-usb-uhci");
|
||||
if (smbus) {
|
||||
*smbus = piix4_pm_init(pci_bus, pci->devfn + 3, 0x1100,
|
||||
isa_get_irq(NULL, 9), NULL, 0, NULL);
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "hw/mips/mips.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_host.h"
|
||||
#include "hw/southbridge/piix.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/irq.h"
|
||||
@ -1012,12 +1013,12 @@ static void gt64120_pci_set_irq(void *opaque, int irq_num, int level)
|
||||
|
||||
/* now we change the pic irq level according to the piix irq mappings */
|
||||
/* XXX: optimize */
|
||||
pic_irq = piix4_dev->config[0x60 + irq_num];
|
||||
pic_irq = piix4_dev->config[PIIX_PIRQCA + irq_num];
|
||||
if (pic_irq < 16) {
|
||||
/* The pic level is the logical OR of all the PCI irqs mapped to it. */
|
||||
pic_level = 0;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (pic_irq == piix4_dev->config[0x60 + i]) {
|
||||
if (pic_irq == piix4_dev->config[PIIX_PIRQCA + i]) {
|
||||
pic_level |= pci_irq_levels[i];
|
||||
}
|
||||
}
|
||||
|
@ -26,9 +26,8 @@
|
||||
#include "qemu/units.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/southbridge/piix.h"
|
||||
#include "hw/isa/superio.h"
|
||||
#include "hw/dma/i8257.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "net/net.h"
|
||||
#include "hw/boards.h"
|
||||
@ -45,8 +44,6 @@
|
||||
#include "hw/irq.h"
|
||||
#include "hw/loader.h"
|
||||
#include "elf.h"
|
||||
#include "hw/rtc/mc146818rtc.h"
|
||||
#include "hw/timer/i8254.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/sysbus.h" /* SysBusDevice */
|
||||
#include "qemu/host-utils.h"
|
||||
@ -97,11 +94,9 @@ typedef struct {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
MIPSCPSState cps;
|
||||
qemu_irq *i8259;
|
||||
qemu_irq i8259[ISA_NUM_IRQS];
|
||||
} MaltaState;
|
||||
|
||||
static ISADevice *pit;
|
||||
|
||||
static struct _loaderparams {
|
||||
int ram_size, ram_low_size;
|
||||
const char *kernel_filename;
|
||||
@ -1235,12 +1230,9 @@ void mips_malta_init(MachineState *machine)
|
||||
int64_t kernel_entry, bootloader_run_addr;
|
||||
PCIBus *pci_bus;
|
||||
ISABus *isa_bus;
|
||||
qemu_irq *isa_irq;
|
||||
qemu_irq cbus_irq, i8259_irq;
|
||||
int piix4_devfn;
|
||||
I2CBus *smbus;
|
||||
DriveInfo *dinfo;
|
||||
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
|
||||
int fl_idx = 0;
|
||||
int be;
|
||||
|
||||
@ -1407,37 +1399,17 @@ void mips_malta_init(MachineState *machine)
|
||||
/* Board ID = 0x420 (Malta Board with CoreLV) */
|
||||
stl_p(memory_region_get_ram_ptr(bios_copy) + 0x10, 0x00000420);
|
||||
|
||||
/*
|
||||
* We have a circular dependency problem: pci_bus depends on isa_irq,
|
||||
* isa_irq is provided by i8259, i8259 depends on ISA, ISA depends
|
||||
* on piix4, and piix4 depends on pci_bus. To stop the cycle we have
|
||||
* qemu_irq_proxy() adds an extra bit of indirection, allowing us
|
||||
* to resolve the isa_irq -> i8259 dependency after i8259 is initialized.
|
||||
*/
|
||||
isa_irq = qemu_irq_proxy(&s->i8259, 16);
|
||||
|
||||
/* Northbridge */
|
||||
pci_bus = gt64120_register(isa_irq);
|
||||
pci_bus = gt64120_register(s->i8259);
|
||||
|
||||
/* Southbridge */
|
||||
ide_drive_get(hd, ARRAY_SIZE(hd));
|
||||
dev = piix4_create(pci_bus, &isa_bus, &smbus, MAX_IDE_BUS);
|
||||
|
||||
piix4_devfn = piix4_init(pci_bus, &isa_bus, 80);
|
||||
|
||||
/*
|
||||
* Interrupt controller
|
||||
* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2
|
||||
*/
|
||||
s->i8259 = i8259_init(isa_bus, i8259_irq);
|
||||
|
||||
isa_bus_irqs(isa_bus, s->i8259);
|
||||
pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1);
|
||||
pci_create_simple(pci_bus, piix4_devfn + 2, "piix4-usb-uhci");
|
||||
smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100,
|
||||
isa_get_irq(NULL, 9), NULL, 0, NULL);
|
||||
pit = i8254_pit_init(isa_bus, 0x40, 0, NULL);
|
||||
i8257_dma_init(isa_bus, 0);
|
||||
mc146818_rtc_init(isa_bus, 2000, NULL);
|
||||
/* Interrupt controller */
|
||||
qdev_connect_gpio_out_named(dev, "intr", 0, i8259_irq);
|
||||
for (int i = 0; i < ISA_NUM_IRQS; i++) {
|
||||
s->i8259[i] = qdev_get_gpio_in_named(dev, "isa", i);
|
||||
}
|
||||
|
||||
/* generate SPD EEPROM data */
|
||||
generate_eeprom_spd(&smbus_eeprom_buf[0 * 256], ram_size);
|
||||
|
@ -28,11 +28,10 @@ config PCI_SABRE
|
||||
select PCI
|
||||
bool
|
||||
|
||||
config PCI_PIIX
|
||||
config PCI_I440FX
|
||||
bool
|
||||
select PCI
|
||||
select PAM
|
||||
select ISA_BUS
|
||||
|
||||
config PCI_EXPRESS_Q35
|
||||
bool
|
||||
|
@ -13,7 +13,7 @@ common-obj-$(CONFIG_VERSATILE_PCI) += versatile.o
|
||||
|
||||
common-obj-$(CONFIG_PCI_SABRE) += sabre.o
|
||||
common-obj-$(CONFIG_FULONG) += bonito.o
|
||||
common-obj-$(CONFIG_PCI_PIIX) += piix.o
|
||||
common-obj-$(CONFIG_PCI_I440FX) += i440fx.o
|
||||
common-obj-$(CONFIG_PCI_EXPRESS_Q35) += q35.o
|
||||
common-obj-$(CONFIG_PCI_EXPRESS_GENERIC_BRIDGE) += gpex.o
|
||||
common-obj-$(CONFIG_PCI_EXPRESS_XILINX) += xilinx-pcie.o
|
||||
|
@ -24,21 +24,14 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_host.h"
|
||||
#include "hw/pci-host/i440fx.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/isa/isa.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/range.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "migration/qemu-file-types.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/pci-host/pam.h"
|
||||
#include "sysemu/reset.h"
|
||||
#include "sysemu/runstate.h"
|
||||
#include "hw/i386/ioapic.h"
|
||||
#include "qapi/visitor.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
@ -58,50 +51,9 @@ typedef struct I440FXState {
|
||||
uint32_t short_root_bus;
|
||||
} 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];
|
||||
|
||||
/* Reset Control Register contents */
|
||||
uint8_t rcr;
|
||||
|
||||
/* IO memory region for Reset Control Register (RCR_IOPORT) */
|
||||
MemoryRegion rcr_mem;
|
||||
} PIIX3State;
|
||||
|
||||
#define TYPE_PIIX3_PCI_DEVICE "pci-piix3"
|
||||
#define PIIX3_PCI_DEVICE(obj) \
|
||||
OBJECT_CHECK(PIIX3State, (obj), TYPE_PIIX3_PCI_DEVICE)
|
||||
|
||||
#define I440FX_PCI_DEVICE(obj) \
|
||||
OBJECT_CHECK(PCII440FXState, (obj), TYPE_I440FX_PCI_DEVICE)
|
||||
|
||||
#define TYPE_PIIX3_DEVICE "PIIX3"
|
||||
#define TYPE_PIIX3_XEN_DEVICE "PIIX3-xen"
|
||||
|
||||
struct PCII440FXState {
|
||||
/*< private >*/
|
||||
PCIDevice parent_obj;
|
||||
@ -128,21 +80,6 @@ struct PCII440FXState {
|
||||
*/
|
||||
#define I440FX_COREBOOT_RAM_SIZE 0x57
|
||||
|
||||
static void piix3_set_irq(void *opaque, int pirq, int level);
|
||||
static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pci_intx);
|
||||
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 i440fx_update_memory_mappings(PCII440FXState *d)
|
||||
{
|
||||
int i;
|
||||
@ -174,28 +111,6 @@ static void i440fx_write_config(PCIDevice *dev,
|
||||
}
|
||||
}
|
||||
|
||||
static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
|
||||
{
|
||||
PCII440FXState *d = opaque;
|
||||
PCIDevice *pd = PCI_DEVICE(d);
|
||||
int ret, i;
|
||||
uint8_t smm_enabled;
|
||||
|
||||
ret = pci_device_load(pd, f);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
i440fx_update_memory_mappings(d);
|
||||
qemu_get_8s(f, &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;
|
||||
@ -208,8 +123,6 @@ 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(parent_obj, PCII440FXState),
|
||||
@ -358,8 +271,6 @@ static void i440fx_realize(PCIDevice *dev, Error **errp)
|
||||
|
||||
PCIBus *i440fx_init(const char *host_type, const char *pci_type,
|
||||
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,
|
||||
@ -372,7 +283,6 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type,
|
||||
PCIBus *b;
|
||||
PCIDevice *d;
|
||||
PCIHostState *s;
|
||||
PIIX3State *piix3;
|
||||
PCII440FXState *f;
|
||||
unsigned i;
|
||||
I440FXState *i440fx;
|
||||
@ -425,29 +335,6 @@ PCIBus *i440fx_init(const char *host_type, const char *pci_type,
|
||||
PAM_EXPAN_SIZE);
|
||||
}
|
||||
|
||||
/* 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()) {
|
||||
PCIDevice *pci_dev = pci_create_simple_multifunction(b,
|
||||
-1, true, TYPE_PIIX3_XEN_DEVICE);
|
||||
piix3 = PIIX3_PCI_DEVICE(pci_dev);
|
||||
pci_bus_irqs(b, xen_piix3_set_irq, xen_pci_slot_get_pirq,
|
||||
piix3, XEN_PIIX_NUM_PIRQS);
|
||||
} else {
|
||||
PCIDevice *pci_dev = pci_create_simple_multifunction(b,
|
||||
-1, true, TYPE_PIIX3_DEVICE);
|
||||
piix3 = PIIX3_PCI_DEVICE(pci_dev);
|
||||
pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3,
|
||||
PIIX_NUM_PIRQS);
|
||||
pci_bus_set_route_irq_fn(b, piix3_route_intx_pin_to_irq);
|
||||
}
|
||||
piix3->pic = pic;
|
||||
*isa_bus = ISA_BUS(qdev_get_child_bus(DEVICE(piix3), "isa.0"));
|
||||
|
||||
*piix3_devfn = piix3->dev.devfn;
|
||||
|
||||
ram_size = ram_size / 8 / 1024 / 1024;
|
||||
if (ram_size > 255) {
|
||||
ram_size = 255;
|
||||
@ -467,312 +354,6 @@ PCIBus *find_i440fx(void)
|
||||
return s ? s->bus : NULL;
|
||||
}
|
||||
|
||||
/* 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_internal(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;
|
||||
}
|
||||
|
||||
static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
|
||||
{
|
||||
int pic_irq;
|
||||
|
||||
pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
|
||||
if (pic_irq >= PIIX_NUM_PIC_IRQS) {
|
||||
return;
|
||||
}
|
||||
|
||||
piix3_set_irq_level_internal(piix3, pirq, 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);
|
||||
}
|
||||
|
||||
static PCIINTxRoute piix3_route_intx_pin_to_irq(void *opaque, int pin)
|
||||
{
|
||||
PIIX3State *piix3 = opaque;
|
||||
int irq = piix3->dev.config[PIIX_PIRQC + pin];
|
||||
PCIINTxRoute route;
|
||||
|
||||
if (irq < PIIX_NUM_PIC_IRQS) {
|
||||
route.mode = PCI_INTX_ENABLED;
|
||||
route.irq = irq;
|
||||
} else {
|
||||
route.mode = PCI_INTX_DISABLED;
|
||||
route.irq = -1;
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
/* irq routing is changed. so rebuild bitmap */
|
||||
static void piix3_update_irq_levels(PIIX3State *piix3)
|
||||
{
|
||||
PCIBus *bus = pci_get_bus(&piix3->dev);
|
||||
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(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 = PIIX3_PCI_DEVICE(dev);
|
||||
int pic_irq;
|
||||
|
||||
pci_bus_fire_intx_routing_notifier(pci_get_bus(&piix3->dev));
|
||||
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;
|
||||
d->rcr = 0;
|
||||
}
|
||||
|
||||
static int piix3_post_load(void *opaque, int version_id)
|
||||
{
|
||||
PIIX3State *piix3 = opaque;
|
||||
int pirq;
|
||||
|
||||
/* Because the i8259 has not been deserialized yet, qemu_irq_raise
|
||||
* might bring the system to a different state than the saved one;
|
||||
* for example, the interrupt could be masked but the i8259 would
|
||||
* not know that yet and would trigger an interrupt in the CPU.
|
||||
*
|
||||
* Here, we update irq levels without raising the interrupt.
|
||||
* Interrupt state will be deserialized separately through the i8259.
|
||||
*/
|
||||
piix3->pic_levels = 0;
|
||||
for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
|
||||
piix3_set_irq_level_internal(piix3, pirq,
|
||||
pci_bus_get_irq_level(pci_get_bus(&piix3->dev), pirq));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int 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(pci_get_bus(&piix3->dev), i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool piix3_rcr_needed(void *opaque)
|
||||
{
|
||||
PIIX3State *piix3 = opaque;
|
||||
|
||||
return (piix3->rcr != 0);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_piix3_rcr = {
|
||||
.name = "PIIX3/rcr",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.needed = piix3_rcr_needed,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT8(rcr, PIIX3State),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_piix3 = {
|
||||
.name = "PIIX3",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 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()
|
||||
},
|
||||
.subsections = (const VMStateDescription*[]) {
|
||||
&vmstate_piix3_rcr,
|
||||
NULL
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len)
|
||||
{
|
||||
PIIX3State *d = opaque;
|
||||
|
||||
if (val & 4) {
|
||||
qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
|
||||
return;
|
||||
}
|
||||
d->rcr = val & 2; /* keep System Reset type only */
|
||||
}
|
||||
|
||||
static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len)
|
||||
{
|
||||
PIIX3State *d = opaque;
|
||||
|
||||
return d->rcr;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps rcr_ops = {
|
||||
.read = rcr_read,
|
||||
.write = rcr_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN
|
||||
};
|
||||
|
||||
static void piix3_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
PIIX3State *d = PIIX3_PCI_DEVICE(dev);
|
||||
|
||||
if (!isa_bus_new(DEVICE(d), get_system_memory(),
|
||||
pci_address_space_io(dev), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_init_io(&d->rcr_mem, OBJECT(dev), &rcr_ops, d,
|
||||
"piix3-reset-control", 1);
|
||||
memory_region_add_subregion_overlap(pci_address_space_io(dev), RCR_IOPORT,
|
||||
&d->rcr_mem, 1);
|
||||
|
||||
qemu_register_reset(piix3_reset, d);
|
||||
}
|
||||
|
||||
static void pci_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->hotpluggable = false;
|
||||
k->realize = piix3_realize;
|
||||
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;
|
||||
/*
|
||||
* Reason: part of PIIX3 southbridge, needs to be wired up by
|
||||
* pc_piix.c's pc_init1()
|
||||
*/
|
||||
dc->user_creatable = false;
|
||||
}
|
||||
|
||||
static const TypeInfo piix3_pci_type_info = {
|
||||
.name = TYPE_PIIX3_PCI_DEVICE,
|
||||
.parent = TYPE_PCI_DEVICE,
|
||||
.instance_size = sizeof(PIIX3State),
|
||||
.abstract = true,
|
||||
.class_init = pci_piix3_class_init,
|
||||
.interfaces = (InterfaceInfo[]) {
|
||||
{ INTERFACE_CONVENTIONAL_PCI_DEVICE },
|
||||
{ },
|
||||
},
|
||||
};
|
||||
|
||||
static void piix3_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->config_write = piix3_write_config;
|
||||
}
|
||||
|
||||
static const TypeInfo piix3_info = {
|
||||
.name = TYPE_PIIX3_DEVICE,
|
||||
.parent = TYPE_PIIX3_PCI_DEVICE,
|
||||
.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 const TypeInfo piix3_xen_info = {
|
||||
.name = TYPE_PIIX3_XEN_DEVICE,
|
||||
.parent = TYPE_PIIX3_PCI_DEVICE,
|
||||
.class_init = piix3_xen_class_init,
|
||||
};
|
||||
|
||||
static void i440fx_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
@ -934,9 +515,6 @@ static void i440fx_register_types(void)
|
||||
{
|
||||
type_register_static(&i440fx_info);
|
||||
type_register_static(&igd_passthrough_i440fx_info);
|
||||
type_register_static(&piix3_pci_type_info);
|
||||
type_register_static(&piix3_info);
|
||||
type_register_static(&piix3_xen_info);
|
||||
type_register_static(&i440fx_pcihost_info);
|
||||
}
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/timer/i8254.h"
|
||||
#include "hw/timer/i8254_internal.h"
|
||||
#include "migration/qemu-file-types.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
/* val must be 0 or 1 */
|
||||
@ -202,43 +201,6 @@ static const VMStateDescription vmstate_pit_channel = {
|
||||
}
|
||||
};
|
||||
|
||||
static int pit_load_old(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
PITCommonState *pit = opaque;
|
||||
PITCommonClass *c = PIT_COMMON_GET_CLASS(pit);
|
||||
PITChannelState *s;
|
||||
int i;
|
||||
|
||||
if (version_id != 1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
s = &pit->channels[i];
|
||||
s->count = qemu_get_be32(f);
|
||||
qemu_get_be16s(f, &s->latched_count);
|
||||
qemu_get_8s(f, &s->count_latched);
|
||||
qemu_get_8s(f, &s->status_latched);
|
||||
qemu_get_8s(f, &s->status);
|
||||
qemu_get_8s(f, &s->read_state);
|
||||
qemu_get_8s(f, &s->write_state);
|
||||
qemu_get_8s(f, &s->write_latch);
|
||||
qemu_get_8s(f, &s->rw_mode);
|
||||
qemu_get_8s(f, &s->mode);
|
||||
qemu_get_8s(f, &s->bcd);
|
||||
qemu_get_8s(f, &s->gate);
|
||||
s->count_load_time = qemu_get_be64(f);
|
||||
s->irq_disabled = 0;
|
||||
if (i == 0) {
|
||||
s->next_transition_time = qemu_get_be64(f);
|
||||
}
|
||||
}
|
||||
if (c->post_load) {
|
||||
c->post_load(pit);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pit_dispatch_pre_save(void *opaque)
|
||||
{
|
||||
PITCommonState *s = opaque;
|
||||
@ -266,8 +228,6 @@ static const VMStateDescription vmstate_pit_common = {
|
||||
.name = "i8254",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 1,
|
||||
.load_state_old = pit_load_old,
|
||||
.pre_save = pit_dispatch_pre_save,
|
||||
.post_load = pit_dispatch_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
|
@ -1,6 +0,0 @@
|
||||
#ifndef HW_ACPI_PIIX4_H
|
||||
#define HW_ACPI_PIIX4_H
|
||||
|
||||
#define TYPE_PIIX4_PM "PIIX4_PM"
|
||||
|
||||
#endif
|
@ -228,46 +228,9 @@ int cmos_get_fd_drive_type(FloppyDriveType fd0);
|
||||
|
||||
#define PORT92_A20_LINE "a20"
|
||||
|
||||
/* acpi_piix.c */
|
||||
|
||||
I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
||||
qemu_irq sci_irq, qemu_irq smi_irq,
|
||||
int smm_enabled, DeviceState **piix4_pm);
|
||||
|
||||
/* hpet.c */
|
||||
extern int no_hpet;
|
||||
|
||||
/* piix_pci.c */
|
||||
struct PCII440FXState;
|
||||
typedef struct PCII440FXState PCII440FXState;
|
||||
|
||||
#define TYPE_I440FX_PCI_HOST_BRIDGE "i440FX-pcihost"
|
||||
#define TYPE_I440FX_PCI_DEVICE "i440FX"
|
||||
|
||||
#define TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE "igd-passthrough-i440FX"
|
||||
|
||||
/*
|
||||
* Reset Control Register: PCI-accessible ISA-Compatible Register at address
|
||||
* 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000).
|
||||
*/
|
||||
#define RCR_IOPORT 0xcf9
|
||||
|
||||
PCIBus *i440fx_init(const char *host_type, const char *pci_type,
|
||||
PCII440FXState **pi440fx_state, int *piix_devfn,
|
||||
ISABus **isa_bus, qemu_irq *pic,
|
||||
MemoryRegion *address_space_mem,
|
||||
MemoryRegion *address_space_io,
|
||||
ram_addr_t ram_size,
|
||||
ram_addr_t below_4g_mem_size,
|
||||
ram_addr_t above_4g_mem_size,
|
||||
MemoryRegion *pci_memory,
|
||||
MemoryRegion *ram_memory);
|
||||
|
||||
PCIBus *find_i440fx(void);
|
||||
/* piix4.c */
|
||||
extern PCIDevice *piix4_dev;
|
||||
int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn);
|
||||
|
||||
/* pc_sysfw.c */
|
||||
void pc_system_flash_create(PCMachineState *pcms);
|
||||
void pc_system_firmware_init(PCMachineState *pcms, MemoryRegion *rom_memory);
|
||||
|
@ -51,11 +51,6 @@ qemu_irq qemu_irq_invert(qemu_irq irq);
|
||||
*/
|
||||
qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2);
|
||||
|
||||
/* Returns a new IRQ set which connects 1:1 to another IRQ set, which
|
||||
* may be set later.
|
||||
*/
|
||||
qemu_irq *qemu_irq_proxy(qemu_irq **target, int n);
|
||||
|
||||
/* For internal use in qtest. Similar to qemu_irq_split, but operating
|
||||
on an existing vector of qemu_irq. */
|
||||
void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n);
|
||||
|
@ -147,4 +147,6 @@ static inline ISABus *isa_bus_from_device(ISADevice *d)
|
||||
return ISA_BUS(qdev_get_parent_bus(DEVICE(d)));
|
||||
}
|
||||
|
||||
#define TYPE_PIIX4_PCI_DEVICE "piix4-isa"
|
||||
|
||||
#endif
|
||||
|
36
include/hw/pci-host/i440fx.h
Normal file
36
include/hw/pci-host/i440fx.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* QEMU i440FX North Bridge Emulation
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HW_PCI_I440FX_H
|
||||
#define HW_PCI_I440FX_H
|
||||
|
||||
#include "hw/hw.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
|
||||
typedef struct PCII440FXState PCII440FXState;
|
||||
|
||||
#define TYPE_I440FX_PCI_HOST_BRIDGE "i440FX-pcihost"
|
||||
#define TYPE_I440FX_PCI_DEVICE "i440FX"
|
||||
|
||||
#define TYPE_IGD_PASSTHROUGH_I440FX_PCI_DEVICE "igd-passthrough-i440FX"
|
||||
|
||||
PCIBus *i440fx_init(const char *host_type, const char *pci_type,
|
||||
PCII440FXState **pi440fx_state,
|
||||
MemoryRegion *address_space_mem,
|
||||
MemoryRegion *address_space_io,
|
||||
ram_addr_t ram_size,
|
||||
ram_addr_t below_4g_mem_size,
|
||||
ram_addr_t above_4g_mem_size,
|
||||
MemoryRegion *pci_memory,
|
||||
MemoryRegion *ram_memory);
|
||||
|
||||
PCIBus *find_i440fx(void);
|
||||
|
||||
#endif
|
74
include/hw/southbridge/piix.h
Normal file
74
include/hw/southbridge/piix.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* QEMU PIIX South Bridge Emulation
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
* Copyright (c) 2018 Hervé Poussineau
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HW_SOUTHBRIDGE_PIIX_H
|
||||
#define HW_SOUTHBRIDGE_PIIX_H
|
||||
|
||||
#include "hw/pci/pci.h"
|
||||
|
||||
#define TYPE_PIIX4_PM "PIIX4_PM"
|
||||
|
||||
I2CBus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
|
||||
qemu_irq sci_irq, qemu_irq smi_irq,
|
||||
int smm_enabled, DeviceState **piix4_pm);
|
||||
|
||||
/* PIRQRC[A:D]: PIRQx Route Control Registers */
|
||||
#define PIIX_PIRQCA 0x60
|
||||
#define PIIX_PIRQCB 0x61
|
||||
#define PIIX_PIRQCC 0x62
|
||||
#define PIIX_PIRQCD 0x63
|
||||
|
||||
/*
|
||||
* Reset Control Register: PCI-accessible ISA-Compatible Register at address
|
||||
* 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000).
|
||||
*/
|
||||
#define PIIX_RCR_IOPORT 0xcf9
|
||||
|
||||
#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */
|
||||
#define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */
|
||||
|
||||
typedef struct PIIXState {
|
||||
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];
|
||||
|
||||
/* Reset Control Register contents */
|
||||
uint8_t rcr;
|
||||
|
||||
/* IO memory region for Reset Control Register (PIIX_RCR_IOPORT) */
|
||||
MemoryRegion rcr_mem;
|
||||
} PIIX3State;
|
||||
|
||||
extern PCIDevice *piix4_dev;
|
||||
|
||||
PIIX3State *piix3_create(PCIBus *pci_bus, ISABus **isa_bus);
|
||||
|
||||
DeviceState *piix4_create(PCIBus *pci_bus, ISABus **isa_bus,
|
||||
I2CBus **smbus, size_t ide_buses);
|
||||
|
||||
#endif
|
@ -1,5 +1,6 @@
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "hw/pci-host/i440fx.h"
|
||||
|
||||
PCIBus *find_i440fx(void)
|
||||
{
|
||||
return NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user