* [Qemu-devel] [PATCH 01/18] acpi.c: make qemu_system_device_hot_add piix independent.
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 02/18] acpi.c: split out pc smbus routines from acpi.c into pc_smbus.c Isaku Yamahata
` (17 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
introruce piix4_device_hot_add() for piix4 specific code
and make qemu_system_device_hot_add() generic.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/acpi.c | 20 ++++++++++++++++++--
hw/pc.c | 2 +-
hw/pc.h | 7 +++++--
sysemu.h | 3 ++-
4 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/hw/acpi.c b/hw/acpi.c
index fccae69..5928fe7 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -714,7 +714,9 @@ static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
#endif
}
-void qemu_system_hot_add_init(void)
+static void piix4_device_hot_add(int bus, int slot, int state);
+
+void piix4_acpi_system_hot_add_init(void)
{
register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, &gpe);
register_ioport_read(GPE_BASE, 4, 1, gpe_readb, &gpe);
@@ -724,6 +726,8 @@ void qemu_system_hot_add_init(void)
register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, NULL);
register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, NULL);
+
+ qemu_system_device_hot_add_register(piix4_device_hot_add);
}
static void enable_device(struct pci_status *p, struct gpe_regs *g, int slot)
@@ -738,7 +742,7 @@ static void disable_device(struct pci_status *p, struct gpe_regs *g, int slot)
p->down |= (1 << slot);
}
-void qemu_system_device_hot_add(int bus, int slot, int state)
+static void piix4_device_hot_add(int bus, int slot, int state)
{
pci0_status.up = 0;
pci0_status.down = 0;
@@ -752,6 +756,18 @@ void qemu_system_device_hot_add(int bus, int slot, int state)
}
}
+static qemu_system_device_hot_add_t device_hot_add_callback;
+void qemu_system_device_hot_add_register(qemu_system_device_hot_add_t callback)
+{
+ device_hot_add_callback = callback;
+}
+
+void qemu_system_device_hot_add(int pcibus, int slot, int state)
+{
+ if (device_hot_add_callback)
+ device_hot_add_callback(pcibus, slot, state);
+}
+
struct acpi_table_header
{
char signature [4]; /* ACPI signature (4 ASCII characters) */
diff --git a/hw/pc.c b/hw/pc.c
index 143b697..a848d8d 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1066,7 +1066,7 @@ static void pc_init1(ram_addr_t ram_size,
pci_nic_init(pci_bus, nd, -1, "ne2k_pci");
}
- qemu_system_hot_add_init();
+ piix4_acpi_system_hot_add_init();
if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
fprintf(stderr, "qemu: too many IDE bus\n");
diff --git a/hw/pc.h b/hw/pc.h
index 0afffa2..9fbae20 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -108,11 +108,14 @@ extern int acpi_enabled;
extern char *acpi_tables;
extern size_t acpi_tables_len;
+void acpi_bios_init(void);
+int acpi_table_add(const char *table_desc);
+
+/* acpi_piix.c */
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq);
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
-void acpi_bios_init(void);
-int acpi_table_add(const char *table_desc);
+void piix4_acpi_system_hot_add_init(void);
/* hpet.c */
extern int no_hpet;
diff --git a/sysemu.h b/sysemu.h
index fe24415..403b35e 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -194,7 +194,8 @@ extern int drive_add(const char *file, const char *fmt, ...);
extern int drive_init(struct drive_opt *arg, int snapshot, void *machine);
/* acpi */
-void qemu_system_hot_add_init(void);
+typedef void (*qemu_system_device_hot_add_t)(int pcibus, int slot, int state);
+void qemu_system_device_hot_add_register(qemu_system_device_hot_add_t callback);
void qemu_system_device_hot_add(int pcibus, int slot, int state);
/* device-hotplug */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 02/18] acpi.c: split out pc smbus routines from acpi.c into pc_smbus.c
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 01/18] acpi.c: make qemu_system_device_hot_add piix independent Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 03/18] acpi.c: split out apm register emulation Isaku Yamahata
` (16 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
Split out pc smbus routines from acpi.c into pc_smbus.c and
use it.
The split out smbus emulation will be used later.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
Makefile.target | 2 +
hw/acpi.c | 164 +++------------------------------------------------
hw/pc_smbus.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/pc_smbus.h | 43 +++++++++++++
4 files changed, 232 insertions(+), 156 deletions(-)
create mode 100644 hw/pc_smbus.c
create mode 100644 hw/pc_smbus.h
diff --git a/Makefile.target b/Makefile.target
index 0159bf7..c1ebb61 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -573,6 +573,7 @@ ifeq ($(TARGET_BASE_ARCH), i386)
OBJS+= ide.o pckbd.o vga.o $(SOUND_HW) dma.o
OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
OBJS+= cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
+OBJS+= pc_smbus.o
OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
OBJS += device-hotplug.o pci-hotplug.o smbios.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
@@ -608,6 +609,7 @@ OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o
OBJS+= g364fb.o jazz_led.o dp8393x.o
OBJS+= ide.o gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
+OBJS+= pc_smbus.o
OBJS+= piix_pci.o parallel.o cirrus_vga.o pcspk.o $(SOUND_HW)
OBJS+= mipsnet.o
OBJS+= pflash_cfi01.o
diff --git a/hw/acpi.c b/hw/acpi.c
index 5928fe7..787b6d9 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -18,6 +18,7 @@
*/
#include "hw.h"
#include "pc.h"
+#include "pc_smbus.h"
#include "pci.h"
#include "qemu-timer.h"
#include "sysemu.h"
@@ -41,15 +42,9 @@ typedef struct PIIX4PMState {
uint8_t apms;
QEMUTimer *tmr_timer;
int64_t tmr_overflow_time;
- i2c_bus *smbus;
- uint8_t smb_stat;
- uint8_t smb_ctl;
- uint8_t smb_cmd;
- uint8_t smb_addr;
- uint8_t smb_data0;
- uint8_t smb_data1;
- uint8_t smb_data[32];
- uint8_t smb_index;
+
+ PCSMBus smb;
+
qemu_irq irq;
} PIIX4PMState;
@@ -67,14 +62,6 @@ typedef struct PIIX4PMState {
#define ACPI_ENABLE 0xf1
#define ACPI_DISABLE 0xf0
-#define SMBHSTSTS 0x00
-#define SMBHSTCNT 0x02
-#define SMBHSTCMD 0x03
-#define SMBHSTADD 0x04
-#define SMBHSTDAT0 0x05
-#define SMBHSTDAT1 0x06
-#define SMBBLKDAT 0x07
-
static PIIX4PMState *pm_state;
static uint32_t get_pmtmr(PIIX4PMState *s)
@@ -279,141 +266,6 @@ static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
#endif
}
-static void smb_transaction(PIIX4PMState *s)
-{
- uint8_t prot = (s->smb_ctl >> 2) & 0x07;
- uint8_t read = s->smb_addr & 0x01;
- uint8_t cmd = s->smb_cmd;
- uint8_t addr = s->smb_addr >> 1;
- i2c_bus *bus = s->smbus;
-
-#ifdef DEBUG
- printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
-#endif
- switch(prot) {
- case 0x0:
- smbus_quick_command(bus, addr, read);
- break;
- case 0x1:
- if (read) {
- s->smb_data0 = smbus_receive_byte(bus, addr);
- } else {
- smbus_send_byte(bus, addr, cmd);
- }
- break;
- case 0x2:
- if (read) {
- s->smb_data0 = smbus_read_byte(bus, addr, cmd);
- } else {
- smbus_write_byte(bus, addr, cmd, s->smb_data0);
- }
- break;
- case 0x3:
- if (read) {
- uint16_t val;
- val = smbus_read_word(bus, addr, cmd);
- s->smb_data0 = val;
- s->smb_data1 = val >> 8;
- } else {
- smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
- }
- break;
- case 0x5:
- if (read) {
- s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
- } else {
- smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
- }
- break;
- default:
- goto error;
- }
- return;
-
- error:
- s->smb_stat |= 0x04;
-}
-
-static void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- PIIX4PMState *s = opaque;
- addr &= 0x3f;
-#ifdef DEBUG
- printf("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
-#endif
- switch(addr) {
- case SMBHSTSTS:
- s->smb_stat = 0;
- s->smb_index = 0;
- break;
- case SMBHSTCNT:
- s->smb_ctl = val;
- if (val & 0x40)
- smb_transaction(s);
- break;
- case SMBHSTCMD:
- s->smb_cmd = val;
- break;
- case SMBHSTADD:
- s->smb_addr = val;
- break;
- case SMBHSTDAT0:
- s->smb_data0 = val;
- break;
- case SMBHSTDAT1:
- s->smb_data1 = val;
- break;
- case SMBBLKDAT:
- s->smb_data[s->smb_index++] = val;
- if (s->smb_index > 31)
- s->smb_index = 0;
- break;
- default:
- break;
- }
-}
-
-static uint32_t smb_ioport_readb(void *opaque, uint32_t addr)
-{
- PIIX4PMState *s = opaque;
- uint32_t val;
-
- addr &= 0x3f;
- switch(addr) {
- case SMBHSTSTS:
- val = s->smb_stat;
- break;
- case SMBHSTCNT:
- s->smb_index = 0;
- val = s->smb_ctl & 0x1f;
- break;
- case SMBHSTCMD:
- val = s->smb_cmd;
- break;
- case SMBHSTADD:
- val = s->smb_addr;
- break;
- case SMBHSTDAT0:
- val = s->smb_data0;
- break;
- case SMBHSTDAT1:
- val = s->smb_data1;
- break;
- case SMBBLKDAT:
- val = s->smb_data[s->smb_index++];
- if (s->smb_index > 31)
- s->smb_index = 0;
- break;
- default:
- val = 0;
- break;
- }
-#ifdef DEBUG
- printf("SMB readb port=0x%04x val=0x%02x\n", addr, val);
-#endif
- return val;
-}
-
static void pm_io_space_update(PIIX4PMState *s)
{
uint32_t pm_io_base;
@@ -541,18 +393,18 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
pci_conf[0x90] = smb_io_base | 1;
pci_conf[0x91] = smb_io_base >> 8;
pci_conf[0xd2] = 0x09;
- register_ioport_write(smb_io_base, 64, 1, smb_ioport_writeb, s);
- register_ioport_read(smb_io_base, 64, 1, smb_ioport_readb, s);
+ register_ioport_write(smb_io_base, 64, 1, smb_ioport_writeb, &s->smb);
+ register_ioport_read(smb_io_base, 64, 1, smb_ioport_readb, &s->smb);
s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s);
- s->smbus = i2c_init_bus(NULL, "i2c");
+ pc_smbus_init(&s->smb);
s->irq = sci_irq;
qemu_register_reset(piix4_reset, 0, s);
- return s->smbus;
+ return s->smb.smbus;
}
#if defined(TARGET_I386)
diff --git a/hw/pc_smbus.c b/hw/pc_smbus.c
new file mode 100644
index 0000000..0ccbd4e
--- /dev/null
+++ b/hw/pc_smbus.c
@@ -0,0 +1,179 @@
+/*
+ * PC SMBus implementation
+ * splitted from acpi.c
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+#include "hw.h"
+#include "pc.h"
+#include "pc_smbus.h"
+#include "pci.h"
+#include "qemu-timer.h"
+#include "sysemu.h"
+#include "i2c.h"
+#include "smbus.h"
+#include "kvm.h"
+#include "acpi.h"
+
+/* no save/load? */
+
+#define SMBHSTSTS 0x00
+#define SMBHSTCNT 0x02
+#define SMBHSTCMD 0x03
+#define SMBHSTADD 0x04
+#define SMBHSTDAT0 0x05
+#define SMBHSTDAT1 0x06
+#define SMBBLKDAT 0x07
+
+static void smb_transaction(PCSMBus *s)
+{
+ uint8_t prot = (s->smb_ctl >> 2) & 0x07;
+ uint8_t read = s->smb_addr & 0x01;
+ uint8_t cmd = s->smb_cmd;
+ uint8_t addr = s->smb_addr >> 1;
+ i2c_bus *bus = s->smbus;
+
+#ifdef DEBUG
+ printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
+#endif
+ switch(prot) {
+ case 0x0:
+ smbus_quick_command(bus, addr, read);
+ break;
+ case 0x1:
+ if (read) {
+ s->smb_data0 = smbus_receive_byte(bus, addr);
+ } else {
+ smbus_send_byte(bus, addr, cmd);
+ }
+ break;
+ case 0x2:
+ if (read) {
+ s->smb_data0 = smbus_read_byte(bus, addr, cmd);
+ } else {
+ smbus_write_byte(bus, addr, cmd, s->smb_data0);
+ }
+ break;
+ case 0x3:
+ if (read) {
+ uint16_t val;
+ val = smbus_read_word(bus, addr, cmd);
+ s->smb_data0 = val;
+ s->smb_data1 = val >> 8;
+ } else {
+ smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
+ }
+ break;
+ case 0x5:
+ if (read) {
+ s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
+ } else {
+ smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
+ }
+ break;
+ default:
+ goto error;
+ }
+ return;
+
+ error:
+ s->smb_stat |= 0x04;
+}
+
+void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ PCSMBus *s = opaque;
+ addr &= 0x3f;
+#ifdef DEBUG
+ printf("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
+#endif
+ switch(addr) {
+ case SMBHSTSTS:
+ s->smb_stat = 0;
+ s->smb_index = 0;
+ break;
+ case SMBHSTCNT:
+ s->smb_ctl = val;
+ if (val & 0x40)
+ smb_transaction(s);
+ break;
+ case SMBHSTCMD:
+ s->smb_cmd = val;
+ break;
+ case SMBHSTADD:
+ s->smb_addr = val;
+ break;
+ case SMBHSTDAT0:
+ s->smb_data0 = val;
+ break;
+ case SMBHSTDAT1:
+ s->smb_data1 = val;
+ break;
+ case SMBBLKDAT:
+ s->smb_data[s->smb_index++] = val;
+ if (s->smb_index > 31)
+ s->smb_index = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+uint32_t smb_ioport_readb(void *opaque, uint32_t addr)
+{
+ PCSMBus *s = opaque;
+ uint32_t val;
+
+ addr &= 0x3f;
+ switch(addr) {
+ case SMBHSTSTS:
+ val = s->smb_stat;
+ break;
+ case SMBHSTCNT:
+ s->smb_index = 0;
+ val = s->smb_ctl & 0x1f;
+ break;
+ case SMBHSTCMD:
+ val = s->smb_cmd;
+ break;
+ case SMBHSTADD:
+ val = s->smb_addr;
+ break;
+ case SMBHSTDAT0:
+ val = s->smb_data0;
+ break;
+ case SMBHSTDAT1:
+ val = s->smb_data1;
+ break;
+ case SMBBLKDAT:
+ val = s->smb_data[s->smb_index++];
+ if (s->smb_index > 31)
+ s->smb_index = 0;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+#ifdef DEBUG
+ printf("SMB readb port=0x%04x val=0x%02x\n", addr, val);
+#endif
+ return val;
+}
+
+void pc_smbus_init(PCSMBus *smb)
+{
+ smb->smbus = i2c_init_bus(NULL, "i2c");
+}
diff --git a/hw/pc_smbus.h b/hw/pc_smbus.h
new file mode 100644
index 0000000..5e5a66f
--- /dev/null
+++ b/hw/pc_smbus.h
@@ -0,0 +1,43 @@
+/*
+ * QEMU PC SMBUS controller Emulation
+ *
+ * Copyright (c) 2009 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+#ifndef PC_SMBUS_H
+#define PC_SMBUS_H
+
+typedef struct PCSMBus {
+ i2c_bus *smbus;
+
+ uint8_t smb_stat;
+ uint8_t smb_ctl;
+ uint8_t smb_cmd;
+ uint8_t smb_addr;
+ uint8_t smb_data0;
+ uint8_t smb_data1;
+ uint8_t smb_data[32];
+ uint8_t smb_index;
+} PCSMBus;
+
+void pc_smbus_init(PCSMBus *smb);
+void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val);
+uint32_t smb_ioport_readb(void *opaque, uint32_t addr);
+
+#endif /* !PC_SMBUS_H */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 03/18] acpi.c: split out apm register emulation.
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 01/18] acpi.c: make qemu_system_device_hot_add piix independent Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 02/18] acpi.c: split out pc smbus routines from acpi.c into pc_smbus.c Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 04/18] acpi.c: make qemu_system_powerdown() piix independent Isaku Yamahata
` (15 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
Split out apm register emulation for acpi.c into pc_apm.c.
The apm emulation will be used later.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
Makefile.target | 4 +-
hw/acpi.c | 60 ++++++++++-------------------------
hw/pc_apm.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/pc_apm.h | 39 +++++++++++++++++++++++
4 files changed, 150 insertions(+), 45 deletions(-)
create mode 100644 hw/pc_apm.c
create mode 100644 hw/pc_apm.h
diff --git a/Makefile.target b/Makefile.target
index c1ebb61..1ab708b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -573,7 +573,7 @@ ifeq ($(TARGET_BASE_ARCH), i386)
OBJS+= ide.o pckbd.o vga.o $(SOUND_HW) dma.o
OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
OBJS+= cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
-OBJS+= pc_smbus.o
+OBJS+= pc_smbus.o pc_apm.o
OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
OBJS += device-hotplug.o pci-hotplug.o smbios.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
@@ -609,7 +609,7 @@ OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o
OBJS+= g364fb.o jazz_led.o dp8393x.o
OBJS+= ide.o gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
-OBJS+= pc_smbus.o
+OBJS+= pc_smbus.o pc_apm.o
OBJS+= piix_pci.o parallel.o cirrus_vga.o pcspk.o $(SOUND_HW)
OBJS+= mipsnet.o
OBJS+= pflash_cfi01.o
diff --git a/hw/acpi.c b/hw/acpi.c
index 787b6d9..75544e8 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -18,6 +18,7 @@
*/
#include "hw.h"
#include "pc.h"
+#include "pc_apm.h"
#include "pc_smbus.h"
#include "pci.h"
#include "qemu-timer.h"
@@ -38,8 +39,9 @@ typedef struct PIIX4PMState {
uint16_t pmsts;
uint16_t pmen;
uint16_t pmcntrl;
- uint8_t apmc;
- uint8_t apms;
+
+ APMState apm;
+
QEMUTimer *tmr_timer;
int64_t tmr_overflow_time;
@@ -217,46 +219,20 @@ static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
return val;
}
-static void pm_smi_writeb(void *opaque, uint32_t addr, uint32_t val)
+static void apm_ctrl_changed(uint32_t val, void *arg)
{
- PIIX4PMState *s = opaque;
- addr &= 1;
-#ifdef DEBUG
- printf("pm_smi_writeb addr=0x%x val=0x%02x\n", addr, val);
-#endif
- if (addr == 0) {
- s->apmc = val;
-
- /* ACPI specs 3.0, 4.7.2.5 */
- if (val == ACPI_ENABLE) {
- s->pmcntrl |= SCI_EN;
- } else if (val == ACPI_DISABLE) {
- s->pmcntrl &= ~SCI_EN;
- }
+ PIIX4PMState *s = arg;
- if (s->dev.config[0x5b] & (1 << 1)) {
- cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
- }
- } else {
- s->apms = val;
+ /* ACPI specs 3.0, 4.7.2.5 */
+ if (val == ACPI_ENABLE) {
+ s->pmcntrl |= SCI_EN;
+ } else if (val == ACPI_DISABLE) {
+ s->pmcntrl &= ~SCI_EN;
}
-}
-static uint32_t pm_smi_readb(void *opaque, uint32_t addr)
-{
- PIIX4PMState *s = opaque;
- uint32_t val;
-
- addr &= 1;
- if (addr == 0) {
- val = s->apmc;
- } else {
- val = s->apms;
+ if (s->dev.config[0x5b] & (1 << 1)) {
+ cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
}
-#ifdef DEBUG
- printf("pm_smi_readb addr=0x%x val=0x%02x\n", addr, val);
-#endif
- return val;
}
static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
@@ -302,8 +278,7 @@ static void pm_save(QEMUFile* f,void *opaque)
qemu_put_be16s(f, &s->pmsts);
qemu_put_be16s(f, &s->pmen);
qemu_put_be16s(f, &s->pmcntrl);
- qemu_put_8s(f, &s->apmc);
- qemu_put_8s(f, &s->apms);
+ apm_save(f, &s->apm);
qemu_put_timer(f, s->tmr_timer);
qemu_put_be64(f, s->tmr_overflow_time);
}
@@ -323,8 +298,7 @@ static int pm_load(QEMUFile* f,void* opaque,int version_id)
qemu_get_be16s(f, &s->pmsts);
qemu_get_be16s(f, &s->pmen);
qemu_get_be16s(f, &s->pmcntrl);
- qemu_get_8s(f, &s->apmc);
- qemu_get_8s(f, &s->apms);
+ apm_load(f, &s->apm);
qemu_get_timer(f, s->tmr_timer);
s->tmr_overflow_time=qemu_get_be64(f);
@@ -372,8 +346,8 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
pci_conf[0x40] = 0x01; /* PM io base read only bit */
- register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s);
- register_ioport_read(0xb2, 2, 1, pm_smi_readb, s);
+ /* APM */
+ apm_init(&s->apm, apm_ctrl_changed, s);
register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
diff --git a/hw/pc_apm.c b/hw/pc_apm.c
new file mode 100644
index 0000000..dac43fb
--- /dev/null
+++ b/hw/pc_apm.c
@@ -0,0 +1,92 @@
+/*
+ * QEMU PC APM controller Emulation
+ *
+ * Copyright (c) 2009 Isaku Yamahata <yamahata at valinux co jp>
+ * VA Linux Systems Japan K.K.
+ *
+ * This is split out from acpi.c
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+#include "pc_apm.h"
+#include "hw.h"
+#include "isa.h"
+
+//#define DEBUG
+
+/* fixed I/O location */
+#define APM_CNT_IOPORT 0xb2
+#define APM_STS_IOPORT 0xb3
+
+static void *apm_arg;
+static apm_ctrl_changed_t apm_callback;
+
+static void apm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ APMState *apm = opaque;
+ addr &= 1;
+#ifdef DEBUG
+ printf("apm_ioport_writeb addr=0x%x val=0x%02x\n", addr, val);
+#endif
+ if (addr == 0) {
+ apm->apmc = val;
+
+ if (apm_callback) {
+ apm_callback(val, apm_arg);
+ }
+ } else {
+ apm->apms = val;
+ }
+}
+
+static uint32_t apm_ioport_readb(void *opaque, uint32_t addr)
+{
+ APMState *apm = opaque;
+ uint32_t val;
+
+ addr &= 1;
+ if (addr == 0) {
+ val = apm->apmc;
+ } else {
+ val = apm->apms;
+ }
+#ifdef DEBUG
+ printf("apm_ioport_readb addr=0x%x val=0x%02x\n", addr, val);
+#endif
+ return val;
+}
+
+void apm_save(QEMUFile *f, APMState *apm)
+{
+ qemu_put_8s(f, &apm->apmc);
+ qemu_put_8s(f, &apm->apms);
+}
+
+void apm_load(QEMUFile *f, APMState *apm)
+{
+ qemu_get_8s(f, &apm->apmc);
+ qemu_get_8s(f, &apm->apms);
+}
+
+void apm_init(APMState *apm, apm_ctrl_changed_t callback, void *arg)
+{
+ apm_callback = callback;
+ apm_arg = arg;
+
+ /* ioport 0xb2, 0xb3 */
+ register_ioport_write(APM_CNT_IOPORT, 2, 1, apm_ioport_writeb, apm);
+ register_ioport_read(APM_CNT_IOPORT, 2, 1, apm_ioport_readb, apm);
+}
diff --git a/hw/pc_apm.h b/hw/pc_apm.h
new file mode 100644
index 0000000..9f4120c
--- /dev/null
+++ b/hw/pc_apm.h
@@ -0,0 +1,39 @@
+/*
+ * QEMU PC APM controller 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+#ifndef PC_APM_H
+#define PC_APM_H
+
+#include <stdint.h>
+#include "qemu-common.h"
+
+typedef struct APMState {
+ uint8_t apmc;
+ uint8_t apms;
+} APMState;
+
+typedef void (*apm_ctrl_changed_t)(uint32_t val, void *arg);
+void apm_init(APMState *s, apm_ctrl_changed_t callback, void *arg);
+
+void apm_save(QEMUFile *f, APMState *apm);
+void apm_load(QEMUFile *f, APMState *apm);
+
+#endif /* PC_APM_H */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 04/18] acpi.c: make qemu_system_powerdown() piix independent.
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (2 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 03/18] acpi.c: split out apm register emulation Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 05/18] acpi: add acpi constants from linux header files and use them Isaku Yamahata
` (14 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
Make qemu_system_powerdown() piix independent by
registering callback function.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/acpi.c | 29 +++++++++++++++++++++++++----
hw/acpi.h | 29 +++++++++++++++++++++++++++++
2 files changed, 54 insertions(+), 4 deletions(-)
create mode 100644 hw/acpi.h
diff --git a/hw/acpi.c b/hw/acpi.c
index 75544e8..66cc4b2 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -323,6 +323,18 @@ static void piix4_reset(void *opaque)
}
}
+#if defined(TARGET_I386)
+static void piix4_pm_powerdown(void *arg)
+{
+ PIIX4PMState *pm_state = (PIIX4PMState*) arg;
+
+ if (pm_state->pmen & PWRBTN_EN) {
+ pm_state->pmsts |= PWRBTN_EN;
+ pm_update_sci(pm_state);
+ }
+}
+#endif
+
i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq)
{
@@ -377,18 +389,27 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
pc_smbus_init(&s->smb);
s->irq = sci_irq;
qemu_register_reset(piix4_reset, 0, s);
+ qemu_system_powerdown_register(piix4_pm_powerdown, pm_state);
return s->smb.smbus;
}
#if defined(TARGET_I386)
+static qemu_powerdown_t qemu_powerdown_callback;
+static void *qemu_powerdown_arg;
+
+void qemu_system_powerdown_register(qemu_powerdown_t callback, void *arg)
+{
+ qemu_powerdown_callback = callback;
+ qemu_powerdown_arg = arg;
+}
+
void qemu_system_powerdown(void)
{
- if (!pm_state) {
+ if (!qemu_powerdown_callback) {
qemu_system_shutdown_request();
- } else if (pm_state->pmen & PWRBTN_EN) {
- pm_state->pmsts |= PWRBTN_EN;
- pm_update_sci(pm_state);
+ } else {
+ qemu_powerdown_callback(qemu_powerdown_arg);
}
}
#endif
diff --git a/hw/acpi.h b/hw/acpi.h
new file mode 100644
index 0000000..884512c
--- /dev/null
+++ b/hw/acpi.h
@@ -0,0 +1,29 @@
+#ifndef QEMU_HW_ACPI_H
+#define QEMU_HW_ACPI_H
+/*
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+#if defined(TARGET_I386)
+typedef void (*qemu_powerdown_t)(void *arg);
+void qemu_system_powerdown_register(qemu_powerdown_t callback, void *arg);
+#else
+#define qemu_system_powerdown_register(callback, arg) do { } while (0)
+#endif
+
+#endif /* !QEMU_HW_ACPI_H */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 05/18] acpi: add acpi constants from linux header files and use them.
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (3 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 04/18] acpi.c: make qemu_system_powerdown() piix independent Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 06/18] acpi.c: split acpi.c into the common part and the piix4 part Isaku Yamahata
` (13 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
add acpi constants from linux header files and
replace the old constants with them.
The acpi constants will be used by other file.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/acpi.c | 55 ++++++++++++++++++++++++-------------------------------
hw/acpi.h | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 80 insertions(+), 31 deletions(-)
diff --git a/hw/acpi.c b/hw/acpi.c
index 66cc4b2..4d0690e 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -29,9 +29,6 @@
//#define DEBUG
-/* i82731AB (PIIX4) compatible power management function */
-#define PM_FREQ 3579545
-
#define ACPI_DBG_IO_ADDR 0xb044
typedef struct PIIX4PMState {
@@ -50,17 +47,6 @@ typedef struct PIIX4PMState {
qemu_irq irq;
} PIIX4PMState;
-#define RSM_STS (1 << 15)
-#define PWRBTN_STS (1 << 8)
-#define RTC_EN (1 << 10)
-#define PWRBTN_EN (1 << 8)
-#define GBL_EN (1 << 5)
-#define TMROF_EN (1 << 0)
-
-#define SCI_EN (1 << 0)
-
-#define SUS_EN (1 << 13)
-
#define ACPI_ENABLE 0xf1
#define ACPI_DISABLE 0xf0
@@ -69,7 +55,7 @@ static PIIX4PMState *pm_state;
static uint32_t get_pmtmr(PIIX4PMState *s)
{
uint32_t d;
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
+ d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, ticks_per_sec);
return d & 0xffffff;
}
@@ -78,9 +64,9 @@ static int get_pmsts(PIIX4PMState *s)
int64_t d;
int pmsts;
pmsts = s->pmsts;
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
+ d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, ticks_per_sec);
if (d >= s->tmr_overflow_time)
- s->pmsts |= TMROF_EN;
+ s->pmsts |= ACPI_BITMASK_TIMER_STATUS;
return s->pmsts;
}
@@ -91,11 +77,16 @@ static void pm_update_sci(PIIX4PMState *s)
pmsts = get_pmsts(s);
sci_level = (((pmsts & s->pmen) &
- (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
+ (ACPI_BITMASK_RT_CLOCK_ENABLE |
+ ACPI_BITMASK_POWER_BUTTON_ENABLE |
+ ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
+ ACPI_BITMASK_TIMER_ENABLE)) != 0);
qemu_set_irq(s->irq, sci_level);
/* schedule a timer interruption if needed */
- if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
- expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
+ if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) &&
+ !(pmsts & ACPI_BITMASK_TIMER_STATUS)) {
+ expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec,
+ PM_TIMER_FREQUENCY);
qemu_mod_timer(s->tmr_timer, expire_time);
} else {
qemu_del_timer(s->tmr_timer);
@@ -118,9 +109,10 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
int64_t d;
int pmsts;
pmsts = get_pmsts(s);
- if (pmsts & val & TMROF_EN) {
+ if (pmsts & val & ACPI_BITMASK_TIMER_STATUS) {
/* if TMRSTS is reset, then compute the new overflow time */
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
+ d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY,
+ ticks_per_sec);
s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
}
s->pmsts &= ~val;
@@ -134,8 +126,8 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
case 0x04:
{
int sus_typ;
- s->pmcntrl = val & ~(SUS_EN);
- if (val & SUS_EN) {
+ s->pmcntrl = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
+ if (val & ACPI_BITMASK_SLEEP_ENABLE) {
/* change suspend type */
sus_typ = (val >> 10) & 7;
switch(sus_typ) {
@@ -143,9 +135,10 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
qemu_system_shutdown_request();
break;
case 1:
- /* RSM_STS should be set on resume. Pretend that resume
- was caused by power button */
- s->pmsts |= (RSM_STS | PWRBTN_STS);
+ /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
+ Pretend that resume was caused by power button */
+ s->pmsts |= (ACPI_BITMASK_WAKE_STATUS |
+ ACPI_BITMASK_POWER_BUTTON_STATUS);
qemu_system_reset_request();
#if defined(TARGET_I386)
cmos_set_s3_resume();
@@ -225,9 +218,9 @@ static void apm_ctrl_changed(uint32_t val, void *arg)
/* ACPI specs 3.0, 4.7.2.5 */
if (val == ACPI_ENABLE) {
- s->pmcntrl |= SCI_EN;
+ s->pmcntrl |= ACPI_BITMASK_SCI_ENABLE;
} else if (val == ACPI_DISABLE) {
- s->pmcntrl &= ~SCI_EN;
+ s->pmcntrl &= ~ACPI_BITMASK_SCI_ENABLE;
}
if (s->dev.config[0x5b] & (1 << 1)) {
@@ -328,8 +321,8 @@ static void piix4_pm_powerdown(void *arg)
{
PIIX4PMState *pm_state = (PIIX4PMState*) arg;
- if (pm_state->pmen & PWRBTN_EN) {
- pm_state->pmsts |= PWRBTN_EN;
+ if (pm_state->pmen & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
+ pm_state->pmsts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
pm_update_sci(pm_state);
}
}
diff --git a/hw/acpi.h b/hw/acpi.h
index 884512c..d686b50 100644
--- a/hw/acpi.h
+++ b/hw/acpi.h
@@ -26,4 +26,60 @@ void qemu_system_powerdown_register(qemu_powerdown_t callback, void *arg);
#define qemu_system_powerdown_register(callback, arg) do { } while (0)
#endif
+/* from linux include/acpi/actype.h */
+/* Default ACPI register widths */
+
+#define ACPI_GPE_REGISTER_WIDTH 8
+#define ACPI_PM1_REGISTER_WIDTH 16
+#define ACPI_PM2_REGISTER_WIDTH 8
+#define ACPI_PM_TIMER_WIDTH 32
+
+/* PM Timer ticks per second (HZ) */
+#define PM_TIMER_FREQUENCY 3579545
+
+
+/* ACPI fixed hardware registers */
+
+/* from linux/drivers/acpi/acpica/aclocal.h */
+/* Masks used to access the bit_registers */
+
+/* PM1x_STS */
+#define ACPI_BITMASK_TIMER_STATUS 0x0001
+#define ACPI_BITMASK_BUS_MASTER_STATUS 0x0010
+#define ACPI_BITMASK_GLOBAL_LOCK_STATUS 0x0020
+#define ACPI_BITMASK_POWER_BUTTON_STATUS 0x0100
+#define ACPI_BITMASK_SLEEP_BUTTON_STATUS 0x0200
+#define ACPI_BITMASK_RT_CLOCK_STATUS 0x0400
+#define ACPI_BITMASK_PCIEXP_WAKE_STATUS 0x4000 /* ACPI 3.0 */
+#define ACPI_BITMASK_WAKE_STATUS 0x8000
+
+#define ACPI_BITMASK_ALL_FIXED_STATUS (\
+ ACPI_BITMASK_TIMER_STATUS | \
+ ACPI_BITMASK_BUS_MASTER_STATUS | \
+ ACPI_BITMASK_GLOBAL_LOCK_STATUS | \
+ ACPI_BITMASK_POWER_BUTTON_STATUS | \
+ ACPI_BITMASK_SLEEP_BUTTON_STATUS | \
+ ACPI_BITMASK_RT_CLOCK_STATUS | \
+ ACPI_BITMASK_WAKE_STATUS)
+
+/* PM1x_EN */
+#define ACPI_BITMASK_TIMER_ENABLE 0x0001
+#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE 0x0020
+#define ACPI_BITMASK_POWER_BUTTON_ENABLE 0x0100
+#define ACPI_BITMASK_SLEEP_BUTTON_ENABLE 0x0200
+#define ACPI_BITMASK_RT_CLOCK_ENABLE 0x0400
+#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE 0x4000 /* ACPI 3.0 */
+
+/* PM1x_CNT */
+#define ACPI_BITMASK_SCI_ENABLE 0x0001
+#define ACPI_BITMASK_BUS_MASTER_RLD 0x0002
+#define ACPI_BITMASK_GLOBAL_LOCK_RELEASE 0x0004
+#define ACPI_BITMASK_SLEEP_TYPE 0x1C00
+#define ACPI_BITMASK_SLEEP_ENABLE 0x2000
+
+/* PM2_CNT */
+#define ACPI_BITMASK_ARB_DISABLE 0x0001
+
+/* PM_TMR */
+
#endif /* !QEMU_HW_ACPI_H */
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 06/18] acpi.c: split acpi.c into the common part and the piix4 part.
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (4 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 05/18] acpi: add acpi constants from linux header files and use them Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 07/18] pc.c: Make smm enable/disable function i440fx independent Isaku Yamahata
` (12 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
Split acpi.c into the common part and the piix4 specific part.
The common part will be used later.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
Makefile.target | 4 +-
hw/acpi.c | 556 +------------------------------------------
hw/{acpi.c => acpi_piix4.c} | 202 +----------------
3 files changed, 5 insertions(+), 757 deletions(-)
copy hw/{acpi.c => acpi_piix4.c} (73%)
diff --git a/Makefile.target b/Makefile.target
index 1ab708b..2cf55b9 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -573,7 +573,7 @@ ifeq ($(TARGET_BASE_ARCH), i386)
OBJS+= ide.o pckbd.o vga.o $(SOUND_HW) dma.o
OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
OBJS+= cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
-OBJS+= pc_smbus.o pc_apm.o
+OBJS+= acpi_piix4.o pc_smbus.o pc_apm.o
OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
OBJS += device-hotplug.o pci-hotplug.o smbios.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
@@ -609,7 +609,7 @@ OBJS+= mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o rc4030.o
OBJS+= g364fb.o jazz_led.o dp8393x.o
OBJS+= ide.o gt64xxx.o pckbd.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
-OBJS+= pc_smbus.o pc_apm.o
+OBJS+= acpi_piix4.o pc_smbus.o pc_apm.o
OBJS+= piix_pci.o parallel.o cirrus_vga.o pcspk.o $(SOUND_HW)
OBJS+= mipsnet.o
OBJS+= pflash_cfi01.o
diff --git a/hw/acpi.c b/hw/acpi.c
index 4d0690e..19f5df0 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -18,374 +18,9 @@
*/
#include "hw.h"
#include "pc.h"
-#include "pc_apm.h"
-#include "pc_smbus.h"
#include "pci.h"
-#include "qemu-timer.h"
#include "sysemu.h"
-#include "i2c.h"
-#include "smbus.h"
-#include "kvm.h"
-
-//#define DEBUG
-
-#define ACPI_DBG_IO_ADDR 0xb044
-
-typedef struct PIIX4PMState {
- PCIDevice dev;
- uint16_t pmsts;
- uint16_t pmen;
- uint16_t pmcntrl;
-
- APMState apm;
-
- QEMUTimer *tmr_timer;
- int64_t tmr_overflow_time;
-
- PCSMBus smb;
-
- qemu_irq irq;
-} PIIX4PMState;
-
-#define ACPI_ENABLE 0xf1
-#define ACPI_DISABLE 0xf0
-
-static PIIX4PMState *pm_state;
-
-static uint32_t get_pmtmr(PIIX4PMState *s)
-{
- uint32_t d;
- d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, ticks_per_sec);
- return d & 0xffffff;
-}
-
-static int get_pmsts(PIIX4PMState *s)
-{
- int64_t d;
- int pmsts;
- pmsts = s->pmsts;
- d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, ticks_per_sec);
- if (d >= s->tmr_overflow_time)
- s->pmsts |= ACPI_BITMASK_TIMER_STATUS;
- return s->pmsts;
-}
-
-static void pm_update_sci(PIIX4PMState *s)
-{
- int sci_level, pmsts;
- int64_t expire_time;
-
- pmsts = get_pmsts(s);
- sci_level = (((pmsts & s->pmen) &
- (ACPI_BITMASK_RT_CLOCK_ENABLE |
- ACPI_BITMASK_POWER_BUTTON_ENABLE |
- ACPI_BITMASK_GLOBAL_LOCK_ENABLE |
- ACPI_BITMASK_TIMER_ENABLE)) != 0);
- qemu_set_irq(s->irq, sci_level);
- /* schedule a timer interruption if needed */
- if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) &&
- !(pmsts & ACPI_BITMASK_TIMER_STATUS)) {
- expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec,
- PM_TIMER_FREQUENCY);
- qemu_mod_timer(s->tmr_timer, expire_time);
- } else {
- qemu_del_timer(s->tmr_timer);
- }
-}
-
-static void pm_tmr_timer(void *opaque)
-{
- PIIX4PMState *s = opaque;
- pm_update_sci(s);
-}
-
-static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- PIIX4PMState *s = opaque;
- addr &= 0x3f;
- switch(addr) {
- case 0x00:
- {
- int64_t d;
- int pmsts;
- pmsts = get_pmsts(s);
- if (pmsts & val & ACPI_BITMASK_TIMER_STATUS) {
- /* if TMRSTS is reset, then compute the new overflow time */
- d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY,
- ticks_per_sec);
- s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
- }
- s->pmsts &= ~val;
- pm_update_sci(s);
- }
- break;
- case 0x02:
- s->pmen = val;
- pm_update_sci(s);
- break;
- case 0x04:
- {
- int sus_typ;
- s->pmcntrl = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
- if (val & ACPI_BITMASK_SLEEP_ENABLE) {
- /* change suspend type */
- sus_typ = (val >> 10) & 7;
- switch(sus_typ) {
- case 0: /* soft power off */
- qemu_system_shutdown_request();
- break;
- case 1:
- /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
- Pretend that resume was caused by power button */
- s->pmsts |= (ACPI_BITMASK_WAKE_STATUS |
- ACPI_BITMASK_POWER_BUTTON_STATUS);
- qemu_system_reset_request();
-#if defined(TARGET_I386)
- cmos_set_s3_resume();
-#endif
- default:
- break;
- }
- }
- }
- break;
- default:
- break;
- }
-#ifdef DEBUG
- printf("PM writew port=0x%04x val=0x%04x\n", addr, val);
-#endif
-}
-
-static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
-{
- PIIX4PMState *s = opaque;
- uint32_t val;
-
- addr &= 0x3f;
- switch(addr) {
- case 0x00:
- val = get_pmsts(s);
- break;
- case 0x02:
- val = s->pmen;
- break;
- case 0x04:
- val = s->pmcntrl;
- break;
- default:
- val = 0;
- break;
- }
-#ifdef DEBUG
- printf("PM readw port=0x%04x val=0x%04x\n", addr, val);
-#endif
- return val;
-}
-
-static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- // PIIX4PMState *s = opaque;
- addr &= 0x3f;
-#ifdef DEBUG
- printf("PM writel port=0x%04x val=0x%08x\n", addr, val);
-#endif
-}
-
-static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
-{
- PIIX4PMState *s = opaque;
- uint32_t val;
-
- addr &= 0x3f;
- switch(addr) {
- case 0x08:
- val = get_pmtmr(s);
- break;
- default:
- val = 0;
- break;
- }
-#ifdef DEBUG
- printf("PM readl port=0x%04x val=0x%08x\n", addr, val);
-#endif
- return val;
-}
-
-static void apm_ctrl_changed(uint32_t val, void *arg)
-{
- PIIX4PMState *s = arg;
-
- /* ACPI specs 3.0, 4.7.2.5 */
- if (val == ACPI_ENABLE) {
- s->pmcntrl |= ACPI_BITMASK_SCI_ENABLE;
- } else if (val == ACPI_DISABLE) {
- s->pmcntrl &= ~ACPI_BITMASK_SCI_ENABLE;
- }
-
- if (s->dev.config[0x5b] & (1 << 1)) {
- cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
- }
-}
-
-static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
-{
-#if defined(DEBUG)
- printf("ACPI: DBG: 0x%08x\n", val);
-#endif
-}
-
-static void pm_io_space_update(PIIX4PMState *s)
-{
- uint32_t pm_io_base;
-
- if (s->dev.config[0x80] & 1) {
- pm_io_base = le32_to_cpu(*(uint32_t *)(s->dev.config + 0x40));
- pm_io_base &= 0xffc0;
-
- /* XXX: need to improve memory and ioport allocation */
-#if defined(DEBUG)
- printf("PM: mapping to 0x%x\n", pm_io_base);
-#endif
- register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
- register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
- register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
- register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
- }
-}
-
-static void pm_write_config(PCIDevice *d,
- uint32_t address, uint32_t val, int len)
-{
- pci_default_write_config(d, address, val, len);
- if (address == 0x80)
- pm_io_space_update((PIIX4PMState *)d);
-}
-
-static void pm_save(QEMUFile* f,void *opaque)
-{
- PIIX4PMState *s = opaque;
-
- pci_device_save(&s->dev, f);
-
- qemu_put_be16s(f, &s->pmsts);
- qemu_put_be16s(f, &s->pmen);
- qemu_put_be16s(f, &s->pmcntrl);
- apm_save(f, &s->apm);
- qemu_put_timer(f, s->tmr_timer);
- qemu_put_be64(f, s->tmr_overflow_time);
-}
-
-static int pm_load(QEMUFile* f,void* opaque,int version_id)
-{
- PIIX4PMState *s = opaque;
- int ret;
-
- if (version_id > 1)
- return -EINVAL;
-
- ret = pci_device_load(&s->dev, f);
- if (ret < 0)
- return ret;
-
- qemu_get_be16s(f, &s->pmsts);
- qemu_get_be16s(f, &s->pmen);
- qemu_get_be16s(f, &s->pmcntrl);
- apm_load(f, &s->apm);
- qemu_get_timer(f, s->tmr_timer);
- s->tmr_overflow_time=qemu_get_be64(f);
-
- pm_io_space_update(s);
-
- return 0;
-}
-
-static void piix4_reset(void *opaque)
-{
- PIIX4PMState *s = opaque;
- uint8_t *pci_conf = s->dev.config;
-
- pci_conf[0x58] = 0;
- pci_conf[0x59] = 0;
- pci_conf[0x5a] = 0;
- pci_conf[0x5b] = 0;
-
- if (kvm_enabled()) {
- /* Mark SMM as already inited (until KVM supports SMM). */
- pci_conf[0x5B] = 0x02;
- }
-}
-
-#if defined(TARGET_I386)
-static void piix4_pm_powerdown(void *arg)
-{
- PIIX4PMState *pm_state = (PIIX4PMState*) arg;
-
- if (pm_state->pmen & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
- pm_state->pmsts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
- pm_update_sci(pm_state);
- }
-}
-#endif
-
-i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
- qemu_irq sci_irq)
-{
- PIIX4PMState *s;
- uint8_t *pci_conf;
-
- s = (PIIX4PMState *)pci_register_device(bus,
- "PM", sizeof(PIIX4PMState),
- devfn, NULL, pm_write_config);
- pm_state = s;
- pci_conf = s->dev.config;
- pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
- pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_82371AB_3);
- pci_conf[0x06] = 0x80;
- pci_conf[0x07] = 0x02;
- pci_conf[0x08] = 0x03; // revision number
- pci_conf[0x09] = 0x00;
- pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_OTHER);
- pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
- pci_conf[0x3d] = 0x01; // interrupt pin 1
-
- pci_conf[0x40] = 0x01; /* PM io base read only bit */
-
- /* APM */
- apm_init(&s->apm, apm_ctrl_changed, s);
-
- register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
-
- if (kvm_enabled()) {
- /* Mark SMM as already inited to prevent SMM from running. KVM does not
- * support SMM mode. */
- pci_conf[0x5B] = 0x02;
- }
-
- /* XXX: which specification is used ? The i82731AB has different
- mappings */
- pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
- pci_conf[0x63] = 0x60;
- pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
- (serial_hds[1] != NULL ? 0x90 : 0);
-
- pci_conf[0x90] = smb_io_base | 1;
- pci_conf[0x91] = smb_io_base >> 8;
- pci_conf[0xd2] = 0x09;
- register_ioport_write(smb_io_base, 64, 1, smb_ioport_writeb, &s->smb);
- register_ioport_read(smb_io_base, 64, 1, smb_ioport_readb, &s->smb);
-
- s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
-
- register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s);
-
- pc_smbus_init(&s->smb);
- s->irq = sci_irq;
- qemu_register_reset(piix4_reset, 0, s);
- qemu_system_powerdown_register(piix4_pm_powerdown, pm_state);
-
- return s->smb.smbus;
-}
+#include "acpi.h"
#if defined(TARGET_I386)
static qemu_powerdown_t qemu_powerdown_callback;
@@ -407,195 +42,6 @@ void qemu_system_powerdown(void)
}
#endif
-#define GPE_BASE 0xafe0
-#define PCI_BASE 0xae00
-#define PCI_EJ_BASE 0xae08
-
-struct gpe_regs {
- uint16_t sts; /* status */
- uint16_t en; /* enabled */
-};
-
-struct pci_status {
- uint32_t up;
- uint32_t down;
-};
-
-static struct gpe_regs gpe;
-static struct pci_status pci0_status;
-
-static uint32_t gpe_read_val(uint16_t val, uint32_t addr)
-{
- if (addr & 1)
- return (val >> 8) & 0xff;
- return val & 0xff;
-}
-
-static uint32_t gpe_readb(void *opaque, uint32_t addr)
-{
- uint32_t val = 0;
- struct gpe_regs *g = opaque;
- switch (addr) {
- case GPE_BASE:
- case GPE_BASE + 1:
- val = gpe_read_val(g->sts, addr);
- break;
- case GPE_BASE + 2:
- case GPE_BASE + 3:
- val = gpe_read_val(g->en, addr);
- break;
- default:
- break;
- }
-
-#if defined(DEBUG)
- printf("gpe read %x == %x\n", addr, val);
-#endif
- return val;
-}
-
-static void gpe_write_val(uint16_t *cur, int addr, uint32_t val)
-{
- if (addr & 1)
- *cur = (*cur & 0xff) | (val << 8);
- else
- *cur = (*cur & 0xff00) | (val & 0xff);
-}
-
-static void gpe_reset_val(uint16_t *cur, int addr, uint32_t val)
-{
- uint16_t x1, x0 = val & 0xff;
- int shift = (addr & 1) ? 8 : 0;
-
- x1 = (*cur >> shift) & 0xff;
-
- x1 = x1 & ~x0;
-
- *cur = (*cur & (0xff << (8 - shift))) | (x1 << shift);
-}
-
-static void gpe_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- struct gpe_regs *g = opaque;
- switch (addr) {
- case GPE_BASE:
- case GPE_BASE + 1:
- gpe_reset_val(&g->sts, addr, val);
- break;
- case GPE_BASE + 2:
- case GPE_BASE + 3:
- gpe_write_val(&g->en, addr, val);
- break;
- default:
- break;
- }
-
-#if defined(DEBUG)
- printf("gpe write %x <== %d\n", addr, val);
-#endif
-}
-
-static uint32_t pcihotplug_read(void *opaque, uint32_t addr)
-{
- uint32_t val = 0;
- struct pci_status *g = opaque;
- switch (addr) {
- case PCI_BASE:
- val = g->up;
- break;
- case PCI_BASE + 4:
- val = g->down;
- break;
- default:
- break;
- }
-
-#if defined(DEBUG)
- printf("pcihotplug read %x == %x\n", addr, val);
-#endif
- return val;
-}
-
-static void pcihotplug_write(void *opaque, uint32_t addr, uint32_t val)
-{
- struct pci_status *g = opaque;
- switch (addr) {
- case PCI_BASE:
- g->up = val;
- break;
- case PCI_BASE + 4:
- g->down = val;
- break;
- }
-
-#if defined(DEBUG)
- printf("pcihotplug write %x <== %d\n", addr, val);
-#endif
-}
-
-static uint32_t pciej_read(void *opaque, uint32_t addr)
-{
-#if defined(DEBUG)
- printf("pciej read %x\n", addr);
-#endif
- return 0;
-}
-
-static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
-{
-#if defined (TARGET_I386)
- int slot = ffs(val) - 1;
-
- pci_device_hot_remove_success(0, slot);
-#endif
-
-#if defined(DEBUG)
- printf("pciej write %x <== %d\n", addr, val);
-#endif
-}
-
-static void piix4_device_hot_add(int bus, int slot, int state);
-
-void piix4_acpi_system_hot_add_init(void)
-{
- register_ioport_write(GPE_BASE, 4, 1, gpe_writeb, &gpe);
- register_ioport_read(GPE_BASE, 4, 1, gpe_readb, &gpe);
-
- register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, &pci0_status);
- register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, &pci0_status);
-
- register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, NULL);
- register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, NULL);
-
- qemu_system_device_hot_add_register(piix4_device_hot_add);
-}
-
-static void enable_device(struct pci_status *p, struct gpe_regs *g, int slot)
-{
- g->sts |= 2;
- p->up |= (1 << slot);
-}
-
-static void disable_device(struct pci_status *p, struct gpe_regs *g, int slot)
-{
- g->sts |= 2;
- p->down |= (1 << slot);
-}
-
-static void piix4_device_hot_add(int bus, int slot, int state)
-{
- pci0_status.up = 0;
- pci0_status.down = 0;
- if (state)
- enable_device(&pci0_status, &gpe, slot);
- else
- disable_device(&pci0_status, &gpe, slot);
- if (gpe.en & 2) {
- qemu_set_irq(pm_state->irq, 1);
- qemu_set_irq(pm_state->irq, 0);
- }
-}
-
static qemu_system_device_hot_add_t device_hot_add_callback;
void qemu_system_device_hot_add_register(qemu_system_device_hot_add_t callback)
{
diff --git a/hw/acpi.c b/hw/acpi_piix4.c
similarity index 73%
copy from hw/acpi.c
copy to hw/acpi_piix4.c
index 4d0690e..0f6f656 100644
--- a/hw/acpi.c
+++ b/hw/acpi_piix4.c
@@ -26,6 +26,7 @@
#include "i2c.h"
#include "smbus.h"
#include "kvm.h"
+#include "acpi.h"
//#define DEBUG
@@ -254,6 +255,7 @@ static void pm_io_space_update(PIIX4PMState *s)
}
}
+
static void pm_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len)
{
@@ -387,25 +389,6 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
return s->smb.smbus;
}
-#if defined(TARGET_I386)
-static qemu_powerdown_t qemu_powerdown_callback;
-static void *qemu_powerdown_arg;
-
-void qemu_system_powerdown_register(qemu_powerdown_t callback, void *arg)
-{
- qemu_powerdown_callback = callback;
- qemu_powerdown_arg = arg;
-}
-
-void qemu_system_powerdown(void)
-{
- if (!qemu_powerdown_callback) {
- qemu_system_shutdown_request();
- } else {
- qemu_powerdown_callback(qemu_powerdown_arg);
- }
-}
-#endif
#define GPE_BASE 0xafe0
#define PCI_BASE 0xae00
@@ -595,184 +578,3 @@ static void piix4_device_hot_add(int bus, int slot, int state)
qemu_set_irq(pm_state->irq, 0);
}
}
-
-static qemu_system_device_hot_add_t device_hot_add_callback;
-void qemu_system_device_hot_add_register(qemu_system_device_hot_add_t callback)
-{
- device_hot_add_callback = callback;
-}
-
-void qemu_system_device_hot_add(int pcibus, int slot, int state)
-{
- if (device_hot_add_callback)
- device_hot_add_callback(pcibus, slot, state);
-}
-
-struct acpi_table_header
-{
- char signature [4]; /* ACPI signature (4 ASCII characters) */
- uint32_t length; /* Length of table, in bytes, including header */
- uint8_t revision; /* ACPI Specification minor version # */
- uint8_t checksum; /* To make sum of entire table == 0 */
- char oem_id [6]; /* OEM identification */
- char oem_table_id [8]; /* OEM table identification */
- uint32_t oem_revision; /* OEM revision number */
- char asl_compiler_id [4]; /* ASL compiler vendor ID */
- uint32_t asl_compiler_revision; /* ASL compiler revision number */
-} __attribute__((packed));
-
-char *acpi_tables;
-size_t acpi_tables_len;
-
-static int acpi_checksum(const uint8_t *data, int len)
-{
- int sum, i;
- sum = 0;
- for(i = 0; i < len; i++)
- sum += data[i];
- return (-sum) & 0xff;
-}
-
-int acpi_table_add(const char *t)
-{
- static const char *dfl_id = "QEMUQEMU";
- char buf[1024], *p, *f;
- struct acpi_table_header acpi_hdr;
- unsigned long val;
- size_t off;
-
- memset(&acpi_hdr, 0, sizeof(acpi_hdr));
-
- if (get_param_value(buf, sizeof(buf), "sig", t)) {
- strncpy(acpi_hdr.signature, buf, 4);
- } else {
- strncpy(acpi_hdr.signature, dfl_id, 4);
- }
- if (get_param_value(buf, sizeof(buf), "rev", t)) {
- val = strtoul(buf, &p, 10);
- if (val > 255 || *p != '\0')
- goto out;
- } else {
- val = 1;
- }
- acpi_hdr.revision = (int8_t)val;
-
- if (get_param_value(buf, sizeof(buf), "oem_id", t)) {
- strncpy(acpi_hdr.oem_id, buf, 6);
- } else {
- strncpy(acpi_hdr.oem_id, dfl_id, 6);
- }
-
- if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) {
- strncpy(acpi_hdr.oem_table_id, buf, 8);
- } else {
- strncpy(acpi_hdr.oem_table_id, dfl_id, 8);
- }
-
- if (get_param_value(buf, sizeof(buf), "oem_rev", t)) {
- val = strtol(buf, &p, 10);
- if(*p != '\0')
- goto out;
- } else {
- val = 1;
- }
- acpi_hdr.oem_revision = cpu_to_le32(val);
-
- if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) {
- strncpy(acpi_hdr.asl_compiler_id, buf, 4);
- } else {
- strncpy(acpi_hdr.asl_compiler_id, dfl_id, 4);
- }
-
- if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) {
- val = strtol(buf, &p, 10);
- if(*p != '\0')
- goto out;
- } else {
- val = 1;
- }
- acpi_hdr.asl_compiler_revision = cpu_to_le32(val);
-
- if (!get_param_value(buf, sizeof(buf), "data", t)) {
- buf[0] = '\0';
- }
-
- acpi_hdr.length = sizeof(acpi_hdr);
-
- f = buf;
- while (buf[0]) {
- struct stat s;
- char *n = strchr(f, ':');
- if (n)
- *n = '\0';
- if(stat(f, &s) < 0) {
- fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
- goto out;
- }
- acpi_hdr.length += s.st_size;
- if (!n)
- break;
- *n = ':';
- f = n + 1;
- }
-
- if (!acpi_tables) {
- acpi_tables_len = sizeof(uint16_t);
- acpi_tables = qemu_mallocz(acpi_tables_len);
- }
- p = acpi_tables + acpi_tables_len;
- acpi_tables_len += sizeof(uint16_t) + acpi_hdr.length;
- acpi_tables = qemu_realloc(acpi_tables, acpi_tables_len);
-
- acpi_hdr.length = cpu_to_le32(acpi_hdr.length);
- *(uint16_t*)p = acpi_hdr.length;
- p += sizeof(uint16_t);
- memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
- off = sizeof(acpi_hdr);
-
- f = buf;
- while (buf[0]) {
- struct stat s;
- int fd;
- char *n = strchr(f, ':');
- if (n)
- *n = '\0';
- fd = open(f, O_RDONLY);
-
- if(fd < 0)
- goto out;
- if(fstat(fd, &s) < 0) {
- close(fd);
- goto out;
- }
-
- do {
- int r;
- r = read(fd, p + off, s.st_size);
- if (r > 0) {
- off += r;
- s.st_size -= r;
- } else if ((r < 0 && errno != EINTR) || r == 0) {
- close(fd);
- goto out;
- }
- } while(s.st_size);
-
- close(fd);
- if (!n)
- break;
- f = n + 1;
- }
-
- ((struct acpi_table_header*)p)->checksum = acpi_checksum((uint8_t*)p, off);
- /* increase number of tables */
- (*(uint16_t*)acpi_tables) =
- cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
- return 0;
-out:
- if (acpi_tables) {
- free(acpi_tables);
- acpi_tables = NULL;
- }
- return -1;
-}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 07/18] pc.c: Make smm enable/disable function i440fx independent.
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (5 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 06/18] acpi.c: split acpi.c into the common part and the piix4 part Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 08/18] pc.c: remove unnecessary global variables, pit and ioapic Isaku Yamahata
` (11 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
make cpu_smm_update() generic to be independent on i440fx by
registering a callback.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/pc.c | 18 +++++++++++++++---
hw/pc.h | 4 +++-
hw/piix_pci.c | 8 +++++---
3 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/hw/pc.c b/hw/pc.c
index a848d8d..b17a33f 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -58,7 +58,6 @@ static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
static PITState *pit;
static IOAPICState *ioapic;
-static PCIDevice *i440fx_state;
typedef struct rom_reset_data {
uint8_t *data;
@@ -118,10 +117,22 @@ uint64_t cpu_get_tsc(CPUX86State *env)
}
/* SMM support */
+
+static cpu_set_smm_t smm_set;
+static void *smm_arg;
+
+void cpu_smm_register(cpu_set_smm_t callback, void *arg)
+{
+ assert(smm_set == NULL);
+ assert(smm_arg == NULL);
+ smm_set = callback;
+ smm_arg = arg;
+}
+
void cpu_smm_update(CPUState *env)
{
- if (i440fx_state && env == first_cpu)
- i440fx_set_smm(i440fx_state, (env->hflags >> HF_SMM_SHIFT) & 1);
+ if (smm_set && smm_arg && env == first_cpu)
+ smm_set(!!(env->hflags && HF_SMM_SHIFT), smm_arg);
}
@@ -848,6 +859,7 @@ static void pc_init1(ram_addr_t ram_size,
ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
int bios_size, isa_bios_size, oprom_area_size;
PCIBus *pci_bus;
+ static PCIDevice *i440fx_state;
int piix3_devfn = -1;
CPUState *env;
qemu_irq *cpu_irq;
diff --git a/hw/pc.h b/hw/pc.h
index 9fbae20..bd711ce 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -103,6 +103,9 @@ extern int fd_bootchk;
void ioport_set_a20(int enable);
int ioport_get_a20(void);
+typedef void (*cpu_set_smm_t)(int smm, void *arg);
+void cpu_smm_register(cpu_set_smm_t callback, void *arg);
+
/* acpi.c */
extern int acpi_enabled;
extern char *acpi_tables;
@@ -126,7 +129,6 @@ int pcspk_audio_init(qemu_irq *pic);
/* piix_pci.c */
PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic);
-void i440fx_set_smm(PCIDevice *d, int val);
int piix3_init(PCIBus *bus, int devfn);
void i440fx_init_memory_mappings(PCIDevice *d);
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 914a65a..e7959f8 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -107,16 +107,16 @@ static void i440fx_update_memory_mappings(PCIDevice *d)
}
}
-void i440fx_set_smm(PCIDevice *d, int val)
+static void i440fx_set_smm(int smm, void *arg)
{
- val = (val != 0);
+ int val = (smm != 0);
+ PCIDevice *d = (PCIDevice*)arg;
if (smm_enabled != val) {
smm_enabled = val;
i440fx_update_memory_mappings(d);
}
}
-
/* XXX: suppress when better memory API. We make the assumption that
no device (in particular the VGA) changes the memory mappings in
the 0xa0000-0x100000 range */
@@ -202,6 +202,8 @@ PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic)
d->config[0x72] = 0x02; /* SMRAM */
register_savevm("I440FX", 0, 2, i440fx_save, i440fx_load, d);
+ cpu_smm_register(&i440fx_set_smm, d);
+
*pi440fx_state = d;
return b;
}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 08/18] pc.c: remove unnecessary global variables, pit and ioapic..
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (6 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 07/18] pc.c: Make smm enable/disable function i440fx independent Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 09/18] pc.c: remove a global variable, floppy_controller Isaku Yamahata
` (10 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
remove unnecessary global static variables, pit and ioapic.
They are unnecessarily global so make them local.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/pc.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/pc.c b/hw/pc.c
index b17a33f..16592e8 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -56,8 +56,6 @@
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
-static PITState *pit;
-static IOAPICState *ioapic;
typedef struct rom_reset_data {
uint8_t *data;
@@ -868,6 +866,8 @@ static void pc_init1(ram_addr_t ram_size,
BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
BlockDriverState *fd[MAX_FD];
int using_vga = cirrus_vga_enabled || std_vga_enabled || vmsvga_enabled;
+ PITState *pit;
+ IOAPICState *ioapic = NULL;
if (ram_size >= 0xe0000000 ) {
above_4g_mem_size = ram_size - 0xe0000000;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 09/18] pc.c: remove a global variable, floppy_controller.
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (7 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 08/18] pc.c: remove unnecessary global variables, pit and ioapic Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 10/18] pc.c: remove a global variable, RTCState *rtc_state Isaku Yamahata
` (9 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
Remove a global variable, floppy_controller.
Since it is unnecessarily global, make it local and pass it as
a function argument.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/pc.c | 8 +++++---
1 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/hw/pc.c b/hw/pc.c
index 16592e8..9055c0d 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -54,7 +54,6 @@
#define MAX_IDE_BUS 2
-static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
typedef struct rom_reset_data {
@@ -264,7 +263,8 @@ static int pc_boot_set(void *opaque, const char *boot_device)
/* hd_table must contain 4 block drivers */
static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
- const char *boot_device, BlockDriverState **hd_table)
+ const char *boot_device, BlockDriverState **hd_table,
+ fdctrl_t *floppy_controller)
{
RTCState *s = rtc_state;
int nbds, bds[3] = { 0, };
@@ -866,6 +866,7 @@ static void pc_init1(ram_addr_t ram_size,
BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
BlockDriverState *fd[MAX_FD];
int using_vga = cirrus_vga_enabled || std_vga_enabled || vmsvga_enabled;
+ fdctrl_t *floppy_controller;
PITState *pit;
IOAPICState *ioapic = NULL;
@@ -1117,7 +1118,8 @@ static void pc_init1(ram_addr_t ram_size,
}
floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
- cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd);
+ cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd,
+ floppy_controller);
if (pci_enabled && usb_enabled) {
usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 10/18] pc.c: remove a global variable, RTCState *rtc_state.
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (8 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 09/18] pc.c: remove a global variable, floppy_controller Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 11/18] pc.c: introduce a function to allocate cpu irq Isaku Yamahata
` (8 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
remove a global variable, RTCState *rtc_state.
Only the cmos_set_s3_resume_init() needs it global.
So introduce a registering function and make it local.
As for other function which references the variable, pass it
as a function argument.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/pc.c | 25 ++++++++++++++++---------
hw/pc.h | 6 ++++++
2 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/hw/pc.c b/hw/pc.c
index 9055c0d..04d61bd 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -54,8 +54,6 @@
#define MAX_IDE_BUS 2
-static RTCState *rtc_state;
-
typedef struct rom_reset_data {
uint8_t *data;
target_phys_addr_t addr;
@@ -199,9 +197,9 @@ static int cmos_get_fd_drive_type(int fd0)
return val;
}
-static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
+static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd,
+ RTCState *s)
{
- RTCState *s = rtc_state;
int cylinders, heads, sectors;
bdrv_get_geometry_hint(hd, &cylinders, &heads, §ors);
rtc_set_memory(s, type_ofs, 47);
@@ -264,9 +262,8 @@ static int pc_boot_set(void *opaque, const char *boot_device)
/* hd_table must contain 4 block drivers */
static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
const char *boot_device, BlockDriverState **hd_table,
- fdctrl_t *floppy_controller)
+ fdctrl_t *floppy_controller, RTCState *s)
{
- RTCState *s = rtc_state;
int nbds, bds[3] = { 0, };
int val;
int fd0, fd1, nb;
@@ -355,9 +352,9 @@ static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
if (hd_table[0])
- cmos_init_hd(0x19, 0x1b, hd_table[0]);
+ cmos_init_hd(0x19, 0x1b, hd_table[0], s);
if (hd_table[1])
- cmos_init_hd(0x1a, 0x24, hd_table[1]);
+ cmos_init_hd(0x1a, 0x24, hd_table[1], s);
val = 0;
for (i = 0; i < 4; i++) {
@@ -867,6 +864,7 @@ static void pc_init1(ram_addr_t ram_size,
BlockDriverState *fd[MAX_FD];
int using_vga = cirrus_vga_enabled || std_vga_enabled || vmsvga_enabled;
fdctrl_t *floppy_controller;
+ RTCState *rtc_state;
PITState *pit;
IOAPICState *ioapic = NULL;
@@ -1036,6 +1034,7 @@ static void pc_init1(ram_addr_t ram_size,
}
rtc_state = rtc_init(0x70, i8259[8], 2000);
+ cmos_set_s3_resume_init(rtc_state);
qemu_register_boot_set(pc_boot_set, rtc_state);
@@ -1119,7 +1118,7 @@ static void pc_init1(ram_addr_t ram_size,
floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd,
- floppy_controller);
+ floppy_controller, rtc_state);
if (pci_enabled && usb_enabled) {
usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
@@ -1204,13 +1203,21 @@ static void pc_init_isa(ram_addr_t ram_size,
initrd_filename, 0, cpu_model);
}
+#if defined(TARGET_I386)
/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
BIOS will read it and start S3 resume at POST Entry */
+static RTCState *rtc_state;
+void cmos_set_s3_resume_init(RTCState *s)
+{
+ rtc_state = s;
+}
+
void cmos_set_s3_resume(void)
{
if (rtc_state)
rtc_set_memory(rtc_state, 0xF, 0xFE);
}
+#endif
static QEMUMachine pc_machine = {
.name = "pc",
diff --git a/hw/pc.h b/hw/pc.h
index bd711ce..a18e558 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -95,7 +95,13 @@ RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq,
int base_year);
void rtc_set_memory(RTCState *s, int addr, int val);
void rtc_set_date(RTCState *s, const struct tm *tm);
+#if defined(TARGET_I386)
+void cmos_set_s3_resume_init(RTCState *s);
void cmos_set_s3_resume(void);
+#else
+static inline void cmos_set_s3_resume_init(RTCState *s) {}
+static inline void cmos_set_s3_resume(void) {}
+#endif
/* pc.c */
extern int fd_bootchk;
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 11/18] pc.c: introduce a function to allocate cpu irq.
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (9 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 10/18] pc.c: remove a global variable, RTCState *rtc_state Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-21 20:32 ` Blue Swirl
2009-06-18 10:57 ` [Qemu-devel] [PATCH 12/18] pc.c: make pc_init1() not refer ferr_irq directly Isaku Yamahata
` (7 subsequent siblings)
18 siblings, 1 reply; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
Introduce a function, pc_allocate_cpu_irq(), to allocate cpu irq
in order to make pic_irq_request() piix independent.
Later piix code will be split out to another file keeping pic_irq_request()
static.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/pc.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/hw/pc.c b/hw/pc.c
index 04d61bd..16e95ec 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -841,6 +841,11 @@ int cpu_is_bsp(CPUState *env)
return env->cpuid_apic_id == 0;
}
+static qemu_irq *pc_allocte_cpu_irq(void)
+{
+ return qemu_allocate_irqs(pic_irq_request, NULL, 1);
+}
+
/* PC hardware initialisation */
static void pc_init1(ram_addr_t ram_size,
const char *boot_device,
@@ -998,7 +1003,7 @@ static void pc_init1(ram_addr_t ram_size,
bochs_bios_init();
- cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
+ cpu_irq = pc_allocte_cpu_irq();
i8259 = i8259_init(cpu_irq[0]);
ferr_irq = i8259[13];
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [Qemu-devel] [PATCH 11/18] pc.c: introduce a function to allocate cpu irq.
2009-06-18 10:57 ` [Qemu-devel] [PATCH 11/18] pc.c: introduce a function to allocate cpu irq Isaku Yamahata
@ 2009-06-21 20:32 ` Blue Swirl
0 siblings, 0 replies; 21+ messages in thread
From: Blue Swirl @ 2009-06-21 20:32 UTC (permalink / raw)
To: Isaku Yamahata; +Cc: qemu-devel
On 6/18/09, Isaku Yamahata <yamahata@valinux.co.jp> wrote:
> Introduce a function, pc_allocate_cpu_irq(), to allocate cpu irq
> in order to make pic_irq_request() piix independent.
> Later piix code will be split out to another file keeping pic_irq_request()
> static.
>
> Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
> ---
> hw/pc.c | 7 ++++++-
> 1 files changed, 6 insertions(+), 1 deletions(-)
>
> diff --git a/hw/pc.c b/hw/pc.c
> index 04d61bd..16e95ec 100644
> --- a/hw/pc.c
> +++ b/hw/pc.c
> @@ -841,6 +841,11 @@ int cpu_is_bsp(CPUState *env)
> return env->cpuid_apic_id == 0;
> }
>
> +static qemu_irq *pc_allocte_cpu_irq(void)
allocte -> allocate
> - cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
> + cpu_irq = pc_allocte_cpu_irq();
allocte -> allocate
^ permalink raw reply [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 12/18] pc.c: make pc_init1() not refer ferr_irq directly.
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (10 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 11/18] pc.c: introduce a function to allocate cpu irq Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 13/18] pc.c: split out cpu initialization from pc_init1() into pc_cpus_init() Isaku Yamahata
` (6 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
By introducing a registering function, make pc_init1() not refer to
ferr_irq directly in order to make ferr_irq piix independent.
Later pc_init1() will be split out into another file keeping ferr_irq
static.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/pc.c | 8 +++++++-
hw/pc.h | 2 ++
2 files changed, 9 insertions(+), 1 deletions(-)
diff --git a/hw/pc.c b/hw/pc.c
index 16e95ec..eeb56cc 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -84,6 +84,12 @@ static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
/* MSDOS compatibility mode FPU exception support */
static qemu_irq ferr_irq;
+
+void pc_register_ferr_irq(qemu_irq irq)
+{
+ ferr_irq = irq;
+}
+
/* XXX: add IGNNE support */
void cpu_set_ferr(CPUX86State *s)
{
@@ -1005,7 +1011,7 @@ static void pc_init1(ram_addr_t ram_size,
cpu_irq = pc_allocte_cpu_irq();
i8259 = i8259_init(cpu_irq[0]);
- ferr_irq = i8259[13];
+ pc_register_ferr_irq(i8259[13]);
if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, i8259);
diff --git a/hw/pc.h b/hw/pc.h
index a18e558..f5f84ad 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -106,6 +106,8 @@ static inline void cmos_set_s3_resume(void) {}
/* pc.c */
extern int fd_bootchk;
+void pc_register_ferr_irq(qemu_irq irq);
+
void ioport_set_a20(int enable);
int ioport_get_a20(void);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 13/18] pc.c: split out cpu initialization from pc_init1() into pc_cpus_init().
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (11 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 12/18] pc.c: make pc_init1() not refer ferr_irq directly Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 14/18] pc.c: split out memory allocation from pc_init1() into pc_memory_init() Isaku Yamahata
` (5 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
split out cpu initialization which is piix independent from pc_init1()
into pc_cpus_init(). Later it will be used.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/pc.c | 51 +++++++++++++++++++++++++++++----------------------
1 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/hw/pc.c b/hw/pc.c
index eeb56cc..880b510 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -847,6 +847,34 @@ int cpu_is_bsp(CPUState *env)
return env->cpuid_apic_id == 0;
}
+static void pc_cpus_init(const char *cpu_model)
+{
+ int i;
+ CPUState *env;
+
+ /* init CPUs */
+ if (cpu_model == NULL) {
+#ifdef TARGET_X86_64
+ cpu_model = "qemu64";
+#else
+ cpu_model = "qemu32";
+#endif
+ }
+
+ for(i = 0; i < smp_cpus; i++) {
+ env = cpu_init(cpu_model);
+ if (!env) {
+ fprintf(stderr, "Unable to find x86 CPU definition\n");
+ exit(1);
+ }
+ if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
+ env->cpuid_apic_id = env->cpu_index;
+ apic_init(env);
+ }
+ qemu_register_reset(main_cpu_reset, 0, env);
+ }
+}
+
static qemu_irq *pc_allocte_cpu_irq(void)
{
return qemu_allocate_irqs(pic_irq_request, NULL, 1);
@@ -867,7 +895,6 @@ static void pc_init1(ram_addr_t ram_size,
PCIBus *pci_bus;
static PCIDevice *i440fx_state;
int piix3_devfn = -1;
- CPUState *env;
qemu_irq *cpu_irq;
qemu_irq *i8259;
int index;
@@ -888,27 +915,7 @@ static void pc_init1(ram_addr_t ram_size,
linux_boot = (kernel_filename != NULL);
- /* init CPUs */
- if (cpu_model == NULL) {
-#ifdef TARGET_X86_64
- cpu_model = "qemu64";
-#else
- cpu_model = "qemu32";
-#endif
- }
-
- for(i = 0; i < smp_cpus; i++) {
- env = cpu_init(cpu_model);
- if (!env) {
- fprintf(stderr, "Unable to find x86 CPU definition\n");
- exit(1);
- }
- if ((env->cpuid_features & CPUID_APIC) || smp_cpus > 1) {
- env->cpuid_apic_id = env->cpu_index;
- apic_init(env);
- }
- qemu_register_reset(main_cpu_reset, 0, env);
- }
+ pc_cpus_init(cpu_model);
vmport_init();
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 14/18] pc.c: split out memory allocation from pc_init1() into pc_memory_init()
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (12 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 13/18] pc.c: split out cpu initialization from pc_init1() into pc_cpus_init() Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 15/18] pc.c: split out vga initialization from pc_init1() into pc_vga_init() Isaku Yamahata
` (4 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
Split out memory allocation and rom/bios loading which doesn't depend
on piix from pc_init1() into pc_memory_init().
Later it will be used.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/pc.c | 71 +++++++++++++++++++++++++++++++++++++++------------------------
1 files changed, 44 insertions(+), 27 deletions(-)
diff --git a/hw/pc.c b/hw/pc.c
index 880b510..3321d88 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -875,36 +875,19 @@ static void pc_cpus_init(const char *cpu_model)
}
}
-static qemu_irq *pc_allocte_cpu_irq(void)
-{
- return qemu_allocate_irqs(pic_irq_request, NULL, 1);
-}
-
-/* PC hardware initialisation */
-static void pc_init1(ram_addr_t ram_size,
- const char *boot_device,
- const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename,
- int pci_enabled, const char *cpu_model)
+static void pc_memory_init(ram_addr_t ram_size,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ ram_addr_t *below_4g_mem_size_p,
+ ram_addr_t *above_4g_mem_size_p)
{
char *filename;
int ret, linux_boot, i;
ram_addr_t ram_addr, bios_offset, option_rom_offset;
ram_addr_t below_4g_mem_size, above_4g_mem_size = 0;
int bios_size, isa_bios_size, oprom_area_size;
- PCIBus *pci_bus;
- static PCIDevice *i440fx_state;
- int piix3_devfn = -1;
- qemu_irq *cpu_irq;
- qemu_irq *i8259;
- int index;
- BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- BlockDriverState *fd[MAX_FD];
int using_vga = cirrus_vga_enabled || std_vga_enabled || vmsvga_enabled;
- fdctrl_t *floppy_controller;
- RTCState *rtc_state;
- PITState *pit;
- IOAPICState *ioapic = NULL;
if (ram_size >= 0xe0000000 ) {
above_4g_mem_size = ram_size - 0xe0000000;
@@ -912,13 +895,11 @@ static void pc_init1(ram_addr_t ram_size,
} else {
below_4g_mem_size = ram_size;
}
+ *above_4g_mem_size_p = above_4g_mem_size;
+ *below_4g_mem_size_p = below_4g_mem_size;
linux_boot = (kernel_filename != NULL);
- pc_cpus_init(cpu_model);
-
- vmport_init();
-
/* allocate RAM */
ram_addr = qemu_ram_alloc(0xa0000);
cpu_register_physical_memory(0, 0xa0000, ram_addr);
@@ -1015,6 +996,42 @@ static void pc_init1(ram_addr_t ram_size,
bios_size, bios_offset | IO_MEM_ROM);
bochs_bios_init();
+}
+
+static qemu_irq *pc_allocte_cpu_irq(void)
+{
+ return qemu_allocate_irqs(pic_irq_request, NULL, 1);
+}
+
+/* PC hardware initialisation */
+static void pc_init1(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename,
+ int pci_enabled, const char *cpu_model)
+{
+ int i;
+ ram_addr_t below_4g_mem_size, above_4g_mem_size;
+ PCIBus *pci_bus;
+ static PCIDevice *i440fx_state;
+ int piix3_devfn = -1;
+ qemu_irq *cpu_irq;
+ qemu_irq *i8259;
+ int index;
+ BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+ BlockDriverState *fd[MAX_FD];
+ fdctrl_t *floppy_controller;
+ RTCState *rtc_state;
+ PITState *pit;
+ IOAPICState *ioapic = NULL;
+
+ pc_cpus_init(cpu_model);
+
+ vmport_init();
+
+ /* allocate ram and load rom/bios */
+ pc_memory_init(ram_size, kernel_filename, kernel_cmdline, initrd_filename,
+ &below_4g_mem_size, &above_4g_mem_size);
cpu_irq = pc_allocte_cpu_irq();
i8259 = i8259_init(cpu_irq[0]);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 15/18] pc.c: split out vga initialization from pc_init1() into pc_vga_init().
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (13 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 14/18] pc.c: split out memory allocation from pc_init1() into pc_memory_init() Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 16/18] pc.c: split out basic device init from pc_init1() into pc_basic_device_init() Isaku Yamahata
` (3 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
Split out vga initialization which is independent of piix
from pc_init1() as pc_vga_init().
Later it will be used.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/pc.c | 43 ++++++++++++++++++++++++-------------------
1 files changed, 24 insertions(+), 19 deletions(-)
diff --git a/hw/pc.c b/hw/pc.c
index 3321d88..76bead4 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1003,7 +1003,29 @@ static qemu_irq *pc_allocte_cpu_irq(void)
return qemu_allocate_irqs(pic_irq_request, NULL, 1);
}
-/* PC hardware initialisation */
+static void pc_vga_init(PCIBus *pci_bus)
+{
+ if (cirrus_vga_enabled) {
+ if (pci_bus) {
+ pci_cirrus_vga_init(pci_bus);
+ } else {
+ isa_cirrus_vga_init();
+ }
+ } else if (vmsvga_enabled) {
+ if (pci_bus)
+ pci_vmsvga_init(pci_bus);
+ else
+ fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
+ } else if (std_vga_enabled) {
+ if (pci_bus) {
+ pci_vga_init(pci_bus, 0, 0);
+ } else {
+ isa_vga_init();
+ }
+ }
+}
+
+* PC hardware initialisation */
static void pc_init1(ram_addr_t ram_size,
const char *boot_device,
const char *kernel_filename, const char *kernel_cmdline,
@@ -1049,24 +1071,7 @@ static void pc_init1(ram_addr_t ram_size,
register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
- if (cirrus_vga_enabled) {
- if (pci_enabled) {
- pci_cirrus_vga_init(pci_bus);
- } else {
- isa_cirrus_vga_init();
- }
- } else if (vmsvga_enabled) {
- if (pci_enabled)
- pci_vmsvga_init(pci_bus);
- else
- fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
- } else if (std_vga_enabled) {
- if (pci_enabled) {
- pci_vga_init(pci_bus, 0, 0);
- } else {
- isa_vga_init();
- }
- }
+ pc_vga_init(pci_enabled? pci_bus: NULL);
rtc_state = rtc_init(0x70, i8259[8], 2000);
cmos_set_s3_resume_init(rtc_state);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 16/18] pc.c: split out basic device init from pc_init1() into pc_basic_device_init()
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (14 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 15/18] pc.c: split out vga initialization from pc_init1() into pc_vga_init() Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 17/18] pc.c: split out pci device init from pc_init1() into pc_pci_device_init() Isaku Yamahata
` (2 subsequent siblings)
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
Split out basic device, i.e. legacy devices like floppy, initialization
from pc_init1() into pc_basic_device_init().
Later it will be used.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/pc.c | 105 +++++++++++++++++++++++++++++++++-----------------------------
1 files changed, 56 insertions(+), 49 deletions(-)
diff --git a/hw/pc.c b/hw/pc.c
index 76bead4..6886751 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1025,7 +1025,59 @@ static void pc_vga_init(PCIBus *pci_bus)
}
}
-* PC hardware initialisation */
+static void pc_basic_device_init(qemu_irq *i8259,
+ fdctrl_t **floppy_controller,
+ RTCState **rtc_state)
+{
+ int i;
+ BlockDriverState *fd[MAX_FD];
+ PITState *pit;
+
+ register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
+
+ register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
+
+ *rtc_state = rtc_init(0x70, i8259[8], 2000);
+ cmos_set_s3_resume_init(*rtc_state);
+
+ qemu_register_boot_set(pc_boot_set, *rtc_state);
+
+ register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
+ register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
+
+ pit = pit_init(0x40, i8259[0]);
+ pcspk_init(pit);
+ if (!no_hpet) {
+ hpet_init(i8259);
+ }
+
+ for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+ if (serial_hds[i]) {
+ serial_init(serial_io[i], i8259[serial_irq[i]], 115200,
+ serial_hds[i]);
+ }
+ }
+
+ for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
+ if (parallel_hds[i]) {
+ parallel_init(parallel_io[i], i8259[parallel_irq[i]],
+ parallel_hds[i]);
+ }
+ }
+
+ i8042_init(i8259[1], i8259[12], 0x60);
+ DMA_init(0);
+ for(i = 0; i < MAX_FD; i++) {
+ int index = drive_get_index(IF_FLOPPY, 0, i);
+ if (index != -1)
+ fd[i] = drives_table[index].bdrv;
+ else
+ fd[i] = NULL;
+ }
+ *floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
+}
+
+/* PC hardware initialisation */
static void pc_init1(ram_addr_t ram_size,
const char *boot_device,
const char *kernel_filename, const char *kernel_cmdline,
@@ -1041,11 +1093,8 @@ static void pc_init1(ram_addr_t ram_size,
qemu_irq *i8259;
int index;
BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- BlockDriverState *fd[MAX_FD];
fdctrl_t *floppy_controller;
RTCState *rtc_state;
- PITState *pit;
- IOAPICState *ioapic = NULL;
pc_cpus_init(cpu_model);
@@ -1066,47 +1115,16 @@ static void pc_init1(ram_addr_t ram_size,
pci_bus = NULL;
}
- /* init basic PC hardware */
- register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
-
- register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
-
pc_vga_init(pci_enabled? pci_bus: NULL);
- rtc_state = rtc_init(0x70, i8259[8], 2000);
- cmos_set_s3_resume_init(rtc_state);
-
- qemu_register_boot_set(pc_boot_set, rtc_state);
-
- register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
- register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
+ /* init basic PC hardware */
+ pc_basic_device_init(i8259, &floppy_controller, &rtc_state);
if (pci_enabled) {
- ioapic = ioapic_init();
- }
- pit = pit_init(0x40, i8259[0]);
- pcspk_init(pit);
- if (!no_hpet) {
- hpet_init(i8259);
- }
- if (pci_enabled) {
+ IOAPICState *ioapic = ioapic_init();
pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
}
- for(i = 0; i < MAX_SERIAL_PORTS; i++) {
- if (serial_hds[i]) {
- serial_init(serial_io[i], i8259[serial_irq[i]], 115200,
- serial_hds[i]);
- }
- }
-
- for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
- if (parallel_hds[i]) {
- parallel_init(parallel_io[i], i8259[parallel_irq[i]],
- parallel_hds[i]);
- }
- }
-
watchdog_pc_init(pci_bus);
for(i = 0; i < nb_nics; i++) {
@@ -1142,21 +1160,10 @@ static void pc_init1(ram_addr_t ram_size,
}
}
- i8042_init(i8259[1], i8259[12], 0x60);
- DMA_init(0);
#ifdef HAS_AUDIO
audio_init(pci_enabled ? pci_bus : NULL, i8259);
#endif
- for(i = 0; i < MAX_FD; i++) {
- index = drive_get_index(IF_FLOPPY, 0, i);
- if (index != -1)
- fd[i] = drives_table[index].bdrv;
- else
- fd[i] = NULL;
- }
- floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
-
cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd,
floppy_controller, rtc_state);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 17/18] pc.c: split out pci device init from pc_init1() into pc_pci_device_init()
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (15 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 16/18] pc.c: split out basic device init from pc_init1() into pc_basic_device_init() Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 10:57 ` [Qemu-devel] [PATCH 18/18] pc.c: split out piix specific part from pc.c into pc_piix.c Isaku Yamahata
2009-06-18 11:00 ` [Qemu-devel] [PATCH] q35 chipset based pc. wip Isaku Yamahata
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
Split out pci device initialization from pc_init1() into pc_pci_device_init().
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
hw/pc.c | 72 +++++++++++++++++++++++++++++++++++----------------------------
1 files changed, 40 insertions(+), 32 deletions(-)
diff --git a/hw/pc.c b/hw/pc.c
index 6886751..4885f25 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1077,6 +1077,45 @@ static void pc_basic_device_init(qemu_irq *i8259,
*floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
}
+static void pc_pci_device_init(PCIBus *pci_bus)
+{
+ {
+ int max_bus;
+ int bus;
+
+ max_bus = drive_get_max_bus(IF_SCSI);
+ for (bus = 0; bus <= max_bus; bus++) {
+ pci_create_simple(pci_bus, -1, "lsi53c895a");
+ }
+ }
+
+ /* Add virtio block devices */
+ {
+ int index;
+ int unit_id = 0;
+
+ while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) {
+ pci_create_simple(pci_bus, -1, "virtio-blk-pci");
+ unit_id++;
+ }
+ }
+
+ /* Add virtio balloon device */
+ if (!no_virtio_balloon) {
+ pci_create_simple(pci_bus, -1, "virtio-balloon-pci");
+ }
+
+ /* Add virtio console devices */
+ {
+ int i;
+ for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
+ if (virtcon_hds[i]) {
+ pci_create_simple(pci_bus, -1, "virtio-console-pci");
+ }
+ }
+ }
+}
+
/* PC hardware initialisation */
static void pc_init1(ram_addr_t ram_size,
const char *boot_device,
@@ -1191,38 +1230,7 @@ static void pc_init1(ram_addr_t ram_size,
}
if (pci_enabled) {
- int max_bus;
- int bus;
-
- max_bus = drive_get_max_bus(IF_SCSI);
- for (bus = 0; bus <= max_bus; bus++) {
- pci_create_simple(pci_bus, -1, "lsi53c895a");
- }
- }
-
- /* Add virtio block devices */
- if (pci_enabled) {
- int index;
- int unit_id = 0;
-
- while ((index = drive_get_index(IF_VIRTIO, 0, unit_id)) != -1) {
- pci_create_simple(pci_bus, -1, "virtio-blk-pci");
- unit_id++;
- }
- }
-
- /* Add virtio balloon device */
- if (pci_enabled && !no_virtio_balloon) {
- pci_create_simple(pci_bus, -1, "virtio-balloon-pci");
- }
-
- /* Add virtio console devices */
- if (pci_enabled) {
- for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) {
- if (virtcon_hds[i]) {
- pci_create_simple(pci_bus, -1, "virtio-console-pci");
- }
- }
+ pc_pci_device_init(pci_bus);
}
}
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH 18/18] pc.c: split out piix specific part from pc.c into pc_piix.c
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (16 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 17/18] pc.c: split out pci device init from pc_init1() into pc_pci_device_init() Isaku Yamahata
@ 2009-06-18 10:57 ` Isaku Yamahata
2009-06-18 11:00 ` [Qemu-devel] [PATCH] q35 chipset based pc. wip Isaku Yamahata
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 10:57 UTC (permalink / raw)
To: qemu-devel; +Cc: yamahata
Finally, we can safely split out the piix specific part from pc.c
into pc_piix.c.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
---
Makefile.target | 2 +-
hw/pc.c | 207 +++++-------------------------------------------------
hw/pc.h | 22 ++++++
hw/pc_piix.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 251 insertions(+), 190 deletions(-)
create mode 100644 hw/pc_piix.c
diff --git a/Makefile.target b/Makefile.target
index 2cf55b9..f2b59f4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -573,7 +573,7 @@ ifeq ($(TARGET_BASE_ARCH), i386)
OBJS+= ide.o pckbd.o vga.o $(SOUND_HW) dma.o
OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
OBJS+= cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
-OBJS+= acpi_piix4.o pc_smbus.o pc_apm.o
+OBJS+= pc_piix.o acpi_piix4.o pc_smbus.o pc_apm.o
OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
OBJS += device-hotplug.o pci-hotplug.o smbios.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
diff --git a/hw/pc.c b/hw/pc.c
index 4885f25..ddcd5e6 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -52,8 +52,6 @@
#define FW_CFG_ACPI_TABLES (FW_CFG_ARCH_LOCAL + 0)
#define FW_CFG_SMBIOS_ENTRIES (FW_CFG_ARCH_LOCAL + 1)
-#define MAX_IDE_BUS 2
-
typedef struct rom_reset_data {
uint8_t *data;
target_phys_addr_t addr;
@@ -266,9 +264,9 @@ static int pc_boot_set(void *opaque, const char *boot_device)
}
/* hd_table must contain 4 block drivers */
-static void cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
- const char *boot_device, BlockDriverState **hd_table,
- fdctrl_t *floppy_controller, RTCState *s)
+void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+ const char *boot_device, BlockDriverState **hd_table,
+ fdctrl_t *floppy_controller, RTCState *s)
{
int nbds, bds[3] = { 0, };
int val;
@@ -769,10 +767,6 @@ static void main_cpu_reset(void *opaque)
cpu_reset(env);
}
-static const int ide_iobase[2] = { 0x1f0, 0x170 };
-static const int ide_iobase2[2] = { 0x3f6, 0x376 };
-static const int ide_irq[2] = { 14, 15 };
-
#define NE2000_NB_MAX 6
static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
@@ -785,7 +779,7 @@ static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
#ifdef HAS_AUDIO
-static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
+void audio_init (PCIBus *pci_bus, qemu_irq *pic)
{
struct soundhw *c;
@@ -803,7 +797,7 @@ static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
}
#endif
-static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
+void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
{
static int nb_ne2k = 0;
@@ -847,7 +841,7 @@ int cpu_is_bsp(CPUState *env)
return env->cpuid_apic_id == 0;
}
-static void pc_cpus_init(const char *cpu_model)
+void pc_cpus_init(const char *cpu_model)
{
int i;
CPUState *env;
@@ -875,12 +869,12 @@ static void pc_cpus_init(const char *cpu_model)
}
}
-static void pc_memory_init(ram_addr_t ram_size,
- const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename,
- ram_addr_t *below_4g_mem_size_p,
- ram_addr_t *above_4g_mem_size_p)
+void pc_memory_init(ram_addr_t ram_size,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ ram_addr_t *below_4g_mem_size_p,
+ ram_addr_t *above_4g_mem_size_p)
{
char *filename;
int ret, linux_boot, i;
@@ -998,12 +992,12 @@ static void pc_memory_init(ram_addr_t ram_size,
bochs_bios_init();
}
-static qemu_irq *pc_allocte_cpu_irq(void)
+qemu_irq *pc_allocte_cpu_irq(void)
{
return qemu_allocate_irqs(pic_irq_request, NULL, 1);
}
-static void pc_vga_init(PCIBus *pci_bus)
+void pc_vga_init(PCIBus *pci_bus)
{
if (cirrus_vga_enabled) {
if (pci_bus) {
@@ -1025,9 +1019,9 @@ static void pc_vga_init(PCIBus *pci_bus)
}
}
-static void pc_basic_device_init(qemu_irq *i8259,
- fdctrl_t **floppy_controller,
- RTCState **rtc_state)
+void pc_basic_device_init(qemu_irq *i8259,
+ fdctrl_t **floppy_controller,
+ RTCState **rtc_state)
{
int i;
BlockDriverState *fd[MAX_FD];
@@ -1077,7 +1071,7 @@ static void pc_basic_device_init(qemu_irq *i8259,
*floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
}
-static void pc_pci_device_init(PCIBus *pci_bus)
+void pc_pci_device_init(PCIBus *pci_bus)
{
{
int max_bus;
@@ -1116,148 +1110,6 @@ static void pc_pci_device_init(PCIBus *pci_bus)
}
}
-/* PC hardware initialisation */
-static void pc_init1(ram_addr_t ram_size,
- const char *boot_device,
- const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename,
- int pci_enabled, const char *cpu_model)
-{
- int i;
- ram_addr_t below_4g_mem_size, above_4g_mem_size;
- PCIBus *pci_bus;
- static PCIDevice *i440fx_state;
- int piix3_devfn = -1;
- qemu_irq *cpu_irq;
- qemu_irq *i8259;
- int index;
- BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- fdctrl_t *floppy_controller;
- RTCState *rtc_state;
-
- pc_cpus_init(cpu_model);
-
- vmport_init();
-
- /* allocate ram and load rom/bios */
- pc_memory_init(ram_size, kernel_filename, kernel_cmdline, initrd_filename,
- &below_4g_mem_size, &above_4g_mem_size);
-
- cpu_irq = pc_allocte_cpu_irq();
- i8259 = i8259_init(cpu_irq[0]);
- pc_register_ferr_irq(i8259[13]);
-
- if (pci_enabled) {
- pci_bus = i440fx_init(&i440fx_state, i8259);
- piix3_devfn = piix3_init(pci_bus, -1);
- } else {
- pci_bus = NULL;
- }
-
- pc_vga_init(pci_enabled? pci_bus: NULL);
-
- /* init basic PC hardware */
- pc_basic_device_init(i8259, &floppy_controller, &rtc_state);
-
- if (pci_enabled) {
- IOAPICState *ioapic = ioapic_init();
- pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
- }
-
- watchdog_pc_init(pci_bus);
-
- for(i = 0; i < nb_nics; i++) {
- NICInfo *nd = &nd_table[i];
-
- if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
- pc_init_ne2k_isa(nd, i8259);
- else
- pci_nic_init(pci_bus, nd, -1, "ne2k_pci");
- }
-
- piix4_acpi_system_hot_add_init();
-
- if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
- fprintf(stderr, "qemu: too many IDE bus\n");
- exit(1);
- }
-
- for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
- index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
- if (index != -1)
- hd[i] = drives_table[index].bdrv;
- else
- hd[i] = NULL;
- }
-
- if (pci_enabled) {
- pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1, i8259);
- } else {
- for(i = 0; i < MAX_IDE_BUS; i++) {
- isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
- hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
- }
- }
-
-#ifdef HAS_AUDIO
- audio_init(pci_enabled ? pci_bus : NULL, i8259);
-#endif
-
- cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd,
- floppy_controller, rtc_state);
-
- if (pci_enabled && usb_enabled) {
- usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
- }
-
- if (pci_enabled && acpi_enabled) {
- uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
- i2c_bus *smbus;
-
- /* TODO: Populate SPD eeprom data. */
- smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]);
- for (i = 0; i < 8; i++) {
- DeviceState *eeprom;
- eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
- qdev_set_prop_int(eeprom, "address", 0x50 + i);
- qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
- qdev_init(eeprom);
- }
- }
-
- if (i440fx_state) {
- i440fx_init_memory_mappings(i440fx_state);
- }
-
- if (pci_enabled) {
- pc_pci_device_init(pci_bus);
- }
-}
-
-static void pc_init_pci(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)
-{
- pc_init1(ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, 1, cpu_model);
-}
-
-static void pc_init_isa(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)
-{
- pc_init1(ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, 0, cpu_model);
-}
-
#if defined(TARGET_I386)
/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
BIOS will read it and start S3 resume at POST Entry */
@@ -1273,26 +1125,3 @@ void cmos_set_s3_resume(void)
rtc_set_memory(rtc_state, 0xF, 0xFE);
}
#endif
-
-static QEMUMachine pc_machine = {
- .name = "pc",
- .desc = "Standard PC",
- .init = pc_init_pci,
- .max_cpus = 255,
- .is_default = 1,
-};
-
-static QEMUMachine isapc_machine = {
- .name = "isapc",
- .desc = "ISA-only PC",
- .init = pc_init_isa,
- .max_cpus = 1,
-};
-
-static void pc_machine_init(void)
-{
- qemu_register_machine(&pc_machine);
- qemu_register_machine(&isapc_machine);
-}
-
-machine_init(pc_machine_init);
diff --git a/hw/pc.h b/hw/pc.h
index f5f84ad..cdd568f 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -108,6 +108,28 @@ extern int fd_bootchk;
void pc_register_ferr_irq(qemu_irq irq);
+void pc_cpus_init(const char *cpu_model);
+void pc_memory_init(ram_addr_t ram_size,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ ram_addr_t *below_4g_mem_size_p,
+ ram_addr_t *above_4g_mem_size_p);
+qemu_irq *pc_allocte_cpu_irq(void);
+void pc_vga_init(PCIBus *pci_bus);
+struct fdctrl_t;
+void pc_basic_device_init(qemu_irq *i8259,
+ struct fdctrl_t **floppy_controller,
+ RTCState **rtc_state);
+void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic);
+#ifdef HAS_AUDIO
+void audio_init (PCIBus *pci_bus, qemu_irq *pic);
+#endif
+void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+ const char *boot_device, BlockDriverState **hd_table,
+ struct fdctrl_t *floppy_controller, RTCState *s);
+void pc_pci_device_init(PCIBus *pci_bus);
+
void ioport_set_a20(int enable);
int ioport_get_a20(void);
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
new file mode 100644
index 0000000..59941f5
--- /dev/null
+++ b/hw/pc_piix.c
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "fdc.h"
+#include "pci.h"
+#include "block.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"
+
+#define MAX_IDE_BUS 2
+
+static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
+static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
+static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
+
+/* PC hardware initialisation */
+static void pc_init1(ram_addr_t ram_size,
+ const char *boot_device,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename,
+ int pci_enabled, const char *cpu_model)
+{
+ int i;
+ ram_addr_t below_4g_mem_size, above_4g_mem_size;
+ PCIBus *pci_bus;
+ static PCIDevice *i440fx_state;
+ int piix3_devfn = -1;
+ qemu_irq *cpu_irq;
+ qemu_irq *i8259;
+ int index;
+ BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+ fdctrl_t *floppy_controller;
+ RTCState *rtc_state;
+
+ pc_cpus_init(cpu_model);
+
+ vmport_init();
+
+ /* allocate ram and load rom/bios */
+ pc_memory_init(ram_size, kernel_filename, kernel_cmdline, initrd_filename,
+ &below_4g_mem_size, &above_4g_mem_size);
+
+ cpu_irq = pc_allocte_cpu_irq();
+ i8259 = i8259_init(cpu_irq[0]);
+ pc_register_ferr_irq(i8259[13]);
+
+ if (pci_enabled) {
+ pci_bus = i440fx_init(&i440fx_state, i8259);
+ piix3_devfn = piix3_init(pci_bus, -1);
+ } else {
+ pci_bus = NULL;
+ }
+
+ pc_vga_init(pci_enabled? pci_bus: NULL);
+
+ /* init basic PC hardware */
+ pc_basic_device_init(i8259, &floppy_controller, &rtc_state);
+
+ if (pci_enabled) {
+ IOAPICState *ioapic = ioapic_init();
+ pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
+ }
+
+ watchdog_pc_init(pci_bus);
+
+ for(i = 0; i < nb_nics; i++) {
+ NICInfo *nd = &nd_table[i];
+
+ if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
+ pc_init_ne2k_isa(nd, i8259);
+ else
+ pci_nic_init(pci_bus, nd, -1, "ne2k_pci");
+ }
+
+ piix4_acpi_system_hot_add_init();
+
+ if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+ fprintf(stderr, "qemu: too many IDE bus\n");
+ exit(1);
+ }
+
+ for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+ index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+ if (index != -1)
+ hd[i] = drives_table[index].bdrv;
+ else
+ hd[i] = NULL;
+ }
+
+ if (pci_enabled) {
+ pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1, i8259);
+ } else {
+ for(i = 0; i < MAX_IDE_BUS; i++) {
+ isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
+ hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
+ }
+ }
+
+#ifdef HAS_AUDIO
+ audio_init(pci_enabled ? pci_bus : NULL, i8259);
+#endif
+
+ pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd,
+ floppy_controller, rtc_state);
+
+ if (pci_enabled && usb_enabled) {
+ usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
+ }
+
+ if (pci_enabled && acpi_enabled) {
+ uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
+ i2c_bus *smbus;
+
+ /* TODO: Populate SPD eeprom data. */
+ smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, i8259[9]);
+ for (i = 0; i < 8; i++) {
+ DeviceState *eeprom;
+ eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
+ qdev_set_prop_int(eeprom, "address", 0x50 + i);
+ qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
+ qdev_init(eeprom);
+ }
+ }
+
+ if (i440fx_state) {
+ i440fx_init_memory_mappings(i440fx_state);
+ }
+
+ if (pci_enabled) {
+ pc_pci_device_init(pci_bus);
+ }
+}
+
+static void pc_init_pci(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)
+{
+ pc_init1(ram_size, boot_device,
+ kernel_filename, kernel_cmdline,
+ initrd_filename, 1, cpu_model);
+}
+
+static void pc_init_isa(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)
+{
+ pc_init1(ram_size, boot_device,
+ kernel_filename, kernel_cmdline,
+ initrd_filename, 0, cpu_model);
+}
+
+static QEMUMachine pc_machine = {
+ .name = "pc",
+ .desc = "Standard PC",
+ .init = pc_init_pci,
+ .max_cpus = 255,
+ .is_default = 1,
+};
+
+static QEMUMachine isapc_machine = {
+ .name = "isapc",
+ .desc = "ISA-only PC",
+ .init = pc_init_isa,
+ .max_cpus = 1,
+};
+
+static void pc_machine_init(void)
+{
+ qemu_register_machine(&pc_machine);
+ qemu_register_machine(&isapc_machine);
+}
+
+machine_init(pc_machine_init);
--
1.6.0.2
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [Qemu-devel] [PATCH] q35 chipset based pc. wip.
2009-06-18 10:56 [Qemu-devel] [PATCH 00/18] split out piix specific part from pc emulator Isaku Yamahata
` (17 preceding siblings ...)
2009-06-18 10:57 ` [Qemu-devel] [PATCH 18/18] pc.c: split out piix specific part from pc.c into pc_piix.c Isaku Yamahata
@ 2009-06-18 11:00 ` Isaku Yamahata
18 siblings, 0 replies; 21+ messages in thread
From: Isaku Yamahata @ 2009-06-18 11:00 UTC (permalink / raw)
To: qemu-devel
This patch is under work in progres as it I haven't successed to boot yet.
This patch is sent out to show the intention of the series of patches.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
--
Makefile.target | 1
hw/acpi_ich9.c | 542 +++++++++++++++++++++++++++++++++++++++++++++++++++
hw/acpi_ich9.h | 53 +++++
hw/pc_q35.c | 199 ++++++++++++++++++
hw/pci.h | 60 +++++
hw/pci_ids.h | 25 ++
hw/q35.c | 587 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/q35.h | 213 ++++++++++++++++++++
hw/q35_smbus.c | 177 ++++++++++++++++
9 files changed, 1850 insertions(+), 7 deletions(-)
diff --git a/Makefile.target b/Makefile.target
index 4d0d01f..722c818 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -574,6 +574,7 @@ OBJS+= ide.o pckbd.o vga.o $(SOUND_HW) dma.o
OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
OBJS+= cirrus_vga.o apic.o ioapic.o parallel.o acpi.o piix_pci.o
OBJS+= pc_piix.o acpi_piix4.o pc_smbus.o pc_apm.o
+OBJS+= pc_q35.o q35.o q35_smbus.o acpi_ich9.o
OBJS+= usb-uhci.o vmmouse.o vmport.o vmware_vga.o hpet.o
OBJS += device-hotplug.o pci-hotplug.o smbios.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
diff --git a/hw/acpi_ich9.c b/hw/acpi_ich9.c
new file mode 100644
index 0000000..83642f8
--- /dev/null
+++ b/hw/acpi_ich9.c
@@ -0,0 +1,542 @@
+/*
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+/*
+ * 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(fmt, ## __VA_ARGS__); } while (0)
+#else
+#define ICH9_DEBUG(fmt, ...) do { } while (0)
+#endif
+
+/* XXX where does the constant, ACPI_DBG_IO_ADDR, come from */
+#define ACPI_DBG_IO_ADDR 0xb044
+static void acpi_dbg_writel(void *opaqe, uint32_t addr, uint32_t val)
+{
+ ICH9_DEBUG("%s: 0x%08x\n", __func__, val);
+}
+
+void acpi_dbg_init(void); /* XXX */
+void acpi_dbg_init(void)
+{
+ register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, NULL);
+}
+
+
+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 gpe_ioport_writeb(struct ich9_lpc_pm_regs *pm,
+ uint32_t addr, uint32_t val);
+static uint32_t gpe_ioport_readb(struct ich9_lpc_pm_regs *pm,
+ uint32_t addr);
+
+#define ACPI_ENABLE 0x2
+#define ACPI_DISABLE 0x3
+
+static struct ich9_lpc_pm_regs *pm_state;
+
+static uint32_t get_pmtmr(struct ich9_lpc_pm_regs *pm)
+{
+ uint32_t d;
+ d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, ticks_per_sec);
+ return d & 0xffffff;
+}
+
+static int get_pm1_sts(struct ich9_lpc_pm_regs *pm)
+{
+ int64_t d;
+ int pm1_sts;
+ pm1_sts = pm->pm1_sts;
+ d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, ticks_per_sec);
+ if (d >= pm->tmr_overflow_time)
+ pm->pm1_sts |= ACPI_BITMASK_TIMER_STATUS;
+ return pm->pm1_sts;
+}
+
+static void pm_update_sci(struct ich9_lpc_pm_regs *pm)
+{
+ int sci_level, pm1_sts;
+ int64_t expire_time;
+
+ pm1_sts = get_pm1_sts(pm);
+ sci_level = (((pm1_sts & pm->pm1_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 */
+ if ((pm->pm1_en & ACPI_BITMASK_TIMER_ENABLE) &&
+ !(pm1_sts & ACPI_BITMASK_TIMER_STATUS)) {
+ expire_time = muldiv64(pm->tmr_overflow_time, ticks_per_sec,
+ PM_TIMER_FREQUENCY);
+ qemu_mod_timer(pm->tmr_timer, expire_time);
+ } else {
+ qemu_del_timer(pm->tmr_timer);
+ }
+}
+
+static void pm_tmr_timer(void *opaque)
+{
+ struct ich9_lpc_pm_regs *pm = opaque;
+ pm_update_sci(pm);
+}
+
+static void pm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ struct ich9_lpc_pm_regs *pm = opaque;
+
+ addr &= ICH9_PMIO_MASK;
+ switch (addr) {
+ case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + 7):
+ case ICH9_PMIO_GPE0_EN ... (ICH9_PMIO_GPE0_EN + 7):
+ gpe_ioport_writeb(pm, addr, val);
+ break;
+ default:
+ break;
+ }
+
+ ICH9_DEBUG("%s port=0x%04x val=0x%04x\n", __func__, addr, val);
+
+}
+
+static uint32_t pm_ioport_readb(void *opaque, uint32_t addr)
+{
+ struct ich9_lpc_pm_regs *pm = opaque;
+ uint32_t val = 0;
+
+ addr &= ICH9_PMIO_MASK;
+ switch(addr) {
+ case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + 7):
+ case ICH9_PMIO_GPE0_EN ... (ICH9_PMIO_GPE0_EN + 7):
+ val = gpe_ioport_readb(pm, addr);
+ break;
+ default:
+ val = 0;
+ break;
+ }
+ ICH9_DEBUG("%s port=0x%04x val=0x%04x\n", __func__, addr, val);
+ return val;
+}
+
+static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
+{
+ struct ich9_lpc_pm_regs *pm = opaque;
+
+ addr &= ICH9_PMIO_MASK;
+ switch(addr) {
+ case ICH9_PMIO_PM1_STS:
+ {
+ int64_t d;
+ int pm1_sts;
+ pm1_sts = get_pm1_sts(pm);
+ if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
+ /* if TMRSTS is reset, then compute the new overflow time */
+ d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY,
+ ticks_per_sec);
+ pm->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
+ }
+ pm->pm1_sts &= ~val;
+ pm_update_sci(pm);
+ }
+ break;
+ case ICH9_PMIO_PM1_EN:
+ pm->pm1_en = val;
+ pm_update_sci(pm);
+ break;
+ case ICH9_PMIO_PM1_CNT:
+ {
+ int sus_typ;
+ pm->pm1_cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE);
+ if (val & ACPI_BITMASK_SLEEP_ENABLE) {
+ /* change suspend type */
+ sus_typ = (val >> 10) & 7;
+ switch(sus_typ) {
+ case 0: /* soft power off */
+ qemu_system_shutdown_request();
+ break;
+ case 1:
+ /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
+ Pretend that resume was caused by power button */
+ pm->pm1_sts |= (ACPI_BITMASK_WAKE_STATUS |
+ ACPI_BITMASK_POWER_BUTTON_STATUS);
+ qemu_system_reset_request();
+#if defined(TARGET_I386)
+ cmos_set_s3_resume();
+#endif
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ pm_ioport_write_fallback(opaque, addr, 2, val);
+ break;
+ }
+ ICH9_DEBUG("%s port=0x%04x val=0x%04x\n", __func__, addr, val);
+}
+
+static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
+{
+ struct ich9_lpc_pm_regs *pm = opaque;
+ uint32_t val;
+
+ addr &= ICH9_PMIO_MASK;
+ switch(addr) {
+ case ICH9_PMIO_PM1_STS:
+ val = get_pm1_sts(pm);
+ break;
+ case ICH9_PMIO_PM1_EN:
+ val = pm->pm1_en;
+ break;
+ case ICH9_PMIO_PM1_CNT:
+ val = pm->pm1_cnt;
+ break;
+ default:
+ val = pm_ioport_read_fallback(opaque, addr, 2);
+ break;
+ }
+ ICH9_DEBUG("%s port=0x%04x val=0x%04x\n", __func__, addr, val);
+ return val;
+}
+
+static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+ // struct ich9_lpc_pm_regs *pm = opaque;
+
+ addr &= ICH9_PMIO_MASK;
+ switch(addr) {
+ default:
+ pm_ioport_write_fallback(opaque, addr, 4, val);
+ break;
+ }
+ ICH9_DEBUG("%s port=0x%04x val=0x%08x\n", __func__, addr, val);
+}
+
+static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
+{
+ struct ich9_lpc_pm_regs *pm = opaque;
+ uint32_t val;
+
+ addr &= ICH9_PMIO_MASK;
+ switch(addr) {
+ case ICH9_PMIO_PM1_TMR:
+ val = get_pmtmr(pm);
+ break;
+
+ default:
+ val = pm_ioport_read_fallback(opaque, addr, 4);
+ break;
+ }
+ ICH9_DEBUG("%s port=0x%04x val=0x%08x\n", __func__, 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(struct ich9_lpc_pm_regs *pm, uint32_t pm_io_base)
+{
+ /* XXX: need to improve memory and ioport allocation */
+ ICH9_DEBUG("%s to 0x%x\n", __func__, 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);
+
+ /* XXX: tmp hack */
+ 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;
+}
+
+void ich9_pm_save(QEMUFile* f, struct ich9_lpc_pm_regs *pm)
+{
+ qemu_put_be16s(f, &pm->pm1_sts);
+ qemu_put_be16s(f, &pm->pm1_en);
+ qemu_put_be16s(f, &pm->pm1_cnt);
+ qemu_put_timer(f, pm->tmr_timer);
+ qemu_put_be64(f, pm->tmr_overflow_time);
+ qemu_put_be64s(f, &pm->gpe0_sts);
+ qemu_put_be64s(f, &pm->gpe0_en);
+ qemu_put_be32s(f, &pm->smi_en);
+ qemu_put_be32s(f, &pm->smi_sts);
+}
+
+void ich9_pm_load(QEMUFile* f, struct ich9_lpc_pm_regs *pm, int version_id)
+{
+ qemu_get_be16s(f, &pm->pm1_sts);
+ qemu_get_be16s(f, &pm->pm1_en);
+ qemu_get_be16s(f, &pm->pm1_cnt);
+ qemu_get_timer(f, pm->tmr_timer);
+ pm->tmr_overflow_time = qemu_get_be64(f);
+ qemu_get_be64s(f, &pm->gpe0_sts);
+ qemu_get_be64s(f, &pm->gpe0_en);
+ qemu_get_be32s(f, &pm->smi_en);
+ qemu_get_be32s(f, &pm->smi_sts);
+}
+
+static void pm_reset(void *opaque)
+{
+ //struct ich9_lpc_pm_regs *pm = opaque;
+ /* XXX:TODO */
+}
+
+#if defined(TARGET_I386)
+static void pm_powerdown(void *arg)
+{
+ struct ich9_lpc_pm_regs *pm = (struct ich9_lpc_pm_regs*) arg;
+
+ if (pm->pm1_en & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
+ pm->pm1_sts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
+ pm_update_sci(pm);
+ }
+}
+#endif
+
+void ich9_pm_init(struct ich9_lpc_pm_regs *pm, qemu_irq sci_irq)
+{
+ pm->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, pm);
+
+ pm->irq = sci_irq;
+ qemu_register_reset(pm_reset, 0, pm);
+ qemu_system_powerdown_register(pm_powerdown, pm_state);
+}
+
+/* GPE */
+static uint8_t *gpe_ioport_get_ptr(struct ich9_lpc_pm_regs *pm, uint32_t addr)
+{
+ uint8_t *cur = NULL;
+
+ switch (addr) {
+ case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + 7):
+ cur = (uint8_t*)&pm->gpe0_sts;
+ cur += addr - ICH9_PMIO_GPE0_STS;
+ break;
+ case ICH9_PMIO_GPE0_EN ... (ICH9_PMIO_GPE0_EN + 7):
+ cur = (uint8_t*)&pm->gpe0_en;
+ cur += addr - ICH9_PMIO_GPE0_EN;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ return cur;
+}
+
+static void gpe_ioport_writeb(struct ich9_lpc_pm_regs *pm,
+ uint32_t addr, uint32_t val)
+{
+ uint8_t *cur = gpe_ioport_get_ptr(pm, addr);
+
+ val &= 0xff;
+ switch (addr) {
+ case ICH9_PMIO_GPE0_STS ... (ICH9_PMIO_GPE0_STS + 7):
+ *cur = (*cur) & ~val;
+ break;
+ case ICH9_PMIO_GPE0_EN ... (ICH9_PMIO_GPE0_EN + 7):
+ *cur = val;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ ICH9_DEBUG("%s %x <== %d\n", __func__, addr, val);
+}
+
+static uint32_t gpe_ioport_readb(struct ich9_lpc_pm_regs *pm,
+ uint32_t addr)
+{
+ uint8_t *cur = gpe_ioport_get_ptr(pm, addr);
+ uint32_t val = 0;
+
+ if (cur != NULL)
+ val = *cur;
+
+ ICH9_DEBUG("%s %x == %x\n", __func__, addr, val);
+ return val;
+}
+
+#if 0
+/* XXX TODO */
+#define PCI_BASE 0xae00
+#define PCI_EJ_BASE 0xae08
+
+struct pci_status {
+ uint32_t up;
+ uint32_t down;
+};
+
+static struct pci_status pci0_status;
+
+
+static uint32_t pcihotplug_read(void *opaque, uint32_t addr)
+{
+ uint32_t val = 0;
+ struct pci_status *g = opaque;
+ switch (addr) {
+ case PCI_BASE:
+ val = g->up;
+ break;
+ case PCI_BASE + 4:
+ val = g->down;
+ break;
+ default:
+ break;
+ }
+
+ ICH9_DEBUG("%s %x == %x\n", __func__, addr, val);
+ return val;
+}
+
+static void pcihotplug_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ struct pci_status *g = opaque;
+ switch (addr) {
+ case PCI_BASE:
+ g->up = val;
+ break;
+ case PCI_BASE + 4:
+ g->down = val;
+ break;
+ }
+
+ ICH9_DEBUG("%s %x <== %d\n", __func__, addr, val);
+}
+
+static uint32_t pciej_read(void *opaque, uint32_t addr)
+{
+ ICH9_DEBUG("%s %x\n", __func__, addr);
+ return 0;
+}
+
+static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
+{
+#if defined (TARGET_I386)
+ int slot = ffs(val) - 1;
+
+ pci_device_hot_remove_success(0, slot);
+#endif
+
+ ICH9_DEBUG("%s %x <== %d\n", __func__, addr, val);
+}
+
+
+void ich9_hot_add_init(void)
+{
+ register_ioport_write(PCI_BASE, 8, 4, pcihotplug_write, &pci0_status);
+ register_ioport_read(PCI_BASE, 8, 4, pcihotplug_read, &pci0_status);
+
+ register_ioport_write(PCI_EJ_BASE, 4, 4, pciej_write, NULL);
+ register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, NULL);
+}
+
+static void enable_device(struct pci_status *p, struct gpe_regs *g, int slot)
+{
+ g->sts |= 2;
+ p->up |= (1 << slot);
+}
+
+static void disable_device(struct pci_status *p, struct gpe_regs *g, int slot)
+{
+ g->sts |= 2;
+ p->down |= (1 << slot);
+}
+
+void qemu_system_device_hot_add(int bus, int slot, int state)
+{
+ pci0_status.up = 0;
+ pci0_status.down = 0;
+ if (state)
+ enable_device(&pci0_status, &gpe, slot);
+ else
+ disable_device(&pci0_status, &gpe, slot);
+ if (gpe.en & 2) {
+ qemu_set_irq(pm_state->irq, 1);
+ qemu_set_irq(pm_state->irq, 0);
+ }
+}
+#else
+static void ich9_device_hot_add(int bus, int slot, int state)
+{
+ /* stub */
+}
+
+void ich9_hot_add_init(void)
+{
+ /* stub */
+
+ qemu_system_device_hot_add_register(ich9_device_hot_add);
+}
+#endif
diff --git a/hw/acpi_ich9.h b/hw/acpi_ich9.h
new file mode 100644
index 0000000..57a4bfe
--- /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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+
+#ifndef HW_ACPI_ICH9_H
+#define HW_ACPI_ICH9_H
+
+#include <stdint.h>
+
+struct ich9_lpc_pm_regs {
+ uint16_t pm1_sts;
+ uint16_t pm1_en;
+
+ /*
+ * 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.
+ */
+ uint16_t pm1_cnt;
+
+ /* uint32_t pm1_tmr; */
+ QEMUTimer *tmr_timer;
+ int64_t tmr_overflow_time;
+
+ uint64_t gpe0_sts;
+ uint64_t gpe0_en;
+
+ uint32_t smi_en;
+ uint32_t smi_sts;
+
+ qemu_irq irq; /* SCI */
+
+ uint32_t pm_io_base;
+};
+
+#endif /* HW_ACPI_ICH9_H */
diff --git a/hw/pc_q35.c b/hw/pc_q35.c
new file mode 100644
index 0000000..ae539e1
--- /dev/null
+++ b/hw/pc_q35.c
@@ -0,0 +1,199 @@
+/*
+ * Q35 chipset based pc system emulator
+ *
+ * Copyright (c) 2009 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+/*
+ * 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.
+ */
+#include "hw.h"
+#include "pc.h"
+#include "fdc.h"
+#include "pci.h"
+#include "block.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 "q35.h"
+
+#define MAX_IDE_BUS 2
+
+static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
+static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
+static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
+
+/* 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)
+{
+ int i;
+ ram_addr_t below_4g_mem_size, above_4g_mem_size;
+ PCIBus *host_bus;
+ PCIBus *pci_bus;
+ static PCIDevice *gmch_state;
+ int ich9_lpc_devfn = -1;
+ qemu_irq *cpu_irq;
+ qemu_irq *i8259;
+ int index;
+ BlockDriverState *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+ IOAPICState *ioapic;
+ fdctrl_t *floppy_controller;
+ RTCState *rtc_state;
+
+ pc_cpus_init(cpu_model);
+
+ vmport_init();
+
+ /* allocate ram and load rom/bios */
+ pc_memory_init(ram_size, kernel_filename, kernel_cmdline, initrd_filename,
+ &below_4g_mem_size, &above_4g_mem_size);
+
+
+ cpu_irq = pc_allocte_cpu_irq();
+ i8259 = i8259_init(cpu_irq[0]);
+ pc_register_ferr_irq(i8259[13]);
+
+ host_bus = gmch_init(&gmch_state, i8259);
+ ich9_lpc_devfn = ich9_lpc_init(host_bus, PCI_DEVFN(ICH9_LPC_DEV,
+ ICH9_LPC_FUNC), i8259);
+ pci_bus = ich9_d2pbr_init(host_bus, PCI_DEVFN(ICH9_D2P_BRIDGE_DEV,
+ ICH9_D2P_BRIDGE_FUNC),
+ ICH9_D2P_SECONDARY_DEFAULT);
+
+ pc_vga_init(pci_bus);
+
+ /* init basic PC hardware */
+ pc_basic_device_init(i8259, &floppy_controller, &rtc_state);
+
+ ioapic = ioapic_init();
+ pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
+
+#if 0
+ if (pci_device_init() < 0) {
+ exit(1);
+ }
+#endif
+
+ watchdog_pc_init(pci_bus);
+
+ for(i = 0; i < nb_nics; i++) {
+ NICInfo *nd = &nd_table[i];
+
+ pci_nic_init(pci_bus, nd, -1, "ne2k_pci");
+ }
+
+ ich9_hot_add_init(); /* XXX */
+
+ if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
+ fprintf(stderr, "qemu: too many IDE bus\n");
+ exit(1);
+ }
+
+ for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
+ index = drive_get_index(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+ if (index != -1)
+ hd[i] = drives_table[index].bdrv;
+ else
+ hd[i] = NULL;
+ }
+
+ /* XXX ich9 supports only SATA */
+ pci_piix3_ide_init(host_bus, hd, -1, i8259);
+
+#ifdef HAS_AUDIO
+ audio_init(pci_bus, i8259);
+#endif
+
+ pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd,
+ floppy_controller, rtc_state);
+
+ if (usb_enabled) {
+ /* XXX: make ich9 specific add usb_uchi_ich9_init() */
+ usb_uhci_piix4_init(host_bus, -1);
+ }
+
+ if (acpi_enabled) {
+ uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
+ i2c_bus *smbus;
+
+ /* TODO: Populate SPD eeprom data. */
+ /* XXX determine proper smb_io_base */
+ smbus = ich9_smb_init(pci_bus, ich9_lpc_devfn + 3, 0xb100);
+ for (i = 0; i < 8; i++) {
+ DeviceState *eeprom;
+ eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
+ qdev_set_prop_int(eeprom, "address", 0x50 + i);
+ qdev_set_prop_ptr(eeprom, "data", eeprom_buf + (i * 256));
+ qdev_init(eeprom);
+ }
+ }
+
+ if (gmch_state) {
+ gmch_init_memory_mappings(gmch_state);
+ }
+
+ 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.h b/hw/pci.h
index c14ab0f..6c6ddc3 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -161,11 +161,21 @@ typedef struct PCIIORegion {
/* Bits in the PCI Status Register (PCI 2.3 spec) */
#define PCI_STATUS_RESERVED1 0x007
#define PCI_STATUS_INT_STATUS 0x008
-#define PCI_STATUS_CAPABILITIES 0x010
-#define PCI_STATUS_66MHZ 0x020
-#define PCI_STATUS_RESERVED2 0x040
-#define PCI_STATUS_FAST_BACK 0x080
+#define PCI_STATUS_CAPABILITIES 0x10 /* Support Capability List */
+#define PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */
+#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */
+#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */
+#define PCI_STATUS_PARITY 0x100 /* Detected parity error */
#define PCI_STATUS_DEVSEL 0x600
+#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */
+#define PCI_STATUS_DEVSEL_FAST 0x000
+#define PCI_STATUS_DEVSEL_MEDIUM 0x200
+#define PCI_STATUS_DEVSEL_SLOW 0x400
+#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */
+#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */
+#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */
+#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */
+#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */
#define PCI_STATUS_RESERVED_MASK_LO (PCI_STATUS_RESERVED1 | \
PCI_STATUS_INT_STATUS | PCI_STATUS_CAPABILITIES | \
@@ -347,22 +357,58 @@ int pci_assign_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp);
void pci_info(Monitor *mon);
+static inline uint8_t
+pci_config_get8(uint8_t *pci_config, uint32_t addr)
+{
+ return pci_config[addr];
+}
+
+static inline uint16_t
+pci_config_get16(uint8_t *pci_config, uint32_t addr)
+{
+ return le16_to_cpup((uint16_t *)&pci_config[addr]);
+}
+
+static inline uint32_t
+pci_config_get32(uint8_t *pci_config, uint32_t addr)
+{
+ return le32_to_cpup((uint32_t *)&pci_config[addr]);
+}
+
+static inline void
+pci_config_set8(uint8_t *pci_config, uint32_t addr, uint8_t val)
+{
+ pci_config[addr] = val;
+}
+
+static inline void
+pci_config_set16(uint8_t *pci_config, uint32_t addr, uint16_t val)
+{
+ cpu_to_le16wu((uint16_t *)&pci_config[addr], val);
+}
+
+static inline void
+pci_config_set32(uint8_t *pci_config, uint32_t addr, uint32_t val)
+{
+ cpu_to_le32wu((uint32_t *)&pci_config[addr], val);
+}
+
static inline void
pci_config_set_vendor_id(uint8_t *pci_config, uint16_t val)
{
- cpu_to_le16wu((uint16_t *)&pci_config[PCI_VENDOR_ID], val);
+ pci_config_set16(pci_config, PCI_VENDOR_ID, val);
}
static inline void
pci_config_set_device_id(uint8_t *pci_config, uint16_t val)
{
- cpu_to_le16wu((uint16_t *)&pci_config[PCI_DEVICE_ID], val);
+ pci_config_set16(pci_config, PCI_DEVICE_ID, val);
}
static inline void
pci_config_set_class(uint8_t *pci_config, uint16_t val)
{
- cpu_to_le16wu((uint16_t *)&pci_config[PCI_CLASS_DEVICE], val);
+ pci_config_set16(pci_config, PCI_CLASS_DEVICE, val);
}
typedef void (*pci_qdev_initfn)(PCIDevice *dev);
diff --git a/hw/pci_ids.h b/hw/pci_ids.h
index f7d0387..4eb6d07 100644
--- a/hw/pci_ids.h
+++ b/hw/pci_ids.h
@@ -33,6 +33,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
@@ -40,6 +41,18 @@
#define PCI_CLASS_PROCESSOR_CO 0x0b40
#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20
+#define PCI_BASE_CLASS_SERIAL 0x0c
+#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00
+#define PCI_CLASS_SERIAL_FIREWIRE_OHCI 0x0c0010
+#define PCI_CLASS_SERIAL_ACCESS 0x0c01
+#define PCI_CLASS_SERIAL_SSA 0x0c02
+#define PCI_CLASS_SERIAL_USB 0x0c03
+#define PCI_CLASS_SERIAL_USB_UHCI 0x0c0300
+#define PCI_CLASS_SERIAL_USB_OHCI 0x0c0310
+#define PCI_CLASS_SERIAL_USB_EHCI 0x0c0320
+#define PCI_CLASS_SERIAL_FIBER 0x0c04
+#define PCI_CLASS_SERIAL_SMBUS 0x0c05
+
#define PCI_CLASS_OTHERS 0xff
/* Vendors and devices. Sort key: vendor first, device next. */
@@ -97,4 +110,16 @@
#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_Q35_MCH 0x29c0
+
#define PCI_VENDOR_ID_INVALID 0xffff
diff --git a/hw/q35.c b/hw/q35.c
new file mode 100644
index 0000000..beea981
--- /dev/null
+++ b/hw/q35.c
@@ -0,0 +1,587 @@
+/*
+ * QEMU GMCH/ICH9 PCI Bridge Emulation
+ *
+ * Copyright (c) 2009 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+/*
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "pc_apm.h"
+#include "pci.h"
+#include "q35.h"
+
+typedef uint32_t pci_addr_t;
+#include "pci_host.h"
+
+typedef struct GMCHState {
+ PCIHostState host;
+
+ struct PCIDevice *dev;
+} GMCHState;
+
+struct GMCH_PCIDevice {
+ PCIDevice d;
+ GMCHState *gmch;
+
+ target_phys_addr_t isa_page_descs[384 / 4];
+ uint8_t smm_enabled;
+};
+
+static void gmch_addr_writel(void* opaque, uint32_t addr, uint32_t val)
+{
+ GMCHState *s = opaque;
+ s->host.config_reg = val;
+}
+
+static uint32_t gmch_addr_readl(void* opaque, uint32_t addr)
+{
+ GMCHState *s = opaque;
+ return s->host.config_reg;
+}
+
+static void ich9_lpc_set_irq(qemu_irq *pic, int irq_num, int level);
+
+/* return the global irq number corresponding to a given device irq
+ pin. We could also use the bus number to have a more precise
+ mapping. */
+static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+{
+ int slot_addend;
+ slot_addend = (pci_dev->devfn >> 3) - 1;
+ return (irq_num + slot_addend) & 3;
+}
+
+static target_phys_addr_t isa_page_descs[384 / 4];
+
+static target_phys_addr_t isa_page_descs_get(uint32_t addr)
+{
+ return isa_page_descs[
+ (addr - Q35_HOST_BRIDGE_SMARM_C_BASE) >> TARGET_PAGE_BITS];
+}
+
+static void update_pam(PCIDevice *d, uint32_t start, uint8_t r)
+{
+ uint32_t addr;
+
+ // printf("ISA mapping %08x-0x%08x: %d\n", start, end, r);
+ switch(r) {
+ case Q35_HOST_BRIDGE_PAM_WE | Q35_HOST_BRIDGE_PAM_RE:
+ /* RAM */
+ cpu_register_physical_memory(start, Q35_HOST_BRIDGE_PAM_AREA_SIZE,
+ start);
+ break;
+
+ case Q35_HOST_BRIDGE_PAM_RE:
+ /* ROM (XXX: not quite correct) */
+ cpu_register_physical_memory(start, Q35_HOST_BRIDGE_PAM_AREA_SIZE,
+ start | IO_MEM_ROM);
+ break;
+
+ case Q35_HOST_BRIDGE_PAM_WE:
+ case 0:
+ /* XXX: should distinguish read/write cases */
+ for(addr = start; addr < start + Q35_HOST_BRIDGE_PAM_AREA_SIZE;
+ addr += TARGET_PAGE_SIZE) {
+ cpu_register_physical_memory(addr, TARGET_PAGE_SIZE,
+ isa_page_descs_get(addr));
+ }
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+}
+
+static uint8_t gmch_get_pam_attr(PCIDevice *d, uint32_t addr, int hi)
+{
+ return (d->config[addr] >> ((!!hi) * 4)) & Q35_HOST_BRIDGE_PAM_MASK;
+}
+
+static void gmch_update_pam(PCIDevice *d, int pam)
+{
+ uint32_t conf_addr = Q35_HOST_BRIDGE_PAM0 + pam;
+ uint32_t phys_addr;
+
+ assert(0 <= pam && pam <= 6);
+
+ if (pam == 0) {
+ update_pam(d, Q35_HOST_BRIDGE_PAM_BIOS_AREA,
+ gmch_get_pam_attr(d, conf_addr, 1));
+ return;
+ }
+
+ phys_addr = Q35_HOST_BRIDGE_PAM_EXPAN_AREA +
+ Q35_HOST_BRIDGE_PAM_EXPAN_AREA * (pam - 1) * 2;
+ update_pam(d, phys_addr, gmch_get_pam_attr(d, conf_addr, 0));
+
+ phys_addr += Q35_HOST_BRIDGE_PAM_AREA_SIZE;
+ update_pam(d, phys_addr, gmch_get_pam_attr(d, conf_addr, 1));
+}
+
+static void gmch_update_memory_mappings(PCIDevice *d)
+{
+ int i;
+
+ for (i = 0; i < 7; i++)
+ gmch_update_pam(d, i);
+}
+
+static void gmch_update_smram(PCIDevice *d)
+{
+ struct GMCH_PCIDevice *gd = (struct GMCH_PCIDevice*)d;
+ uint32_t smram;
+ uint32_t addr;
+
+ smram = d->config[Q35_HOST_BRDIGE_SMRAM];
+ if ((gd->smm_enabled && (smram & Q35_HOST_BRIDGE_SMRAM_G_SMRAME)) ||
+ (smram & Q35_HOST_BRIDGE_SMRAM_D_OPEN)) {
+ cpu_register_physical_memory(Q35_HOST_BRIDGE_SMARM_C_BASE,
+ Q35_HOST_BRIDGE_SMRAM_C_SIZE,
+ Q35_HOST_BRIDGE_SMARM_C_BASE);
+ } else {
+ for(addr = Q35_HOST_BRIDGE_SMARM_C_BASE;
+ addr < Q35_HOST_BRIDGE_SMRAM_C_END;
+ addr += TARGET_PAGE_SIZE) {
+ cpu_register_physical_memory(addr, TARGET_PAGE_SIZE,
+ isa_page_descs_get(addr));
+ }
+ }
+}
+
+static void gmch_set_smm(int smm, void *arg)
+{
+ uint8_t val = (smm != 0);
+ struct GMCH_PCIDevice *gd = (struct GMCH_PCIDevice*)arg;
+
+ if (gd->smm_enabled != val) {
+ gd->smm_enabled = val;
+ gmch_update_smram(&gd->d);
+ }
+}
+
+/* XXX: suppress when better memory API. We make the assumption that
+ no device (in particular the VGA) changes the memory mappings in
+ the 0xa0000-0x100000 =
+ [Q35_HOST_BRIDGE_SMARM_C_BASE, Q35_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END)
+ range */
+void gmch_init_memory_mappings(PCIDevice *d)
+{
+ int i;
+ for(i = 0; i < 96; i++) {
+ isa_page_descs[i] = cpu_get_physical_page_desc(Q35_HOST_BRIDGE_SMARM_C_BASE + i * 0x1000);
+ }
+}
+
+static void gmch_write_config(PCIDevice *d,
+ uint32_t address, uint32_t val, int len)
+{
+ /* XXX: implement SMRAM.D_LOCK */
+ pci_default_write_config(d, address, val, len);
+ if ((address >= 0x59 && address <= 0x5f))
+ gmch_update_memory_mappings(d);
+
+ if (address <= Q35_HOST_BRDIGE_SMRAM &&
+ Q35_HOST_BRDIGE_SMRAM <= address + len)
+ gmch_update_smram(d);
+}
+
+static void gmch_save(QEMUFile* f, void *opaque)
+{
+ struct GMCH_PCIDevice *gd = opaque;
+
+ pci_device_save(&gd->d, f);
+ qemu_put_8s(f, &gd->smm_enabled);
+}
+
+static int gmch_load(QEMUFile* f, void *opaque, int version_id)
+{
+ struct GMCH_PCIDevice *gd = opaque;
+ int ret;
+
+ if (version_id > 2)
+ return -EINVAL;
+
+ ret = pci_device_load(&gd->d, f);
+ if (ret < 0)
+ return ret;
+ gmch_update_memory_mappings(&gd->d);
+
+ qemu_get_8s(f, &gd->smm_enabled);
+ gmch_update_smram(&gd->d);
+
+ return 0;
+}
+
+/* host bridge */
+PCIBus *gmch_init(PCIDevice **pgmch_state, qemu_irq *pic)
+{
+ PCIBus *b;
+ PCIDevice *d;
+ struct GMCH_PCIDevice *gd;
+ GMCHState *s;
+
+ s = qemu_mallocz(sizeof(GMCHState));
+ b = pci_register_bus(NULL, "pci",
+ ich9_lpc_set_irq, pci_slot_get_pirq, pic, 0,
+ 8 /* PIRQ A-H */);
+ s->host.bus = b;
+
+ register_ioport_write(Q35_HOST_BRIDGE_CONFIG_ADDR,
+ 4, 4, gmch_addr_writel, s);
+ register_ioport_read(Q35_HOST_BRIDGE_CONFIG_ADDR,
+ 4, 4, gmch_addr_readl, s);
+
+ register_ioport_write(Q35_HOST_BRIDGE_CONFIG_DATA,
+ 4, 1, pci_host_data_writeb, s);
+ register_ioport_write(Q35_HOST_BRIDGE_CONFIG_DATA,
+ 4, 2, pci_host_data_writew, s);
+ register_ioport_write(Q35_HOST_BRIDGE_CONFIG_DATA,
+ 4, 4, pci_host_data_writel, s);
+ register_ioport_read(Q35_HOST_BRIDGE_CONFIG_DATA,
+ 4, 1, pci_host_data_readb, s);
+ register_ioport_read(Q35_HOST_BRIDGE_CONFIG_DATA,
+ 4, 2, pci_host_data_readw, s);
+ register_ioport_read(Q35_HOST_BRIDGE_CONFIG_DATA,
+ 4, 4, pci_host_data_readl, s);
+
+ d = pci_register_device(b, Q35_HOST_BRIDGE,
+ sizeof(struct GMCH_PCIDevice), 0,
+ NULL, gmch_write_config);
+ s->dev = d;
+ gd = (struct GMCH_PCIDevice*)d;
+ gd->gmch = s;
+
+ pci_config_set_vendor_id(d->config, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(d->config, PCI_DEVICE_ID_INTEL_Q35_MCH);
+ d->config[PCI_REVISION_ID] = Q35_HOST_BRIDGE_REVISION_DEFUALT;
+ pci_config_set_class(d->config, PCI_CLASS_BRIDGE_HOST);
+ d->config[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL;
+
+ d->config[Q35_HOST_BRDIGE_SMRAM] = Q35_HOST_BRIDGE_SMRAM_DEFAULT;
+
+ register_savevm(Q35_HOST_BRIDGE, 0, 2, gmch_save, gmch_load, gd);
+ cpu_smm_register(&gmch_set_smm, gd);
+
+ *pgmch_state = d;
+ return b;
+}
+
+/* ICH9 DMI-to-PCI bridge */
+static int ich9_d2pbr_map_irq_fn(PCIDevice *pci_dev, int irq_num)
+{
+ return irq_num;
+}
+
+static void ich9_d2pbr_reset(PCIDevice *d)
+{
+ uint8_t *pci_conf = d->config;
+
+ pci_config_set16(pci_conf, PCI_COMMAND,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ pci_config_set16(pci_conf, PCI_STATUS,
+ PCI_STATUS_DEVSEL_MEDIUM);
+}
+
+static void ich9_d2pbr_save(QEMUFile* f, void *opaque)
+{
+ PCIDevice *d = opaque;
+ pci_device_save(d, f);
+}
+
+static int ich9_d2pbr_load(QEMUFile* f, void *opaque, int version_id)
+{
+ PCIDevice *d = opaque;
+ if (version_id != 2)
+ return -EINVAL;
+ return pci_device_load(d, f);
+}
+
+PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int secondary_bus_num)
+{
+ PCIBus *b;
+ PCIDevice *d;
+ uint8_t *pci_conf;
+
+ b = pci_bridge_create_simple(bus, devfn,
+ PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_0,
+ ich9_d2pbr_map_irq_fn, ICH9_D2P_BRIDGE,
+ secondary_bus_num);
+ if (b == NULL)
+ return NULL;
+
+ d = pci_bus_to_dev(b);
+ register_savevm(ICH9_D2P_BRIDGE, 0, ICH9_D2P_BRIDGE_SAVEVM_VERSION,
+ ich9_d2pbr_save, ich9_d2pbr_load, d);
+
+ /* some command bits are hotwired to 0 for pcie */
+ pci_conf_initw(d, PCI_COMMAND, d->callback[PCI_COMMAND],
+ PCI_COMMAND_IO |
+ PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER |
+ PCI_COMMAND_PARITY |
+ PCI_COMMAND_SERR);
+
+ pci_conf = d->config;
+
+ pci_config_set8(pci_conf, PCI_REVISION_ID, ICH9_D2P_A2_REVISION);
+
+ // XXX
+ pci_config_set8(pci_conf, PCI_CLASS_INTERFACE,
+ PCI_CLASS_BRDIGE_PCI_INF_SUB);
+ pci_config_set8(pci_conf, PCI_HEADER_TYPE, PCI_HEADER_TYPE_BRIDGE);
+
+ ich9_d2pbr_reset(d);
+ return b;
+}
+
+
+/* ICH9 LPC PCI to ISA bridge */
+struct ICH9_LPCDevice {
+ PCIDevice d;
+
+ int pci_irq_levels[ICH9_LPC_NB_PIRQS];
+
+ APMState apm;
+ struct ich9_lpc_pm_regs pm;
+};
+
+static struct ICH9_LPCDevice *ich9_pci_to_lpc(PCIDevice *d)
+{
+ return (struct ICH9_LPCDevice*)d;
+}
+
+static struct ICH9_LPCDevice *ich9_lpc;
+
+static void ich9_lpc_reset(struct ICH9_LPCDevice *lpc)
+{
+ uint8_t *pci_conf = lpc->d.config;
+ int i;
+
+ pci_config_set16(pci_conf, PCI_COMMAND,
+ PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ /* XXX capability isn't supported yet */
+ pci_config_set16(pci_conf, PCI_STATUS,
+ PCI_STATUS_DEVSEL_MEDIUM /* | PCI_STATUS_CAPABILITIES */);
+
+ for (i = 0; i < 4; i++) {
+ pci_config_set8(pci_conf, ICH9_LPC_PIRQA_ROUT + 1,
+ ICH9_LPC_PIRQ_ROUT_DEFAULT);
+ }
+ for (i = 0; i < 4; i++) {
+ pci_config_set8(pci_conf, ICH9_LPC_PIRQE_ROUT + 1,
+ ICH9_LPC_PIRQ_ROUT_DEFAULT);
+ }
+ pci_config_set32(pci_conf, ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_DEFAULT);
+ pci_config_set32(pci_conf, ICH9_LPC_RCBA, ICH9_LPC_RCBA_DEFAULT);
+}
+
+static int ich9_lpc_pic_irq(struct ICH9_LPCDevice *lpc, int irq_num)
+{
+ switch (irq_num) {
+ case 0 ... 3:
+ return lpc->d.config[ICH9_LPC_PIRQA_ROUT + irq_num];
+ case 4 ... 7:
+ return lpc->d.config[ICH9_LPC_PIRQE_ROUT + (irq_num - 4)];
+ default:
+ break;
+ }
+ assert(0);
+ return 0;
+}
+
+static void ich9_lpc_set_irq(qemu_irq *pic, int irq_num, int level)
+{
+ int i, pic_irq, pic_level;
+
+ assert(0 <= irq_num && irq_num < 8);
+ ich9_lpc->pci_irq_levels[irq_num] = level;
+
+ /* XXX: check ICH9_LPC_PIRQ_ROUT_IRQEN bit */
+
+ /* now we change the pic irq level according to the piix irq mappings */
+ /* XXX: optimize */
+ pic_irq = ich9_lpc_pic_irq(ich9_lpc, irq_num);
+
+ /* XXX: IRQ 16 - 23 */
+ 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 < ICH9_LPC_NB_PIRQS; i++) {
+ if (pic_irq == ich9_lpc_pic_irq(ich9_lpc, i)) {
+ pic_level |= ich9_lpc->pci_irq_levels[i];
+ }
+ }
+ qemu_set_irq(pic[pic_irq], pic_level);
+ }
+}
+
+/* APM */
+static void ich9_apm_ctrl_changed(uint32_t val, void *arg)
+{
+#if 0
+ struct ICH9_LPCDevice *lpc = arg;
+
+ /* XXX: TODO */
+/* FADT ACPI_ENABLE/ACPI_DISABLE */
+#define ICH9_APM_ACPI_ENABLE 0x2
+#define ICH9_APM_ACPI_DISABLE 0x3
+
+ /* ACPI specs 3.0, 4.7.2.5 */
+ if (val == ACPI_ENABLE) {
+ lpc->pmcntrl |= ACPI_BITMASK_SCI_ENABLE;
+ } else if (val == ACPI_DISABLE) {
+ lpc->pmcntrl &= ~ACPI_BITMASK_SCI_ENABLE;
+ }
+#endif
+
+ /* XXX: TODO */
+ /* SMI_EN = PMBASE + 30
+ * SMI control and enable register
+ */
+#if 0
+ if ((SMI_EN register) & APMC_EN) {
+ cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
+ }
+#endif
+}
+
+/* config:PMBASE */
+static void
+ich9_lpc_pmbase_update(PCIDevice *d, uint32_t addr, uint32_t data, int len)
+{
+ uint32_t pm_io_base = pci_config_get32(d->config, ICH9_LPC_PMBASE);
+ pm_io_base &= ICH9_LPC_PMBASE_BASE_ADDRESS_MASK;
+
+ ich9_pm_iospace_update(&ich9_pci_to_lpc(d)->pm, pm_io_base);
+}
+
+static void ich9_lpc_save(QEMUFile* f, void *opaque)
+{
+ struct ICH9_LPCDevice *lpc = opaque;
+ int i;
+
+ pci_device_save(&lpc->d, f);
+
+ for (i = 0; i < ICH9_LPC_NB_PIRQS; i++)
+ qemu_put_be32(f, lpc->pci_irq_levels[i]);
+
+ ich9_pm_save(f, &lpc->pm);
+}
+
+static int ich9_lpc_load(QEMUFile* f, void *opaque, int version_id)
+{
+ struct ICH9_LPCDevice *lpc = opaque;
+ int ret, i;
+
+ ret = pci_device_load(&lpc->d, f);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ICH9_LPC_NB_PIRQS; i++)
+ lpc->pci_irq_levels[i] = qemu_get_be32(f);
+
+ ich9_pm_load(f, &lpc->pm, version_id);
+ ich9_lpc_pmbase_update(&lpc->d,
+ 0, 0, 0 /* don't care those args */);
+ return 0;
+}
+
+static void ich9_set_sci(void *opaque, int irq_num, int level)
+{
+ /* opaque = pic */
+ assert(irq_num == 0);
+ ich9_lpc_set_irq(opaque, 1/* SCI = PIRQB# */, level);
+}
+
+static qemu_irq *ich9_lpc_allocate_sci_irq(qemu_irq *pic)
+{
+ return qemu_allocate_irqs(ich9_set_sci, pic, 1);
+}
+
+int ich9_lpc_init(PCIBus *bus, int devfn, qemu_irq *pic)
+{
+ struct ICH9_LPCDevice *lpc;
+ uint8_t *pci_conf;
+ qemu_irq *sci_irq;
+
+ assert(devfn == PCI_DEVFN(ICH9_LPC_DEV, ICH9_LPC_FUNC));
+
+ lpc = (struct ICH9_LPCDevice*)pci_register_device(bus, ICH9_A2_LPC,
+ sizeof(*lpc), devfn,
+ NULL, NULL);
+ ich9_lpc = lpc;
+ pci_conf = lpc->d.config;
+
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_ICH9_8); // ICH9 LPC
+ pci_config_set8(pci_conf, PCI_REVISION_ID, ICH9_A2_LPC_REVISION);
+ pci_config_set_class(pci_conf, PCI_CLASS_BRIDGE_ISA);
+
+ // header_type = PCI_multifunction, generic
+ pci_config_set8(pci_conf, PCI_HEADER_TYPE,
+ PCI_HEADER_TYPE_NORMAL | PCI_HEADER_TYPE_MULTI_FUNCTION);
+
+ apm_init(&lpc->apm, ich9_apm_ctrl_changed, &lpc);
+
+ sci_irq = ich9_lpc_allocate_sci_irq(pic);
+ ich9_pm_init(&lpc->pm, sci_irq[0]);
+ pci_conf_initl(&lpc->d, ICH9_LPC_PMBASE, ich9_lpc_pmbase_update,
+ ICH9_LPC_PMBASE_DEFAULT);
+ pci_config_set32(lpc->d.config, ICH9_LPC_PMBASE, ICH9_LPC_PMBASE_DEFAULT);
+
+ register_savevm(ICH9_A2_LPC, 0, ICH9_A2_LPC_SAVEVM_VERSION,
+ ich9_lpc_save, ich9_lpc_load, lpc);
+
+ ich9_lpc_reset(lpc);
+
+#if 0
+ /* XXX TODO */
+#define GPE_BASE_PIIX4 0xafe0
+#define ICH9_PMBASE_COMPAT ((GPE_BASE - ICH9_PMIO_GEP0_STS) | ICH9_LPC_PMBASE_RTE)
+ pci_config_set32(pci_conf,ICH9_PMBASE_COMPAT);
+ qemu_acpi_gpe_init(pci_conf[ICH9_LPC_PMBASE] + ICH9_PMIO_GEP0_STS)
+#endif
+ return 0;
+}
diff --git a/hw/q35.h b/hw/q35.h
new file mode 100644
index 0000000..998bcd6
--- /dev/null
+++ b/hw/q35.h
@@ -0,0 +1,213 @@
+/*
+ * 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 General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef HW_Q35_H
+#define HW_Q35_H
+
+#include "acpi_ich9.h"
+
+void gmch_init_memory_mappings(PCIDevice *d);
+PCIBus *gmch_init(PCIDevice **pgmch_state, qemu_irq *pic);
+
+PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int secondary_bus_num);
+int ich9_lpc_init(PCIBus *bus, int devfn, qemu_irq *pic);
+
+i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
+
+void ich9_pm_init(struct ich9_lpc_pm_regs *pm, qemu_irq sci_irq);
+void ich9_pm_iospace_update(struct ich9_lpc_pm_regs *pm, uint32_t pm_io_base);
+void ich9_pm_save(QEMUFile* f, struct ich9_lpc_pm_regs *pm);
+void ich9_pm_load(QEMUFile* f, struct ich9_lpc_pm_regs *pm, int version_id);
+
+void ich9_hot_add_init(void);
+
+#define Q35_MASK(bit, ms_bit, ls_bit) ((((uint##bit##_t)1 << (ms_bit)) - 1) & ~(((uint##bit##_t)1 << ls_bit) - 1))
+
+/*
+ * gmch part
+ */
+
+/* PCI configuration */
+#define Q35_HOST_BRIDGE "GMCH"
+
+#define Q35_HOST_BRIDGE_CONFIG_ADDR 0xcf8
+#define Q35_HOST_BRIDGE_CONFIG_DATA 0xcfc
+
+/* D0:F0 configuration space */
+#define Q35_HOST_BRIDGE_REVISION_DEFUALT 0x0
+
+#define Q35_HOST_BRIDGE_PCIEXBAR 0x60 /* 64bit register */
+#define Q35_HOST_BRIDGE_PCIEXBAR_DEFAULT 0xe0000000
+#define Q35_HOST_BRIDGE_PCIEXBAR_ADMSK Q35_MASK(64, 35, 25) /* bit 35:28 */
+#define Q35_HOST_BRIDGE_PCIEXBAR_128ADMSK ((uint64_t)(1 << 26))
+#define Q35_HOST_BRIDGE_PCIEXBAR_64ADMSK ((uint64_t)(1 << 25))
+#define Q35_HOST_BRIDGE_PCIEXBAR_LENGTH ((uint64_t)(0x2 << 1))
+#define Q35_HOST_BRIDGE_PCIEXBAREN ((uint64_t)1)
+
+#define Q35_HOST_BRIDGE_PAM0 0x90
+#define Q35_HOST_BRIDGE_PAM_BIOS_AREA 0xf0000
+#define Q35_HOST_BRIDGE_PAM_AREA_SIZE 0x1000 /* 16KB */
+#define Q35_HOST_BRIDGE_PAM1 0x91
+#define Q35_HOST_BRIDGE_PAM_EXPAN_AREA 0xc0000
+#define Q35_HOST_BRIDGE_PAM2 0x92
+#define Q35_HOST_BRIDGE_PAM3 0x93
+#define Q35_HOST_BRIDGE_PAM4 0x94
+#define Q35_HOST_BRIDGE_PAM5 0x95
+#define Q35_HOST_BRIDGE_PAM_EXBIOS_AREA 0xe0000
+#define Q35_HOST_BRIDGE_PAM6 0x96
+#define Q35_HOST_BRIDGE_PAM_WE_HI ((uint8_t)(0x2 << 4))
+#define Q35_HOST_BRIDGE_PAM_RE_HI ((uint8_t)(0x1 << 4))
+#define Q35_HOST_BRIDGE_PAM_HI_MASK ((uint8_t)(0x3 << 4))
+#define Q35_HOST_BRIDGE_PAM_WE_LO ((uint8_t)0x2)
+#define Q35_HOST_BRIDGE_PAM_RE_LO ((uint8_t)0x1)
+#define Q35_HOST_BRIDGE_PAM_LO_MASK ((uint8_t)0x3)
+#define Q35_HOST_BRIDGE_PAM_WE ((uint8_t)0x2)
+#define Q35_HOST_BRIDGE_PAM_RE ((uint8_t)0x1)
+#define Q35_HOST_BRIDGE_PAM_MASK ((uint8_t)0x3)
+
+
+#define Q35_HOST_BRDIGE_SMRAM 0x9d
+#define Q35_HOST_BRIDGE_SMRAM_DEFAULT ((uint8_t)0x2)
+#define Q35_HOST_BRIDGE_SMRAM_D_OPEN ((uint8_t)(1 << 6))
+#define Q35_HOST_BRIDGE_SMRAM_D_CLS ((uint8_t)(1 << 5))
+#define Q35_HOST_BRIDGE_SMRAM_D_LCK ((uint8_t)(1 << 4))
+#define Q35_HOST_BRIDGE_SMRAM_G_SMRAME ((uint8_t)(1 << 3))
+#define Q35_HOST_BRIDGE_SMRAM_C_BASE_SEG_MASK ((uint8_t)0x7)
+#define Q35_HOST_BRIDGE_SMRAM_C_BASE_SEG ((uint8_t)0x2) /* hardwired to b010 */
+#define Q35_HOST_BRIDGE_SMARM_C_BASE 0xa0000
+#define Q35_HOST_BRIDGE_SMRAM_C_END 0xc0000
+#define Q35_HOST_BRIDGE_SMRAM_C_SIZE 0x20000
+#define Q35_HOST_BRIDGE_UPPER_SYSTEM_BIOS_END 0x100000
+
+#define Q35_HOST_BRIDGE_ESMRAMC 0x9e
+#define Q35_HOST_BRDIGE_ESMRAMC_H_SMRAME ((uint8_t)(1 << 6))
+#define Q35_HOST_BRDIGE_ESMRAMC_E_SMERR ((uint8_t)(1 << 5))
+#define Q35_HOST_BRDIGE_ESMRAMC_SM_CACHE ((uint8_t)(1 << 4))
+#define Q35_HOST_BRDIGE_ESMRAMC_SM_L1 ((uint8_t)(1 << 3))
+#define Q35_HOST_BRDIGE_ESMRAMC_SM_L2 ((uint8_t)(1 << 2))
+#define Q35_HOST_BRDIGE_ESMRAMC_TSEG_SZ_MASK ((uint8_t)(0x3 << 1))
+#define Q35_HOST_BRDIGE_ESMRAMC_TSEG_SZ_1MB ((uint8_t)(0x0 << 1))
+#define Q35_HOST_BRDIGE_ESMRAMC_TSEG_SZ_2MB ((uint8_t)(0x1 << 1))
+#define Q35_HOST_BRDIGE_ESMRAMC_TSEG_SZ_8MB ((uint8_t)(0x2 << 1))
+#define Q35_HOST_BRDIGE_ESMRAMC_T_EN ((uint8_t)1)
+
+
+/*
+ * ich9 part
+ */
+
+/* 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
+
+/* 1 pcie port on gmch and 6 pcie port on ich9,
+ the next bus # is 7 */
+#define ICH9_D2P_SECONDARY_DEFAULT 7
+
+#define ICH9_D2P_A2_REVISION 0x92
+
+
+/* D30:F1 LPC controller */
+#define ICH9_A2_LPC "ICH9 A2 LPC"
+#define ICH9_A2_LPC_SAVEVM_VERSION 0
+
+#define ICH9_LPC_DEV 30
+#define ICH9_LPC_FUNC 1
+
+#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_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 0x1
+
+#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
+
+/* 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_SMI_EN 0x30
+#define ICH9_PMIO_SMI_STS 0x34
+
+
+/* D30: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))
+
+/* D30:F3 SMBus I/O and memory mapped I/O registers */
+#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..41804d0
--- /dev/null
+++ b/hw/q35_smbus.c
@@ -0,0 +1,177 @@
+/*
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
+ */
+/*
+ * 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 "pc_smbus.h"
+#include "pci.h"
+//#include "qemu-timer.h"
+#include "sysemu.h"
+#include "i2c.h"
+#include "smbus.h"
+#include "kvm.h"
+
+#include "q35.h"
+
+typedef struct ICH9_SMBState {
+ PCIDevice dev;
+
+ PCSMBus smb;
+} ICH9_SMBState;
+
+#define ICH9_SMB_SAVEVM_VERSION_CURRENT 0
+
+#if 0
+#define SMBHSTSTS ICH9_SMB_HST_STS
+#define SMBHSTCNT ICH9_SMB_HST_CNT
+#define SMBHSTCMD ICH9_SMB_HST_CMD
+#define SMBHSTADD ICH9_SMB_XMIT_SLVA
+#define SMBHSTDAT0 ICH9_SMB_HST_D0
+#define SMBHSTDAT1 ICH9_SMB_HST_D1
+#define SMBBLKDAT ICH9_SMB_HOST_BLOCK_DB
+#endif
+
+static ICH9_SMBState *ich9_pci_to_smb(PCIDevice* pci_dev)
+{
+ return (ICH9_SMBState*)pci_dev;
+}
+
+
+static void ich9_smb_save(QEMUFile* f,void *opaque)
+{
+ ICH9_SMBState *s = opaque;
+
+ pci_device_save(&s->dev, f);
+}
+
+static int ich9_smb_load(QEMUFile* f,void* opaque,int version_id)
+{
+ ICH9_SMBState *s = opaque;
+ int ret;
+
+ if (version_id > ICH9_SMB_SAVEVM_VERSION_CURRENT)
+ return -EINVAL;
+
+ ret = pci_device_load(&s->dev, f);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void ich9_smb_reset(void *opaque)
+{
+ //ICH9_SMBState *s = opaque;
+ //uint8_t *pci_conf = s->dev.config;
+
+ /* XXX not yet */
+}
+
+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)) {
+ uint32_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)) {
+ uint32_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,
+ uint32_t addr, uint32_t size, int type)
+{
+ ICH9_SMBState *s = ich9_pci_to_smb(dev);
+
+ assert(size == ICH9_SMB_SMB_BASE_SIZE);
+ assert(type == PCI_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);
+}
+
+i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
+{
+ ICH9_SMBState *s;
+ uint8_t *pci_conf;
+
+ s = (ICH9_SMBState *)pci_register_device(bus,
+ "ICH9 SMB", sizeof(ICH9_SMBState),
+ devfn, NULL, NULL);
+ pci_conf = s->dev.config;
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_ICH9_6);
+
+ pci_config_set16(pci_conf, PCI_STATUS,
+ PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
+ pci_conf_initw(&s->dev, PCI_STATUS, NULL,
+ PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY);
+
+ pci_config_set8(pci_conf, PCI_REVISION_ID, ICH9_A2_SMB_REVISION);
+ pci_config_set8(pci_conf, PCI_CLASS_INTERFACE, ICH9_SMB_PI);
+
+ pci_config_set_class(pci_conf, PCI_CLASS_SERIAL_SMBUS);
+ pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type
+
+ /* XXX: D31IP.SMIP in chipset configuration space */
+ pci_config_set8(pci_conf, PCI_INTERRUPT_PIN, 0x01); // interrupt pin 1
+
+ pci_config_set8(pci_conf, ICH9_SMB_HOSTC, 0);
+
+
+ /* XXX:
+ * paralell_hds[0]
+ * serial_hds[0]
+ * serial_hds[0]
+ * fdc
+ */
+
+ // XXX smb_io_base
+ pci_config_set8(pci_conf, ICH9_SMB_HOSTC, 0);
+ /* XXX bar0, bar1: 64bit BAR support*/
+ pci_register_bar(&s->dev, ICH9_SMB_SMB_BASE_BAR,
+ ICH9_SMB_SMB_BASE_SIZE, PCI_ADDRESS_SPACE_IO,
+ &ich9_smb_map_ioport);
+
+ register_savevm("ich9_smb", 0, ICH9_SMB_SAVEVM_VERSION_CURRENT,
+ ich9_smb_save, ich9_smb_load, s);
+
+ pc_smbus_init(&s->smb);
+ qemu_register_reset(ich9_smb_reset, 0, s);
+
+ return s->smb.smbus;
+}
--
yamahata
^ permalink raw reply related [flat|nested] 21+ messages in thread