aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.objs2
-rw-r--r--Makefile.target4
-rw-r--r--cpu-all.h2
-rw-r--r--cpu-defs.h6
-rw-r--r--cpu-exec.c7
-rw-r--r--cpus.c90
-rw-r--r--exec-all.h3
-rw-r--r--exec.c8
-rw-r--r--hw/acpi.c745
-rw-r--r--hw/acpi.h78
-rw-r--r--hw/acpi_piix4.c599
-rw-r--r--hw/apb_pci.c7
-rw-r--r--hw/apm.c86
-rw-r--r--hw/apm.h22
-rw-r--r--hw/e1000.c4
-rw-r--r--hw/fdc.c35
-rw-r--r--hw/fdc.h5
-rw-r--r--hw/hw.h5
-rw-r--r--hw/ide/core.c2
-rw-r--r--hw/mc146818rtc.c47
-rw-r--r--hw/mc146818rtc.h10
-rw-r--r--hw/mips_jazz.c1
-rw-r--r--hw/mips_malta.c3
-rw-r--r--hw/mips_r4k.c3
-rw-r--r--hw/pc.c423
-rw-r--r--hw/pc.h48
-rw-r--r--hw/pc_piix.c316
-rw-r--r--hw/pci.c8
-rw-r--r--hw/pci.h4
-rw-r--r--hw/pckbd.c4
-rw-r--r--hw/piix_pci.c5
-rw-r--r--hw/pm_smbus.c176
-rw-r--r--hw/pm_smbus.h21
-rw-r--r--hw/ppc_prep.c1
-rw-r--r--hw/qdev.c16
-rw-r--r--hw/qdev.h4
-rw-r--r--hw/serial.c13
-rw-r--r--hw/sm501.c172
-rw-r--r--hw/tmp105.c9
-rw-r--r--hw/vga.c10
-rw-r--r--ia64-dis.c10
-rw-r--r--kvm-all.c24
-rw-r--r--kvm.h4
-rw-r--r--pc-bios/README5
-rw-r--r--pc-bios/bios.binbin131072 -> 131072 bytes
-rw-r--r--pc-bios/openbios-ppcbin312132 -> 312028 bytes
-rw-r--r--pc-bios/openbios-sparc32bin217668 -> 217664 bytes
-rw-r--r--pc-bios/openbios-sparc64bin1065880 -> 1065872 bytes
-rw-r--r--qemu-common.h8
m---------roms/seabios0
-rw-r--r--savevm.c23
-rw-r--r--target-i386/kvm.c29
-rw-r--r--target-ppc/kvm.c10
-rw-r--r--target-s390x/kvm.c10
-rw-r--r--target-sparc/cpu.h2
-rw-r--r--target-sparc/exec.h5
-rw-r--r--target-sparc/helper.c2
-rw-r--r--target-sparc/op_helper.c9
58 files changed, 1945 insertions, 1200 deletions
diff --git a/Makefile.objs b/Makefile.objs
index ecdd53e..110f8fd 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -226,6 +226,8 @@ sound-obj-$(CONFIG_CS4231A) += cs4231a.o
adlib.o fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
+hw-obj-$(CONFIG_LINUX) += virtio-9p-debug.o virtio-9p-local.o
+
######################################################################
# libdis
# NOTE: the disassembler code is only needed for debugging
diff --git a/Makefile.target b/Makefile.target
index c092900..f2cd4ff 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -168,7 +168,7 @@ obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o
obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o
obj-y += vhost_net.o
obj-$(CONFIG_VHOST_NET) += vhost.o
-obj-$(CONFIG_LINUX) += virtio-9p.o virtio-9p-debug.o virtio-9p-local.o
+obj-$(CONFIG_LINUX) += virtio-9p.o
obj-y += rwhandler.o
obj-$(CONFIG_KVM) += kvm.o kvm-all.o
obj-$(CONFIG_NO_KVM) += kvm-stub.o
@@ -195,6 +195,7 @@ obj-i386-y += cirrus_vga.o apic.o ioapic.o piix_pci.o
obj-i386-y += vmmouse.o vmport.o hpet.o
obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o
obj-i386-y += debugcon.o multiboot.o
+obj-i386-y += pm_smbus.o apm.o acpi_piix4.o pc_piix.o
# shared objects
obj-ppc-y = ppc.o
@@ -220,6 +221,7 @@ obj-mips-y += dma.o vga.o i8259.o
obj-mips-y += g364fb.o jazz_led.o
obj-mips-y += gt64xxx.o pckbd.o mc146818rtc.o
obj-mips-y += piix4.o cirrus_vga.o
+obj-mips-y += pm_smbus.o apm.o acpi_piix4.o
obj-microblaze-y = petalogix_s3adsp1800_mmu.o
diff --git a/cpu-all.h b/cpu-all.h
index 52a1817..47a5722 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -821,6 +821,8 @@ void cpu_watchpoint_remove_all(CPUState *env, int mask);
void cpu_single_step(CPUState *env, int enabled);
void cpu_reset(CPUState *s);
+int cpu_is_stopped(CPUState *env);
+void run_on_cpu(CPUState *env, void (*func)(void *data), void *data);
#define CPU_LOG_TB_OUT_ASM (1 << 0)
#define CPU_LOG_TB_IN_ASM (1 << 1)
diff --git a/cpu-defs.h b/cpu-defs.h
index 0140596..8d4bf86 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -132,6 +132,7 @@ typedef struct icount_decr_u16 {
struct kvm_run;
struct KVMState;
+struct qemu_work_item;
typedef struct CPUBreakpoint {
target_ulong pc;
@@ -158,8 +159,6 @@ typedef struct CPUWatchpoint {
target_ulong mem_io_vaddr; /* target virtual addr at which the \
memory was accessed */ \
uint32_t halted; /* Nonzero if the CPU is in suspend state */ \
- uint32_t stop; /* Stop request */ \
- uint32_t stopped; /* Artificially stopped */ \
uint32_t interrupt_request; \
volatile sig_atomic_t exit_request; \
CPU_COMMON_TLB \
@@ -202,8 +201,11 @@ typedef struct CPUWatchpoint {
void *opaque; \
\
uint32_t created; \
+ uint32_t stop; /* Stop request */ \
+ uint32_t stopped; /* Artificially stopped */ \
struct QemuThread *thread; \
struct QemuCond *halt_cond; \
+ struct qemu_work_item *queued_work_first, *queued_work_last; \
const char *cpu_model_str; \
struct KVMState *kvm_state; \
struct kvm_run *kvm_run; \
diff --git a/cpu-exec.c b/cpu-exec.c
index dc81e79..c776605 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -213,6 +213,8 @@ static void cpu_handle_debug_exception(CPUState *env)
/* main execution loop */
+volatile sig_atomic_t exit_request;
+
int cpu_exec(CPUState *env1)
{
volatile host_reg_t saved_env_reg;
@@ -234,6 +236,11 @@ int cpu_exec(CPUState *env1)
asm("");
env = env1;
+ if (exit_request) {
+ env->exit_request = 1;
+ exit_request = 0;
+ }
+
#if defined(TARGET_I386)
if (!kvm_enabled()) {
/* put eflags in CPU temporary format */
diff --git a/cpus.c b/cpus.c
index 29462e5..8341f6c 100644
--- a/cpus.c
+++ b/cpus.c
@@ -91,6 +91,11 @@ void cpu_synchronize_all_post_init(void)
}
}
+int cpu_is_stopped(CPUState *env)
+{
+ return !vm_running || env->stopped;
+}
+
static void do_vm_stop(int reason)
{
if (vm_running) {
@@ -115,6 +120,8 @@ static int cpu_has_work(CPUState *env)
{
if (env->stop)
return 1;
+ if (env->queued_work_first)
+ return 1;
if (env->stopped || !vm_running)
return 0;
if (!env->halted)
@@ -140,7 +147,7 @@ static int io_thread_fd = -1;
static void qemu_event_increment(void)
{
/* Write 8 bytes to be compatible with eventfd. */
- static uint64_t val = 1;
+ static const uint64_t val = 1;
ssize_t ret;
if (io_thread_fd == -1)
@@ -252,6 +259,11 @@ int qemu_cpu_self(void *env)
return 1;
}
+void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
+{
+ func(data);
+}
+
void resume_all_vcpus(void)
{
}
@@ -304,6 +316,7 @@ static QemuCond qemu_cpu_cond;
/* system init */
static QemuCond qemu_system_cond;
static QemuCond qemu_pause_cond;
+static QemuCond qemu_work_cond;
static void tcg_block_io_signals(void);
static void kvm_block_io_signals(CPUState *env);
@@ -334,6 +347,50 @@ void qemu_main_loop_start(void)
qemu_cond_broadcast(&qemu_system_cond);
}
+void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
+{
+ struct qemu_work_item wi;
+
+ if (qemu_cpu_self(env)) {
+ func(data);
+ return;
+ }
+
+ wi.func = func;
+ wi.data = data;
+ if (!env->queued_work_first)
+ env->queued_work_first = &wi;
+ else
+ env->queued_work_last->next = &wi;
+ env->queued_work_last = &wi;
+ wi.next = NULL;
+ wi.done = false;
+
+ qemu_cpu_kick(env);
+ while (!wi.done) {
+ CPUState *self_env = cpu_single_env;
+
+ qemu_cond_wait(&qemu_work_cond, &qemu_global_mutex);
+ cpu_single_env = self_env;
+ }
+}
+
+static void flush_queued_work(CPUState *env)
+{
+ struct qemu_work_item *wi;
+
+ if (!env->queued_work_first)
+ return;
+
+ while ((wi = env->queued_work_first)) {
+ env->queued_work_first = wi->next;
+ wi->func(wi->data);
+ wi->done = true;
+ }
+ env->queued_work_last = NULL;
+ qemu_cond_broadcast(&qemu_work_cond);
+}
+
static void qemu_wait_io_event_common(CPUState *env)
{
if (env->stop) {
@@ -341,6 +398,7 @@ static void qemu_wait_io_event_common(CPUState *env)
env->stopped = 1;
qemu_cond_signal(&qemu_pause_cond);
}
+ flush_queued_work(env);
}
static void qemu_wait_io_event(CPUState *env)
@@ -454,8 +512,7 @@ void qemu_cpu_kick(void *_env)
{
CPUState *env = _env;
qemu_cond_broadcast(env->halt_cond);
- if (kvm_enabled())
- qemu_thread_signal(env->thread, SIG_IPI);
+ qemu_thread_signal(env->thread, SIG_IPI);
}
int qemu_cpu_self(void *_env)
@@ -472,6 +529,7 @@ static void cpu_signal(int sig)
{
if (cpu_single_env)
cpu_exit(cpu_single_env);
+ exit_request = 1;
}
static void tcg_block_io_signals(void)
@@ -542,26 +600,20 @@ static void unblock_io_signals(void)
pthread_sigmask(SIG_BLOCK, &set, NULL);
}
-static void qemu_signal_lock(unsigned int msecs)
-{
- qemu_mutex_lock(&qemu_fair_mutex);
-
- while (qemu_mutex_trylock(&qemu_global_mutex)) {
- qemu_thread_signal(tcg_cpu_thread, SIG_IPI);
- if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs))
- break;
- }
- qemu_mutex_unlock(&qemu_fair_mutex);
-}
-
void qemu_mutex_lock_iothread(void)
{
if (kvm_enabled()) {
qemu_mutex_lock(&qemu_fair_mutex);
qemu_mutex_lock(&qemu_global_mutex);
qemu_mutex_unlock(&qemu_fair_mutex);
- } else
- qemu_signal_lock(100);
+ } else {
+ qemu_mutex_lock(&qemu_fair_mutex);
+ if (qemu_mutex_trylock(&qemu_global_mutex)) {
+ qemu_thread_signal(tcg_cpu_thread, SIG_IPI);
+ qemu_mutex_lock(&qemu_global_mutex);
+ }
+ qemu_mutex_unlock(&qemu_fair_mutex);
+ }
}
void qemu_mutex_unlock_iothread(void)
@@ -588,7 +640,6 @@ void pause_all_vcpus(void)
while (penv) {
penv->stop = 1;
- qemu_thread_signal(penv->thread, SIG_IPI);
qemu_cpu_kick(penv);
penv = (CPUState *)penv->next_cpu;
}
@@ -597,7 +648,7 @@ void pause_all_vcpus(void)
qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);
penv = first_cpu;
while (penv) {
- qemu_thread_signal(penv->thread, SIG_IPI);
+ qemu_cpu_kick(penv);
penv = (CPUState *)penv->next_cpu;
}
}
@@ -610,7 +661,6 @@ void resume_all_vcpus(void)
while (penv) {
penv->stop = 0;
penv->stopped = 0;
- qemu_thread_signal(penv->thread, SIG_IPI);
qemu_cpu_kick(penv);
penv = (CPUState *)penv->next_cpu;
}
diff --git a/exec-all.h b/exec-all.h
index 1016de2..4565dd0 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -351,4 +351,7 @@ CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler);
/* vl.c */
extern int singlestep;
+/* cpu-exec.c */
+extern volatile sig_atomic_t exit_request;
+
#endif
diff --git a/exec.c b/exec.c
index 3416aed..56b5561 100644
--- a/exec.c
+++ b/exec.c
@@ -2775,8 +2775,12 @@ ram_addr_t qemu_ram_alloc(ram_addr_t size)
if (mem_path) {
#if defined (__linux__) && !defined(TARGET_S390X)
new_block->host = file_ram_alloc(size, mem_path);
- if (!new_block->host)
- exit(1);
+ if (!new_block->host) {
+ new_block->host = qemu_vmalloc(size);
+#ifdef MADV_MERGEABLE
+ madvise(new_block->host, size, MADV_MERGEABLE);
+#endif
+ }
#else
fprintf(stderr, "-mem-path option unsupported\n");
exit(1);
diff --git a/hw/acpi.c b/hw/acpi.c
index e3b63b7..c7044b1 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -17,750 +17,7 @@
*/
#include "hw.h"
#include "pc.h"
-#include "pci.h"
-#include "qemu-timer.h"
-#include "sysemu.h"
-#include "i2c.h"
-#include "smbus.h"
-
-//#define DEBUG
-
-/* i82731AB (PIIX4) compatible power management function */
-#define PM_FREQ 3579545
-
-#define ACPI_DBG_IO_ADDR 0xb044
-
-typedef struct PIIX4PMState {
- PCIDevice dev;
- uint16_t pmsts;
- uint16_t pmen;
- uint16_t pmcntrl;
- uint8_t apmc;
- 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;
- qemu_irq irq;
- qemu_irq cmos_s3;
- qemu_irq smi_irq;
- int kvm_enabled;
-} 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
-
-#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)
-{
- uint32_t d;
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, get_ticks_per_sec());
- return d & 0xffffff;
-}
-
-static int get_pmsts(PIIX4PMState *s)
-{
- int64_t d;
-
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, get_ticks_per_sec());
- if (d >= s->tmr_overflow_time)
- s->pmsts |= TMROF_EN;
- 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) &
- (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 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, get_ticks_per_sec(), PM_FREQ);
- 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 & TMROF_EN) {
- /* if TMRSTS is reset, then compute the new overflow time */
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ,
- get_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 & ~(SUS_EN);
- if (val & SUS_EN) {
- /* change suspend type */
- sus_typ = (val >> 10) & 7;
- switch(sus_typ) {
- case 0: /* soft power off */
- 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);
- qemu_system_reset_request();
- if (s->cmos_s3) {
- qemu_irq_raise(s->cmos_s3);
- }
- 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;
-#ifdef DEBUG
- addr &= 0x3f;
- 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 pm_smi_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- 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;
- }
-
- if (s->dev.config[0x5b] & (1 << 1)) {
- if (s->smi_irq) {
- qemu_irq_raise(s->smi_irq);
- }
- }
- } else {
- s->apms = val;
- }
-}
-
-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;
- }
-#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)
-{
-#if defined(DEBUG)
- printf("ACPI: DBG: 0x%08x\n", 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;
-
- 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 (range_covers_byte(address, len, 0x80))
- pm_io_space_update((PIIX4PMState *)d);
-}
-
-static int vmstate_acpi_post_load(void *opaque, int version_id)
-{
- PIIX4PMState *s = opaque;
-
- pm_io_space_update(s);
- return 0;
-}
-
-static const VMStateDescription vmstate_acpi = {
- .name = "piix4_pm",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .post_load = vmstate_acpi_post_load,
- .fields = (VMStateField []) {
- VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
- VMSTATE_UINT16(pmsts, PIIX4PMState),
- VMSTATE_UINT16(pmen, PIIX4PMState),
- VMSTATE_UINT16(pmcntrl, PIIX4PMState),
- VMSTATE_UINT8(apmc, PIIX4PMState),
- VMSTATE_UINT8(apms, PIIX4PMState),
- VMSTATE_TIMER(tmr_timer, PIIX4PMState),
- VMSTATE_INT64(tmr_overflow_time, PIIX4PMState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-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 (s->kvm_enabled) {
- /* Mark SMM as already inited (until KVM supports SMM). */
- pci_conf[0x5B] = 0x02;
- }
-}
-
-static void piix4_powerdown(void *opaque, int irq, int power_failing)
-{
- PIIX4PMState *s = opaque;
-
- if (!s) {
- qemu_system_shutdown_request();
- } else if (s->pmen & PWRBTN_EN) {
- s->pmsts |= PWRBTN_EN;
- pm_update_sci(s);
- }
-}
-
-i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
- qemu_irq sci_irq, qemu_irq cmos_s3, qemu_irq smi_irq,
- int kvm_enabled)
-{
- 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 */
-
- register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s);
- register_ioport_read(0xb2, 2, 1, pm_smi_readb, s);
-
- register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
-
- s->kvm_enabled = kvm_enabled;
- if (s->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);
- register_ioport_read(smb_io_base, 64, 1, smb_ioport_readb, s);
-
- s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
-
- qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1);
-
- vmstate_register(0, &vmstate_acpi, s);
-
- s->smbus = i2c_init_bus(NULL, "i2c");
- s->irq = sci_irq;
- s->cmos_s3 = cmos_s3;
- s->smi_irq = smi_irq;
- qemu_register_reset(piix4_reset, s);
-
- return s->smbus;
-}
-
-#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)
-{
- BusState *bus = opaque;
- DeviceState *qdev, *next;
- PCIDevice *dev;
- int slot = ffs(val) - 1;
-
- QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
- dev = DO_UPCAST(PCIDevice, qdev, qdev);
- if (PCI_SLOT(dev->devfn) == slot) {
- qdev_free(qdev);
- }
- }
-
-
-#if defined(DEBUG)
- printf("pciej write %x <== %d\n", addr, val);
-#endif
-}
-
-static int piix4_device_hotplug(PCIDevice *dev, int state);
-
-void piix4_acpi_system_hot_add_init(PCIBus *bus)
-{
- 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, bus);
- register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus);
-
- pci_bus_hotplug(bus, piix4_device_hotplug);
-}
-
-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 int piix4_device_hotplug(PCIDevice *dev, int state)
-{
- int slot = PCI_SLOT(dev->devfn);
-
- 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);
- }
- return 0;
-}
+#include "acpi.h"
struct acpi_table_header
{
diff --git a/hw/acpi.h b/hw/acpi.h
new file mode 100644
index 0000000..5949958
--- /dev/null
+++ b/hw/acpi.h
@@ -0,0 +1,78 @@
+#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, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/* 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 */
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
new file mode 100644
index 0000000..0fce958
--- /dev/null
+++ b/hw/acpi_piix4.c
@@ -0,0 +1,599 @@
+/*
+ * ACPI implementation
+ *
+ * Copyright (c) 2006 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>
+ */
+#include "hw.h"
+#include "pc.h"
+#include "apm.h"
+#include "pm_smbus.h"
+#include "pci.h"
+#include "acpi.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+# define PIIX4_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
+#else
+# define PIIX4_DPRINTF(format, ...) do { } while (0)
+#endif
+
+#define ACPI_DBG_IO_ADDR 0xb044
+
+#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;
+};
+
+typedef struct PIIX4PMState {
+ PCIDevice dev;
+ uint16_t pmsts;
+ uint16_t pmen;
+ uint16_t pmcntrl;
+
+ APMState apm;
+
+ QEMUTimer *tmr_timer;
+ int64_t tmr_overflow_time;
+
+ PMSMBus smb;
+ uint32_t smb_io_base;
+
+ qemu_irq irq;
+ qemu_irq cmos_s3;
+ qemu_irq smi_irq;
+ int kvm_enabled;
+
+ /* for pci hotplug */
+ struct gpe_regs gpe;
+ struct pci_status pci0_status;
+} PIIX4PMState;
+
+static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s);
+
+#define ACPI_ENABLE 0xf1
+#define ACPI_DISABLE 0xf0
+
+static uint32_t get_pmtmr(PIIX4PMState *s)
+{
+ uint32_t d;
+ d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec());
+ return d & 0xffffff;
+}
+
+static int get_pmsts(PIIX4PMState *s)
+{
+ int64_t d;
+
+ d = muldiv64(qemu_get_clock(vm_clock), PM_TIMER_FREQUENCY,
+ get_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, get_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,
+ get_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 (s->cmos_s3) {
+ qemu_irq_raise(s->cmos_s3);
+ }
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ PIIX4_DPRINTF("PM writew port=0x%04x val=0x%04x\n", addr, val);
+}
+
+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;
+ }
+ PIIX4_DPRINTF("PM readw port=0x%04x val=0x%04x\n", addr, val);
+ return val;
+}
+
+static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+ // PIIX4PMState *s = opaque;
+ PIIX4_DPRINTF("PM writel port=0x%04x val=0x%08x\n", addr & 0x3f, val);
+}
+
+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;
+ }
+ PIIX4_DPRINTF("PM readl port=0x%04x val=0x%08x\n", addr, val);
+ 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)) {
+ if (s->smi_irq) {
+ qemu_irq_raise(s->smi_irq);
+ }
+ }
+}
+
+static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+ PIIX4_DPRINTF("ACPI: DBG: 0x%08x\n", val);
+}
+
+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 */
+ PIIX4_DPRINTF("PM: mapping to 0x%x\n", pm_io_base);
+ 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 (range_covers_byte(address, len, 0x80))
+ pm_io_space_update((PIIX4PMState *)d);
+}
+
+static int vmstate_acpi_post_load(void *opaque, int version_id)
+{
+ PIIX4PMState *s = opaque;
+
+ pm_io_space_update(s);
+ return 0;
+}
+
+static const VMStateDescription vmstate_acpi = {
+ .name = "piix4_pm",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .post_load = vmstate_acpi_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_PCI_DEVICE(dev, PIIX4PMState),
+ VMSTATE_UINT16(pmsts, PIIX4PMState),
+ VMSTATE_UINT16(pmen, PIIX4PMState),
+ VMSTATE_UINT16(pmcntrl, PIIX4PMState),
+ VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState),
+ VMSTATE_TIMER(tmr_timer, PIIX4PMState),
+ VMSTATE_INT64(tmr_overflow_time, PIIX4PMState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+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 (s->kvm_enabled) {
+ /* Mark SMM as already inited (until KVM supports SMM). */
+ pci_conf[0x5B] = 0x02;
+ }
+}
+
+static void piix4_powerdown(void *opaque, int irq, int power_failing)
+{
+ PIIX4PMState *s = opaque;
+
+ if (!s) {
+ qemu_system_shutdown_request();
+ } else if (s->pmen & ACPI_BITMASK_POWER_BUTTON_ENABLE) {
+ s->pmsts |= ACPI_BITMASK_POWER_BUTTON_STATUS;
+ pm_update_sci(s);
+ }
+}
+
+static int piix4_pm_initfn(PCIDevice *dev)
+{
+ PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev, dev);
+ uint8_t *pci_conf;
+
+ 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 (s->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] = s->smb_io_base | 1;
+ pci_conf[0x91] = s->smb_io_base >> 8;
+ pci_conf[0xd2] = 0x09;
+ register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb);
+ register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb);
+
+ s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
+
+ qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1);
+
+ pm_smbus_init(&s->dev.qdev, &s->smb);
+ qemu_register_reset(piix4_reset, s);
+ piix4_acpi_system_hot_add_init(dev->bus, s);
+
+ return 0;
+}
+
+i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
+ qemu_irq sci_irq, qemu_irq cmos_s3, qemu_irq smi_irq,
+ int kvm_enabled)
+{
+ PCIDevice *dev;
+ PIIX4PMState *s;
+
+ dev = pci_create(bus, devfn, "PIIX4_PM");
+ qdev_prop_set_uint32(&dev->qdev, "smb_io_base", smb_io_base);
+
+ s = DO_UPCAST(PIIX4PMState, dev, dev);
+ s->irq = sci_irq;
+ s->cmos_s3 = cmos_s3;
+ s->smi_irq = smi_irq;
+ s->kvm_enabled = kvm_enabled;
+
+ qdev_init_nofail(&dev->qdev);
+
+ return s->smb.smbus;
+}
+
+static PCIDeviceInfo piix4_pm_info = {
+ .qdev.name = "PIIX4_PM",
+ .qdev.desc = "PM",
+ .qdev.size = sizeof(PIIX4PMState),
+ .qdev.vmsd = &vmstate_acpi,
+ .init = piix4_pm_initfn,
+ .config_write = pm_write_config,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("smb_io_base", PIIX4PMState, smb_io_base, 0),
+ DEFINE_PROP_END_OF_LIST(),
+ }
+};
+
+static void piix4_pm_register(void)
+{
+ pci_qdev_register(&piix4_pm_info);
+}
+
+device_init(piix4_pm_register);
+
+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;
+ }
+
+ PIIX4_DPRINTF("gpe read %x == %x\n", addr, val);
+ 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;
+ }
+
+ PIIX4_DPRINTF("gpe write %x <== %d\n", addr, val);
+}
+
+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;
+ }
+
+ PIIX4_DPRINTF("pcihotplug read %x == %x\n", 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;
+ }
+
+ PIIX4_DPRINTF("pcihotplug write %x <== %d\n", addr, val);
+}
+
+static uint32_t pciej_read(void *opaque, uint32_t addr)
+{
+ PIIX4_DPRINTF("pciej read %x\n", addr);
+ return 0;
+}
+
+static void pciej_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ BusState *bus = opaque;
+ DeviceState *qdev, *next;
+ PCIDevice *dev;
+ int slot = ffs(val) - 1;
+
+ QLIST_FOREACH_SAFE(qdev, &bus->children, sibling, next) {
+ dev = DO_UPCAST(PCIDevice, qdev, qdev);
+ if (PCI_SLOT(dev->devfn) == slot) {
+ qdev_free(qdev);
+ }
+ }
+
+
+ PIIX4_DPRINTF("pciej write %x <== %d\n", addr, val);
+}
+
+static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state);
+
+static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s)
+{
+ struct gpe_regs *gpe = &s->gpe;
+ struct pci_status *pci0_status = &s->pci0_status;
+
+ 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, bus);
+ register_ioport_read(PCI_EJ_BASE, 4, 4, pciej_read, bus);
+
+ pci_bus_hotplug(bus, piix4_device_hotplug, &s->dev.qdev);
+}
+
+static void enable_device(PIIX4PMState *s, int slot)
+{
+ s->gpe.sts |= 2;
+ s->pci0_status.up |= (1 << slot);
+}
+
+static void disable_device(PIIX4PMState *s, int slot)
+{
+ s->gpe.sts |= 2;
+ s->pci0_status.down |= (1 << slot);
+}
+
+static int piix4_device_hotplug(DeviceState *qdev, PCIDevice *dev, int state)
+{
+ int slot = PCI_SLOT(dev->devfn);
+ PIIX4PMState *s = DO_UPCAST(PIIX4PMState, dev,
+ DO_UPCAST(PCIDevice, qdev, qdev));
+
+ s->pci0_status.up = 0;
+ s->pci0_status.down = 0;
+ if (state) {
+ enable_device(s, slot);
+ } else {
+ disable_device(s, slot);
+ }
+ if (s->gpe.en & 2) {
+ qemu_set_irq(s->irq, 1);
+ qemu_set_irq(s->irq, 0);
+ }
+ return 0;
+}
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index 095f3b7..65d8ba6 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -73,10 +73,9 @@ typedef struct APBState {
uint32_t obio_irq_map[32];
qemu_irq pci_irqs[32];
uint32_t reset_control;
+ unsigned int nr_resets;
} APBState;
-static unsigned int nr_resets;
-
static void apb_config_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
{
@@ -108,7 +107,7 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr,
s->reset_control &= ~(val & RESET_WCMASK);
s->reset_control |= val & RESET_WMASK;
if (val & SOFT_POR) {
- nr_resets = 0;
+ s->nr_resets = 0;
qemu_system_reset_request();
} else if (val & SOFT_XIR) {
qemu_system_reset_request();
@@ -374,7 +373,7 @@ static void pci_pbm_reset(DeviceState *d)
s->pci_irq_map[i] &= PBM_PCI_IMR_MASK;
}
- if (nr_resets++ == 0) {
+ if (s->nr_resets++ == 0) {
/* Power on reset */
s->reset_control = POR;
}
diff --git a/hw/apm.c b/hw/apm.c
new file mode 100644
index 0000000..cdda72f
--- /dev/null
+++ b/hw/apm.c
@@ -0,0 +1,86 @@
+/*
+ * QEMU PC APM controller Emulation
+ * This is split out 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, see <http://www.gnu.org/licenses/>
+ */
+
+#include "apm.h"
+#include "hw.h"
+
+//#define DEBUG
+
+#ifdef DEBUG
+# define APM_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
+#else
+# define APM_DPRINTF(format, ...) do { } while (0)
+#endif
+
+/* fixed I/O location */
+#define APM_CNT_IOPORT 0xb2
+#define APM_STS_IOPORT 0xb3
+
+static void apm_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ APMState *apm = opaque;
+ addr &= 1;
+ APM_DPRINTF("apm_ioport_writeb addr=0x%x val=0x%02x\n", addr, val);
+ 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;
+ }
+ APM_DPRINTF("apm_ioport_readb addr=0x%x val=0x%02x\n", addr, val);
+ return val;
+}
+
+const VMStateDescription vmstate_apm = {
+ .name = "APM State",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(apmc, APMState),
+ VMSTATE_UINT8(apms, APMState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+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/apm.h b/hw/apm.h
new file mode 100644
index 0000000..f7c741e
--- /dev/null
+++ b/hw/apm.h
@@ -0,0 +1,22 @@
+#ifndef APM_H
+#define APM_H
+
+#include <stdint.h>
+#include "qemu-common.h"
+#include "hw.h"
+
+typedef void (*apm_ctrl_changed_t)(uint32_t val, void *arg);
+
+typedef struct APMState {
+ uint8_t apmc;
+ uint8_t apms;
+
+ apm_ctrl_changed_t callback;
+ void *arg;
+} APMState;
+
+void apm_init(APMState *s, apm_ctrl_changed_t callback, void *arg);
+
+extern const VMStateDescription vmstate_apm;
+
+#endif /* APM_H */
diff --git a/hw/e1000.c b/hw/e1000.c
index 34cc451..96d045d 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -544,8 +544,8 @@ start_xmit(E1000State *s)
static int
receive_filter(E1000State *s, const uint8_t *buf, int size)
{
- static uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- static int mta_shift[] = {4, 3, 2, 0};
+ static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+ static const int mta_shift[] = {4, 3, 2, 0};
uint32_t f, rctl = s->mac_reg[RCTL], ra[2], *rp;
if (is_vlan_packet(s, buf) && vlan_rx_filter_enabled(s)) {
diff --git a/hw/fdc.c b/hw/fdc.c
index c4ca9e9..6306496 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1918,7 +1918,7 @@ FDCtrl *sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
return fdctrl;
}
-static int fdctrl_init_common(FDCtrl *fdctrl, target_phys_addr_t io_base)
+static int fdctrl_init_common(FDCtrl *fdctrl)
{
int i, j;
static int command_tables_inited = 0;
@@ -1949,7 +1949,6 @@ static int fdctrl_init_common(FDCtrl *fdctrl, target_phys_addr_t io_base)
DMA_register_channel(fdctrl->dma_chann, &fdctrl_transfer_handler, fdctrl);
fdctrl_connect_drives(fdctrl);
- vmstate_register(io_base, &vmstate_fdc, fdctrl);
return 0;
}
@@ -1973,7 +1972,8 @@ static int isabus_fdc_init1(ISADevice *dev)
isa_init_irq(&isa->busdev, &fdctrl->irq, isairq);
fdctrl->dma_chann = dma_chann;
- ret = fdctrl_init_common(fdctrl, iobase);
+ qdev_set_legacy_instance_id(&dev->qdev, iobase, 2);
+ ret = fdctrl_init_common(fdctrl);
return ret;
}
@@ -1991,7 +1991,8 @@ static int sysbus_fdc_init1(SysBusDevice *dev)
qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
fdctrl->dma_chann = -1;
- ret = fdctrl_init_common(fdctrl, io);
+ qdev_set_legacy_instance_id(&dev->qdev, io, 2);
+ ret = fdctrl_init_common(fdctrl);
return ret;
}
@@ -2008,14 +2009,26 @@ static int sun4m_fdc_init1(SysBusDevice *dev)
qdev_init_gpio_in(&dev->qdev, fdctrl_handle_tc, 1);
fdctrl->sun4m = 1;
- return fdctrl_init_common(fdctrl, io);
+ qdev_set_legacy_instance_id(&dev->qdev, io, 2);
+ return fdctrl_init_common(fdctrl);
}
+static const VMStateDescription vmstate_isa_fdc ={
+ .name = "fdc",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .fields = (VMStateField []) {
+ VMSTATE_STRUCT(state, FDCtrlISABus, 0, vmstate_fdc, FDCtrl),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static ISADeviceInfo isa_fdc_info = {
.init = isabus_fdc_init1,
.qdev.name = "isa-fdc",
.qdev.size = sizeof(FDCtrlISABus),
.qdev.no_user = 1,
+ .qdev.vmsd = &vmstate_isa_fdc,
.qdev.reset = fdctrl_external_reset_isa,
.qdev.props = (Property[]) {
DEFINE_PROP_DRIVE("driveA", FDCtrlISABus, state.drives[0].dinfo),
@@ -2024,10 +2037,21 @@ static ISADeviceInfo isa_fdc_info = {
},
};
+static const VMStateDescription vmstate_sysbus_fdc ={
+ .name = "fdc",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .fields = (VMStateField []) {
+ VMSTATE_STRUCT(state, FDCtrlSysBus, 0, vmstate_fdc, FDCtrl),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static SysBusDeviceInfo sysbus_fdc_info = {
.init = sysbus_fdc_init1,
.qdev.name = "sysbus-fdc",
.qdev.size = sizeof(FDCtrlSysBus),
+ .qdev.vmsd = &vmstate_sysbus_fdc,
.qdev.reset = fdctrl_external_reset_sysbus,
.qdev.props = (Property[]) {
DEFINE_PROP_DRIVE("driveA", FDCtrlSysBus, state.drives[0].dinfo),
@@ -2040,6 +2064,7 @@ static SysBusDeviceInfo sun4m_fdc_info = {
.init = sun4m_fdc_init1,
.qdev.name = "SUNW,fdtwo",
.qdev.size = sizeof(FDCtrlSysBus),
+ .qdev.vmsd = &vmstate_sysbus_fdc,
.qdev.reset = fdctrl_external_reset_sysbus,
.qdev.props = (Property[]) {
DEFINE_PROP_DRIVE("drive", FDCtrlSysBus, state.drives[0].dinfo),
diff --git a/hw/fdc.h b/hw/fdc.h
index d173902..c48b5e0 100644
--- a/hw/fdc.h
+++ b/hw/fdc.h
@@ -1,3 +1,6 @@
+#ifndef HW_FDC_H
+#define HW_FDC_H
+
/* fdc.c */
#include "sysemu.h"
#define MAX_FD 2
@@ -10,3 +13,5 @@ FDCtrl *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
FDCtrl *sun4m_fdctrl_init(qemu_irq irq, target_phys_addr_t io_base,
DriveInfo **fds, qemu_irq *fdc_tc);
int fdctrl_get_drive_type(FDCtrl *fdctrl, int drive_num);
+
+#endif
diff --git a/hw/hw.h b/hw/hw.h
index 328b704..fc2d184 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -321,7 +321,6 @@ struct VMStateDescription {
int (*pre_load)(void *opaque);
int (*post_load)(void *opaque, int version_id);
void (*pre_save)(void *opaque);
- void (*post_save)(void *opaque);
VMStateField *fields;
};
@@ -759,5 +758,9 @@ extern void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
void *opaque);
extern int vmstate_register(int instance_id, const VMStateDescription *vmsd,
void *base);
+extern int vmstate_register_with_alias_id(int instance_id,
+ const VMStateDescription *vmsd,
+ void *base, int alias_id,
+ int required_for_version);
void vmstate_unregister(const VMStateDescription *vmsd, void *opaque);
#endif
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 0757528..b0165bc 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -36,7 +36,7 @@
#define IDE_PAGE_SIZE 4096
-static int smart_attributes[][5] = {
+static const int smart_attributes[][5] = {
/* id, flags, val, wrst, thrsh */
{ 0x01, 0x03, 0x64, 0x64, 0x06}, /* raw read */
{ 0x03, 0x03, 0x64, 0x64, 0x46}, /* spin up */
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 89a423e..571c593 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -28,9 +28,16 @@
#include "apic.h"
#include "isa.h"
#include "hpet_emul.h"
+#include "mc146818rtc.h"
//#define DEBUG_CMOS
+#ifdef DEBUG_CMOS
+# define CMOS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
+#else
+# define CMOS_DPRINTF(format, ...) do { } while (0)
+#endif
+
#define RTC_REINJECT_ON_ACK_COUNT 20
#define RTC_SECONDS 0
@@ -65,7 +72,7 @@
#define REG_C_PF 0x40
#define REG_C_AF 0x20
-struct RTCState {
+typedef struct RTCState {
ISADevice dev;
uint8_t cmos_data[128];
uint8_t cmos_index;
@@ -85,7 +92,7 @@ struct RTCState {
QEMUTimer *coalesced_timer;
QEMUTimer *second_timer;
QEMUTimer *second_timer2;
-};
+} RTCState;
static void rtc_irq_raise(qemu_irq irq)
{
@@ -210,10 +217,8 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
if ((addr & 1) == 0) {
s->cmos_index = data & 0x7f;
} else {
-#ifdef DEBUG_CMOS
- printf("cmos: write index=0x%02x val=0x%02x\n",
- s->cmos_index, data);
-#endif
+ CMOS_DPRINTF("cmos: write index=0x%02x val=0x%02x\n",
+ s->cmos_index, data);
switch(s->cmos_index) {
case RTC_SECONDS_ALARM:
case RTC_MINUTES_ALARM:
@@ -484,22 +489,22 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
ret = s->cmos_data[s->cmos_index];
break;
}
-#ifdef DEBUG_CMOS
- printf("cmos: read index=0x%02x val=0x%02x\n",
- s->cmos_index, ret);
-#endif
+ CMOS_DPRINTF("cmos: read index=0x%02x val=0x%02x\n",
+ s->cmos_index, ret);
return ret;
}
}
-void rtc_set_memory(RTCState *s, int addr, int val)
+void rtc_set_memory(ISADevice *dev, int addr, int val)
{
+ RTCState *s = DO_UPCAST(RTCState, dev, dev);
if (addr >= 0 && addr <= 127)
s->cmos_data[addr] = val;
}
-void rtc_set_date(RTCState *s, const struct tm *tm)
+void rtc_set_date(ISADevice *dev, const struct tm *tm)
{
+ RTCState *s = DO_UPCAST(RTCState, dev, dev);
s->current_tm = *tm;
rtc_copy_date(s);
}
@@ -508,18 +513,19 @@ void rtc_set_date(RTCState *s, const struct tm *tm)
#define REG_IBM_CENTURY_BYTE 0x32
#define REG_IBM_PS2_CENTURY_BYTE 0x37
-static void rtc_set_date_from_host(RTCState *s)
+static void rtc_set_date_from_host(ISADevice *dev)
{
+ RTCState *s = DO_UPCAST(RTCState, dev, dev);
struct tm tm;
int val;
/* set the CMOS date */
qemu_get_timedate(&tm, 0);
- rtc_set_date(s, &tm);
+ rtc_set_date(dev, &tm);
val = rtc_to_bcd(s, (tm.tm_year / 100) + 19);
- rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
- rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
+ rtc_set_memory(dev, REG_IBM_CENTURY_BYTE, val);
+ rtc_set_memory(dev, REG_IBM_PS2_CENTURY_BYTE, val);
}
static int rtc_post_load(void *opaque, int version_id)
@@ -591,7 +597,7 @@ static int rtc_initfn(ISADevice *dev)
s->cmos_data[RTC_REG_C] = 0x00;
s->cmos_data[RTC_REG_D] = 0x80;
- rtc_set_date_from_host(s);
+ rtc_set_date_from_host(dev);
s->periodic_timer = qemu_new_timer(rtc_clock, rtc_periodic_timer, s);
#ifdef TARGET_I386
@@ -609,25 +615,26 @@ static int rtc_initfn(ISADevice *dev)
register_ioport_write(base, 2, 1, cmos_ioport_write, s);
register_ioport_read(base, 2, 1, cmos_ioport_read, s);
- vmstate_register(base, &vmstate_rtc, s);
+ qdev_set_legacy_instance_id(&dev->qdev, base, 2);
qemu_register_reset(rtc_reset, s);
return 0;
}
-RTCState *rtc_init(int base_year)
+ISADevice *rtc_init(int base_year)
{
ISADevice *dev;
dev = isa_create("mc146818rtc");
qdev_prop_set_int32(&dev->qdev, "base_year", base_year);
qdev_init_nofail(&dev->qdev);
- return DO_UPCAST(RTCState, dev, dev);
+ return dev;
}
static ISADeviceInfo mc146818rtc_info = {
.qdev.name = "mc146818rtc",
.qdev.size = sizeof(RTCState),
.qdev.no_user = 1,
+ .qdev.vmsd = &vmstate_rtc,
.init = rtc_initfn,
.qdev.props = (Property[]) {
DEFINE_PROP_INT32("base_year", RTCState, base_year, 1980),
diff --git a/hw/mc146818rtc.h b/hw/mc146818rtc.h
new file mode 100644
index 0000000..6f46a68
--- /dev/null
+++ b/hw/mc146818rtc.h
@@ -0,0 +1,10 @@
+#ifndef MC146818RTC_H
+#define MC146818RTC_H
+
+#include "isa.h"
+
+ISADevice *rtc_init(int base_year);
+void rtc_set_memory(ISADevice *dev, int addr, int val);
+void rtc_set_date(ISADevice *dev, const struct tm *tm);
+
+#endif /* !MC146818RTC_H */
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 5609597..6e0ec8f 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -35,6 +35,7 @@
#include "esp.h"
#include "mips-bios.h"
#include "loader.h"
+#include "mc146818rtc.h"
enum jazz_model_e
{
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 586c1c3..792709b 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -44,6 +44,7 @@
#include "ide.h"
#include "loader.h"
#include "elf.h"
+#include "mc146818rtc.h"
//#define DEBUG_BOARD_INIT
@@ -776,7 +777,7 @@ void mips_malta_init (ram_addr_t ram_size,
PCIBus *pci_bus;
ISADevice *isa_dev;
CPUState *env;
- RTCState *rtc_state;
+ ISADevice *rtc_state;
FDCtrl *floppy_controller;
MaltaFPGAState *malta_fpga;
qemu_irq *i8259;
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 0d5e2a6..f1fcfcd 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -21,6 +21,7 @@
#include "ide.h"
#include "loader.h"
#include "elf.h"
+#include "mc146818rtc.h"
#define MAX_IDE_BUS 2
@@ -165,7 +166,7 @@ void mips_r4k_init (ram_addr_t ram_size,
int bios_size;
CPUState *env;
ResetData *reset_info;
- RTCState *rtc_state;
+ ISADevice *rtc_state;
int i;
qemu_irq *i8259;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
diff --git a/hw/pc.c b/hw/pc.c
index db2b9a2..20dc7fd 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -27,26 +27,14 @@
#include "fdc.h"
#include "pci.h"
#include "vmware_vga.h"
-#include "usb-uhci.h"
-#include "usb-ohci.h"
-#include "prep_pci.h"
-#include "apb_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 "ide.h"
#include "loader.h"
#include "elf.h"
#include "multiboot.h"
-#include "kvm.h"
+#include "mc146818rtc.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
@@ -63,13 +51,6 @@
#define FW_CFG_IRQ0_OVERRIDE (FW_CFG_ARCH_LOCAL + 2)
#define FW_CFG_E820_TABLE (FW_CFG_ARCH_LOCAL + 3)
-#define MAX_IDE_BUS 2
-
-static FDCtrl *floppy_controller;
-static RTCState *rtc_state;
-static PITState *pit;
-static PCII440FXState *i440fx_state;
-
#define E820_NR_ENTRIES 16
struct e820_entry {
@@ -85,12 +66,7 @@ struct e820_table {
static struct e820_table e820_table;
-typedef struct isa_irq_state {
- qemu_irq *i8259;
- qemu_irq *ioapic;
-} IsaIrqState;
-
-static void isa_irq_handler(void *opaque, int n, int level)
+void isa_irq_handler(void *opaque, int n, int level)
{
IsaIrqState *isa = (IsaIrqState *)opaque;
@@ -107,6 +83,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)
{
@@ -125,10 +107,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_MASK), smm_arg);
}
@@ -198,9 +192,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,
+ ISADevice *s)
{
- RTCState *s = rtc_state;
int cylinders, heads, sectors;
bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
rtc_set_memory(s, type_ofs, 47);
@@ -232,7 +226,7 @@ static int boot_device2nibble(char boot_device)
return 0;
}
-static int set_boot_dev(RTCState *s, const char *boot_device, int fd_bootchk)
+static int set_boot_dev(ISADevice *s, const char *boot_device, int fd_bootchk)
{
#define PC_MAX_BOOT_DEVICES 3
int nbds, bds[3] = { 0, };
@@ -262,10 +256,10 @@ 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, DriveInfo **hd_table)
+void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
+ const char *boot_device, DriveInfo **hd_table,
+ FDCtrl *floppy_controller, ISADevice *s)
{
- RTCState *s = rtc_state;
int val;
int fd0, fd1, nb;
int i;
@@ -340,9 +334,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]->bdrv);
+ cmos_init_hd(0x19, 0x1b, hd_table[0]->bdrv, s);
if (hd_table[1])
- cmos_init_hd(0x1a, 0x24, hd_table[1]->bdrv);
+ cmos_init_hd(0x1a, 0x24, hd_table[1]->bdrv, s);
val = 0;
for (i = 0; i < 4; i++) {
@@ -710,10 +704,6 @@ static void load_linux(void *fw_cfg,
nb_option_roms++;
}
-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 const int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360,
@@ -724,7 +714,7 @@ static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
#ifdef HAS_AUDIO
-static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
+void pc_audio_init (PCIBus *pci_bus, qemu_irq *pic)
{
struct soundhw *c;
@@ -742,7 +732,7 @@ static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
}
#endif
-static void pc_init_ne2k_isa(NICInfo *nd)
+void pc_init_ne2k_isa(NICInfo *nd)
{
static int nb_ne2k = 0;
@@ -761,16 +751,16 @@ int cpu_is_bsp(CPUState *env)
/* set CMOS shutdown status register (index 0xF) as S3_resume(0xFE)
BIOS will read it and start S3 resume at POST Entry */
-static void cmos_set_s3_resume(void *opaque, int irq, int level)
+void pc_cmos_set_s3_resume(void *opaque, int irq, int level)
{
- RTCState *s = opaque;
+ ISADevice *s = opaque;
if (level) {
rtc_set_memory(s, 0xF, 0xFE);
}
}
-static void acpi_smi_interrupt(void *opaque, int irq, int level)
+void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
{
CPUState *s = opaque;
@@ -798,31 +788,37 @@ static CPUState *pc_new_cpu(const char *cpu_model)
return env;
}
-/* 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,
- const char *cpu_model,
- int pci_enabled)
+void pc_cpus_init(const char *cpu_model)
+{
+ int i;
+
+ /* 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++) {
+ pc_new_cpu(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)
{
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;
- PCIBus *pci_bus;
- int piix3_devfn = -1;
- qemu_irq *cpu_irq;
- qemu_irq *isa_irq;
- qemu_irq *i8259;
- qemu_irq *cmos_s3;
- qemu_irq *smi_irq;
- IsaIrqState *isa_irq_state;
- DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
- DriveInfo *fd[MAX_FD];
- void *fw_cfg;
+ void **fw_cfg;
if (ram_size >= 0xe0000000 ) {
above_4g_mem_size = ram_size - 0xe0000000;
@@ -830,24 +826,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);
- /* 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++) {
- pc_new_cpu(cpu_model);
- }
-
- vmport_init();
-
/* allocate RAM */
ram_addr = qemu_ram_alloc(below_4g_mem_size);
cpu_register_physical_memory(0, 0xa0000, ram_addr);
@@ -910,63 +893,60 @@ static void pc_init1(ram_addr_t ram_size,
rom_set_fw(fw_cfg);
if (linux_boot) {
- load_linux(fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size);
+ load_linux(*fw_cfg, kernel_filename, initrd_filename, kernel_cmdline, below_4g_mem_size);
}
for (i = 0; i < nb_option_roms; i++) {
rom_add_option(option_rom[i]);
}
+}
- cpu_irq = qemu_allocate_irqs(pic_irq_request, NULL, 1);
- i8259 = i8259_init(cpu_irq[0]);
- isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
- isa_irq_state->i8259 = i8259;
- isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
-
- if (pci_enabled) {
- pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
- } else {
- pci_bus = NULL;
- isa_bus_new(NULL);
- }
- isa_bus_irqs(isa_irq);
-
- ferr_irq = isa_reserve_irq(13);
-
- /* init basic PC hardware */
- register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
-
- register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
+qemu_irq *pc_allocate_cpu_irq(void)
+{
+ return qemu_allocate_irqs(pic_irq_request, NULL, 1);
+}
+void pc_vga_init(PCIBus *pci_bus)
+{
if (cirrus_vga_enabled) {
- if (pci_enabled) {
+ if (pci_bus) {
pci_cirrus_vga_init(pci_bus);
} else {
isa_cirrus_vga_init();
}
} else if (vmsvga_enabled) {
- if (pci_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_enabled) {
+ if (pci_bus) {
pci_vga_init(pci_bus, 0, 0);
} else {
isa_vga_init();
}
}
+}
+
+void pc_basic_device_init(qemu_irq *isa_irq,
+ FDCtrl **floppy_controller,
+ ISADevice **rtc_state)
+{
+ int i;
+ DriveInfo *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(2000);
+ *rtc_state = rtc_init(2000);
- qemu_register_boot_set(pc_boot_set, 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);
- if (pci_enabled) {
- isa_irq_state->ioapic = ioapic_init();
- }
pit = pit_init(0x40, isa_reserve_irq(0));
pcspk_init(pit);
if (!no_hpet) {
@@ -985,235 +965,22 @@ static void pc_init1(ram_addr_t ram_size,
}
}
- 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);
- else
- pci_nic_init_nofail(nd, "e1000", NULL);
- }
-
- 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++) {
- hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
- }
-
- if (pci_enabled) {
- pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
- } else {
- for(i = 0; i < MAX_IDE_BUS; i++) {
- isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
- hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
- }
- }
-
isa_create_simple("i8042");
DMA_init(0);
-#ifdef HAS_AUDIO
- audio_init(pci_enabled ? pci_bus : NULL, isa_irq);
-#endif
for(i = 0; i < MAX_FD; i++) {
fd[i] = drive_get(IF_FLOPPY, 0, i);
}
- floppy_controller = fdctrl_init_isa(fd);
-
- cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd);
-
- 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;
-
- cmos_s3 = qemu_allocate_irqs(cmos_set_s3_resume, rtc_state, 1);
- smi_irq = qemu_allocate_irqs(acpi_smi_interrupt, first_cpu, 1);
- /* TODO: Populate SPD eeprom data. */
- smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
- isa_reserve_irq(9), *cmos_s3, *smi_irq,
- kvm_enabled());
- for (i = 0; i < 8; i++) {
- DeviceState *eeprom;
- eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
- qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
- qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
- qdev_init_nofail(eeprom);
- }
- piix4_acpi_system_hot_add_init(pci_bus);
- }
-
- if (i440fx_state) {
- i440fx_init_memory_mappings(i440fx_state);
- }
-
- 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");
- }
- }
+ *floppy_controller = fdctrl_init_isa(fd);
}
-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)
+void pc_pci_device_init(PCIBus *pci_bus)
{
- pc_init1(ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 1);
-}
-
-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)
-{
- if (cpu_model == NULL)
- cpu_model = "486";
- pc_init1(ram_size, boot_device,
- kernel_filename, kernel_cmdline,
- initrd_filename, cpu_model, 0);
-}
+ int max_bus;
+ int bus;
-static QEMUMachine pc_machine = {
- .name = "pc-0.13",
- .alias = "pc",
- .desc = "Standard PC",
- .init = pc_init_pci,
- .max_cpus = 255,
- .is_default = 1,
-};
-
-static QEMUMachine pc_machine_v0_12 = {
- .name = "pc-0.12",
- .desc = "Standard PC",
- .init = pc_init_pci,
- .max_cpus = 255,
- .compat_props = (GlobalProperty[]) {
- {
- .driver = "virtio-serial-pci",
- .property = "max_nr_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },
- { /* end of list */ }
+ max_bus = drive_get_max_bus(IF_SCSI);
+ for (bus = 0; bus <= max_bus; bus++) {
+ pci_create_simple(pci_bus, -1, "lsi53c895a");
}
-};
-
-static QEMUMachine pc_machine_v0_11 = {
- .name = "pc-0.11",
- .desc = "Standard PC, qemu 0.11",
- .init = pc_init_pci,
- .max_cpus = 255,
- .compat_props = (GlobalProperty[]) {
- {
- .driver = "virtio-blk-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "virtio-serial-pci",
- .property = "max_nr_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "ide-drive",
- .property = "ver",
- .value = "0.11",
- },{
- .driver = "scsi-disk",
- .property = "ver",
- .value = "0.11",
- },{
- .driver = "PCI",
- .property = "rombar",
- .value = stringify(0),
- },
- { /* end of list */ }
- }
-};
-
-static QEMUMachine pc_machine_v0_10 = {
- .name = "pc-0.10",
- .desc = "Standard PC, qemu 0.10",
- .init = pc_init_pci,
- .max_cpus = 255,
- .compat_props = (GlobalProperty[]) {
- {
- .driver = "virtio-blk-pci",
- .property = "class",
- .value = stringify(PCI_CLASS_STORAGE_OTHER),
- },{
- .driver = "virtio-serial-pci",
- .property = "class",
- .value = stringify(PCI_CLASS_DISPLAY_OTHER),
- },{
- .driver = "virtio-serial-pci",
- .property = "max_nr_ports",
- .value = stringify(1),
- },{
- .driver = "virtio-serial-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "virtio-net-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "virtio-blk-pci",
- .property = "vectors",
- .value = stringify(0),
- },{
- .driver = "ide-drive",
- .property = "ver",
- .value = "0.10",
- },{
- .driver = "scsi-disk",
- .property = "ver",
- .value = "0.10",
- },{
- .driver = "PCI",
- .property = "rombar",
- .value = stringify(0),
- },
- { /* end of list */ }
- },
-};
-
-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(&pc_machine_v0_12);
- qemu_register_machine(&pc_machine_v0_11);
- qemu_register_machine(&pc_machine_v0_10);
- qemu_register_machine(&isapc_machine);
}
-
-machine_init(pc_machine_init);
diff --git a/hw/pc.h b/hw/pc.h
index d11a576..654b7b3 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -3,6 +3,8 @@
#include "qemu-common.h"
#include "ioport.h"
+#include "isa.h"
+#include "fdc.h"
/* PC-style peripherals (also used by other machines). */
@@ -36,6 +38,14 @@ uint32_t pic_intack_read(PicState2 *s);
void pic_info(Monitor *mon);
void irq_info(Monitor *mon);
+/* ISA */
+typedef struct isa_irq_state {
+ qemu_irq *i8259;
+ qemu_irq *ioapic;
+} IsaIrqState;
+
+void isa_irq_handler(void *opaque, int n, int level);
+
/* i8254.c */
#define PIT_FREQ 1193182
@@ -66,20 +76,40 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
target_phys_addr_t base, ram_addr_t size,
target_phys_addr_t mask);
-/* mc146818rtc.c */
-
-typedef struct RTCState RTCState;
-
-RTCState *rtc_init(int base_year);
-void rtc_set_memory(RTCState *s, int addr, int val);
-void rtc_set_date(RTCState *s, const struct tm *tm);
-
/* pc.c */
extern int fd_bootchk;
+void pc_register_ferr_irq(qemu_irq irq);
+void pc_cmos_set_s3_resume(void *opaque, int irq, int level);
+void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
+
+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_allocate_cpu_irq(void);
+void pc_vga_init(PCIBus *pci_bus);
+void pc_basic_device_init(qemu_irq *isa_irq,
+ FDCtrl **floppy_controller,
+ ISADevice **rtc_state);
+void pc_init_ne2k_isa(NICInfo *nd);
+#ifdef HAS_AUDIO
+void pc_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, DriveInfo **hd_table,
+ FDCtrl *floppy_controller, ISADevice *s);
+void pc_pci_device_init(PCIBus *pci_bus);
+
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;
@@ -94,7 +124,6 @@ i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base,
qemu_irq sci_irq, qemu_irq cmos_s3, qemu_irq smi_irq,
int kvm_enabled);
void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
-void piix4_acpi_system_hot_add_init(PCIBus *bus);
/* hpet.c */
extern int no_hpet;
@@ -108,7 +137,6 @@ struct PCII440FXState;
typedef struct PCII440FXState PCII440FXState;
PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, qemu_irq *pic, int ram_size);
-void i440fx_set_smm(PCII440FXState *d, int val);
void i440fx_init_memory_mappings(PCII440FXState *d);
/* piix4.c */
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
new file mode 100644
index 0000000..70f563a
--- /dev/null
+++ b/hw/pc_piix.c
@@ -0,0 +1,316 @@
+/*
+ * 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 "apic.h"
+#include "pci.h"
+#include "usb-uhci.h"
+#include "usb-ohci.h"
+#include "net.h"
+#include "boards.h"
+#include "ide.h"
+#include "kvm.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,
+ const char *cpu_model,
+ int pci_enabled)
+{
+ int i;
+ ram_addr_t below_4g_mem_size, above_4g_mem_size;
+ PCIBus *pci_bus;
+ PCII440FXState *i440fx_state;
+ int piix3_devfn = -1;
+ qemu_irq *cpu_irq;
+ qemu_irq *isa_irq;
+ qemu_irq *i8259;
+ qemu_irq *cmos_s3;
+ qemu_irq *smi_irq;
+ IsaIrqState *isa_irq_state;
+ DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
+ FDCtrl *floppy_controller;
+ ISADevice *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_allocate_cpu_irq();
+ i8259 = i8259_init(cpu_irq[0]);
+ isa_irq_state = qemu_mallocz(sizeof(*isa_irq_state));
+ isa_irq_state->i8259 = i8259;
+ if (pci_enabled) {
+ isa_irq_state->ioapic = ioapic_init();
+ }
+ isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
+
+ if (pci_enabled) {
+ pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
+ } else {
+ pci_bus = NULL;
+ isa_bus_new(NULL);
+ }
+ isa_bus_irqs(isa_irq);
+
+ pc_register_ferr_irq(isa_reserve_irq(13));
+
+ pc_vga_init(pci_enabled? pci_bus: NULL);
+
+ /* init basic PC hardware */
+ pc_basic_device_init(isa_irq, &floppy_controller, &rtc_state);
+
+ 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);
+ else
+ pci_nic_init_nofail(nd, "e1000", NULL);
+ }
+
+ 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++) {
+ hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+ }
+
+ if (pci_enabled) {
+ pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
+ } else {
+ for(i = 0; i < MAX_IDE_BUS; i++) {
+ isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+ hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
+ }
+ }
+
+#ifdef HAS_AUDIO
+ pc_audio_init(pci_enabled ? pci_bus : NULL, isa_irq);
+#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;
+
+ cmos_s3 = qemu_allocate_irqs(pc_cmos_set_s3_resume, rtc_state, 1);
+ smi_irq = qemu_allocate_irqs(pc_acpi_smi_interrupt, first_cpu, 1);
+ /* TODO: Populate SPD eeprom data. */
+ smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
+ isa_reserve_irq(9), *cmos_s3, *smi_irq,
+ kvm_enabled());
+ for (i = 0; i < 8; i++) {
+ DeviceState *eeprom;
+ eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
+ qdev_prop_set_uint8(eeprom, "address", 0x50 + i);
+ qdev_prop_set_ptr(eeprom, "data", eeprom_buf + (i * 256));
+ qdev_init_nofail(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, cpu_model, 1);
+}
+
+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)
+{
+ if (cpu_model == NULL)
+ cpu_model = "486";
+ pc_init1(ram_size, boot_device,
+ kernel_filename, kernel_cmdline,
+ initrd_filename, cpu_model, 0);
+}
+
+static QEMUMachine pc_machine = {
+ .name = "pc-0.13",
+ .alias = "pc",
+ .desc = "Standard PC",
+ .init = pc_init_pci,
+ .max_cpus = 255,
+ .is_default = 1,
+};
+
+static QEMUMachine pc_machine_v0_12 = {
+ .name = "pc-0.12",
+ .desc = "Standard PC",
+ .init = pc_init_pci,
+ .max_cpus = 255,
+ .compat_props = (GlobalProperty[]) {
+ {
+ .driver = "virtio-serial-pci",
+ .property = "max_nr_ports",
+ .value = stringify(1),
+ },{
+ .driver = "virtio-serial-pci",
+ .property = "vectors",
+ .value = stringify(0),
+ },
+ { /* end of list */ }
+ }
+};
+
+static QEMUMachine pc_machine_v0_11 = {
+ .name = "pc-0.11",
+ .desc = "Standard PC, qemu 0.11",
+ .init = pc_init_pci,
+ .max_cpus = 255,
+ .compat_props = (GlobalProperty[]) {
+ {
+ .driver = "virtio-blk-pci",
+ .property = "vectors",
+ .value = stringify(0),
+ },{
+ .driver = "virtio-serial-pci",
+ .property = "max_nr_ports",
+ .value = stringify(1),
+ },{
+ .driver = "virtio-serial-pci",
+ .property = "vectors",
+ .value = stringify(0),
+ },{
+ .driver = "ide-drive",
+ .property = "ver",
+ .value = "0.11",
+ },{
+ .driver = "scsi-disk",
+ .property = "ver",
+ .value = "0.11",
+ },{
+ .driver = "PCI",
+ .property = "rombar",
+ .value = stringify(0),
+ },
+ { /* end of list */ }
+ }
+};
+
+static QEMUMachine pc_machine_v0_10 = {
+ .name = "pc-0.10",
+ .desc = "Standard PC, qemu 0.10",
+ .init = pc_init_pci,
+ .max_cpus = 255,
+ .compat_props = (GlobalProperty[]) {
+ {
+ .driver = "virtio-blk-pci",
+ .property = "class",
+ .value = stringify(PCI_CLASS_STORAGE_OTHER),
+ },{
+ .driver = "virtio-serial-pci",
+ .property = "class",
+ .value = stringify(PCI_CLASS_DISPLAY_OTHER),
+ },{
+ .driver = "virtio-serial-pci",
+ .property = "max_nr_ports",
+ .value = stringify(1),
+ },{
+ .driver = "virtio-serial-pci",
+ .property = "vectors",
+ .value = stringify(0),
+ },{
+ .driver = "virtio-net-pci",
+ .property = "vectors",
+ .value = stringify(0),
+ },{
+ .driver = "virtio-blk-pci",
+ .property = "vectors",
+ .value = stringify(0),
+ },{
+ .driver = "ide-drive",
+ .property = "ver",
+ .value = "0.10",
+ },{
+ .driver = "scsi-disk",
+ .property = "ver",
+ .value = "0.10",
+ },{
+ .driver = "PCI",
+ .property = "rombar",
+ .value = stringify(0),
+ },
+ { /* end of list */ }
+ },
+};
+
+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(&pc_machine_v0_12);
+ qemu_register_machine(&pc_machine_v0_11);
+ qemu_register_machine(&pc_machine_v0_10);
+ qemu_register_machine(&isapc_machine);
+}
+
+machine_init(pc_machine_init);
diff --git a/hw/pci.c b/hw/pci.c
index 1e143d9..8d84651 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -42,6 +42,7 @@ struct PCIBus {
pci_set_irq_fn set_irq;
pci_map_irq_fn map_irq;
pci_hotplug_fn hotplug;
+ DeviceState *hotplug_qdev;
void *irq_opaque;
PCIDevice *devices[256];
PCIDevice *parent_dev;
@@ -233,10 +234,11 @@ void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
bus->irq_count = qemu_mallocz(nirq * sizeof(bus->irq_count[0]));
}
-void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug)
+void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *qdev)
{
bus->qbus.allow_hotplug = 1;
bus->hotplug = hotplug;
+ bus->hotplug_qdev = qdev;
}
void pci_bus_set_mem_base(PCIBus *bus, target_phys_addr_t base)
@@ -1667,7 +1669,7 @@ static int pci_qdev_init(DeviceState *qdev, DeviceInfo *base)
pci_add_option_rom(pci_dev);
if (qdev->hotplugged)
- bus->hotplug(pci_dev, 1);
+ bus->hotplug(bus->hotplug_qdev, pci_dev, 1);
return 0;
}
@@ -1675,7 +1677,7 @@ static int pci_unplug_device(DeviceState *qdev)
{
PCIDevice *dev = DO_UPCAST(PCIDevice, qdev, qdev);
- dev->bus->hotplug(dev, 0);
+ dev->bus->hotplug(dev->bus->hotplug_qdev, dev, 0);
return 0;
}
diff --git a/hw/pci.h b/hw/pci.h
index 625188c..f6e6c5f 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -209,13 +209,13 @@ int pci_device_load(PCIDevice *s, QEMUFile *f);
typedef void (*pci_set_irq_fn)(void *opaque, int irq_num, int level);
typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
-typedef int (*pci_hotplug_fn)(PCIDevice *pci_dev, int state);
+typedef int (*pci_hotplug_fn)(DeviceState *qdev, PCIDevice *pci_dev, int state);
void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
const char *name, int devfn_min);
PCIBus *pci_bus_new(DeviceState *parent, const char *name, int devfn_min);
void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int nirq);
-void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug);
+void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
PCIBus *pci_register_bus(DeviceState *parent, const char *name,
pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int devfn_min, int nirq);
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 7998aa6..e83b8a6 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -126,8 +126,6 @@ typedef struct KBDState {
target_phys_addr_t mask;
} KBDState;
-static KBDState kbd_state;
-
/* update irq and KBD_STAT_[MOUSE_]OBF */
/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
incorrect, but it avoids having to simulate exact delays */
@@ -390,7 +388,7 @@ void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
target_phys_addr_t base, ram_addr_t size,
target_phys_addr_t mask)
{
- KBDState *s = &kbd_state;
+ KBDState *s = qemu_mallocz(sizeof(KBDState));
int s_io_memory;
s->irq_kbd = kbd_irq;
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 97519db..aff7f6d 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -114,8 +114,10 @@ static void i440fx_update_memory_mappings(PCII440FXState *d)
}
}
-void i440fx_set_smm(PCII440FXState *d, int val)
+static void i440fx_set_smm(int val, void *arg)
{
+ PCII440FXState *d = arg;
+
val = (val != 0);
if (d->smm_enabled != val) {
d->smm_enabled = val;
@@ -210,6 +212,7 @@ static int i440fx_initfn(PCIDevice *dev)
d->dev.config[I440FX_SMRAM] = 0x02;
+ cpu_smm_register(&i440fx_set_smm, d);
return 0;
}
diff --git a/hw/pm_smbus.c b/hw/pm_smbus.c
new file mode 100644
index 0000000..5d6046d
--- /dev/null
+++ b/hw/pm_smbus.c
@@ -0,0 +1,176 @@
+/*
+ * 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, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include "hw.h"
+#include "pc.h"
+#include "pm_smbus.h"
+#include "smbus.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
+
+//#define DEBUG
+
+#ifdef DEBUG
+# define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__)
+#else
+# define SMBUS_DPRINTF(format, ...) do { } while (0)
+#endif
+
+
+static void smb_transaction(PMSMBus *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;
+
+ SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
+ 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)
+{
+ PMSMBus *s = opaque;
+ addr &= 0x3f;
+ SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
+ 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)
+{
+ PMSMBus *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;
+ }
+ SMBUS_DPRINTF("SMB readb port=0x%04x val=0x%02x\n", addr, val);
+ return val;
+}
+
+void pm_smbus_init(DeviceState *parent, PMSMBus *smb)
+{
+ smb->smbus = i2c_init_bus(parent, "i2c");
+}
diff --git a/hw/pm_smbus.h b/hw/pm_smbus.h
new file mode 100644
index 0000000..4750a40
--- /dev/null
+++ b/hw/pm_smbus.h
@@ -0,0 +1,21 @@
+#ifndef PM_SMBUS_H
+#define PM_SMBUS_H
+
+typedef struct PMSMBus {
+ 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;
+} PMSMBus;
+
+void pm_smbus_init(DeviceState *parent, PMSMBus *smb);
+void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val);
+uint32_t smb_ioport_readb(void *opaque, uint32_t addr);
+
+#endif /* !PM_SMBUS_H */
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index a5e25b5..09a9881 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -36,6 +36,7 @@
#include "qemu-log.h"
#include "ide.h"
#include "loader.h"
+#include "mc146818rtc.h"
//#define HARD_DEBUG_PPC_IO
//#define DEBUG_PPC_IO
diff --git a/hw/qdev.c b/hw/qdev.c
index d3bf0fa..af17486 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -93,6 +93,7 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info)
assert(bus->allow_hotplug);
dev->hotplugged = 1;
}
+ dev->instance_id_alias = -1;
dev->state = DEV_STATE_CREATED;
return dev;
}
@@ -278,12 +279,23 @@ int qdev_init(DeviceState *dev)
return rc;
}
qemu_register_reset(qdev_reset, dev);
- if (dev->info->vmsd)
- vmstate_register(-1, dev->info->vmsd, dev);
+ if (dev->info->vmsd) {
+ vmstate_register_with_alias_id(-1, dev->info->vmsd, dev,
+ dev->instance_id_alias,
+ dev->alias_required_for_version);
+ }
dev->state = DEV_STATE_INITIALIZED;
return 0;
}
+void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
+ int required_for_version)
+{
+ assert(dev->state == DEV_STATE_CREATED);
+ dev->instance_id_alias = alias_id;
+ dev->alias_required_for_version = required_for_version;
+}
+
int qdev_unplug(DeviceState *dev)
{
if (!dev->parent_bus->allow_hotplug) {
diff --git a/hw/qdev.h b/hw/qdev.h
index d8fbc73..a44060e 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -44,6 +44,8 @@ struct DeviceState {
QLIST_HEAD(, BusState) child_bus;
int num_child_bus;
QLIST_ENTRY(DeviceState) sibling;
+ int instance_id_alias;
+ int alias_required_for_version;
};
typedef void (*bus_dev_printfn)(Monitor *mon, DeviceState *dev, int indent);
@@ -112,6 +114,8 @@ int qdev_device_help(QemuOpts *opts);
DeviceState *qdev_device_add(QemuOpts *opts);
int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT;
void qdev_init_nofail(DeviceState *dev);
+void qdev_set_legacy_instance_id(DeviceState *dev, int alias_id,
+ int required_for_version);
int qdev_unplug(DeviceState *dev);
void qdev_free(DeviceState *dev);
int qdev_simple_unplug_cb(DeviceState *dev);
diff --git a/hw/serial.c b/hw/serial.c
index 90213c4..9102edb 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -771,7 +771,7 @@ static int serial_isa_initfn(ISADevice *dev)
s->baudbase = 115200;
isa_init_irq(dev, &s->irq, isa->isairq);
serial_init_core(s);
- vmstate_register(isa->iobase, &vmstate_serial, s);
+ qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3);
register_ioport_write(isa->iobase, 8, 1, serial_ioport_write, s);
register_ioport_read(isa->iobase, 8, 1, serial_ioport_read, s);
@@ -790,6 +790,16 @@ SerialState *serial_isa_init(int index, CharDriverState *chr)
return &DO_UPCAST(ISASerialState, dev, dev)->state;
}
+static const VMStateDescription vmstate_isa_serial = {
+ .name = "serial",
+ .version_id = 3,
+ .minimum_version_id = 2,
+ .fields = (VMStateField []) {
+ VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
SerialState *serial_init(int base, qemu_irq irq, int baudbase,
CharDriverState *chr)
{
@@ -956,6 +966,7 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
static ISADeviceInfo serial_isa_info = {
.qdev.name = "isa-serial",
.qdev.size = sizeof(ISASerialState),
+ .qdev.vmsd = &vmstate_isa_serial,
.init = serial_isa_initfn,
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("index", ISASerialState, index, -1),
diff --git a/hw/sm501.c b/hw/sm501.c
index 9310014..b5ec2da 100644
--- a/hw/sm501.c
+++ b/hw/sm501.c
@@ -31,16 +31,16 @@
#include "qdev-addr.h"
/*
- * Status: 2008/11/02
+ * Status: 2010/05/07
* - Minimum implementation for Linux console : mmio regs and CRT layer.
- * - Always updates full screen.
+ * - 2D grapihcs acceleration partially supported : only fill rectangle.
*
* TODO:
* - Panel support
- * - Hardware cursor support
* - Touch panel support
* - USB support
* - UART support
+ * - More 2D graphics engine support
* - Performance tuning
*/
@@ -510,6 +510,18 @@ typedef struct SM501State {
uint32_t dc_crt_hwc_color_1_2;
uint32_t dc_crt_hwc_color_3;
+ uint32_t twoD_destination;
+ uint32_t twoD_dimension;
+ uint32_t twoD_control;
+ uint32_t twoD_pitch;
+ uint32_t twoD_foreground;
+ uint32_t twoD_stretch;
+ uint32_t twoD_color_compare_mask;
+ uint32_t twoD_mask;
+ uint32_t twoD_window_width;
+ uint32_t twoD_source_base;
+ uint32_t twoD_destination_base;
+
} SM501State;
static uint32_t get_local_mem_size_index(uint32_t size)
@@ -619,6 +631,69 @@ static int within_hwc_y_range(SM501State *state, int y, int crt)
return (hwc_y <= y && y < hwc_y + SM501_HWC_HEIGHT);
}
+static void sm501_2d_operation(SM501State * s)
+{
+ /* obtain operation parameters */
+ int operation = (s->twoD_control >> 16) & 0x1f;
+ int dst_x = (s->twoD_destination >> 16) & 0x01FFF;
+ int dst_y = s->twoD_destination & 0xFFFF;
+ int operation_width = (s->twoD_dimension >> 16) & 0x1FFF;
+ int operation_height = s->twoD_dimension & 0xFFFF;
+ uint32_t color = s->twoD_foreground;
+ int format_flags = (s->twoD_stretch >> 20) & 0x3;
+ int addressing = (s->twoD_stretch >> 16) & 0xF;
+
+ /* get frame buffer info */
+#if 0 /* for future use */
+ uint8_t * src = s->local_mem + (s->twoD_source_base & 0x03FFFFFF);
+#endif
+ uint8_t * dst = s->local_mem + (s->twoD_destination_base & 0x03FFFFFF);
+ int dst_width = (s->dc_crt_h_total & 0x00000FFF) + 1;
+
+ if (addressing != 0x0) {
+ printf("%s: only XY addressing is supported.\n", __func__);
+ abort();
+ }
+
+ if ((s->twoD_source_base & 0x08000000) ||
+ (s->twoD_destination_base & 0x08000000)) {
+ printf("%s: only local memory is supported.\n", __func__);
+ abort();
+ }
+
+ switch (operation) {
+ case 0x01: /* fill rectangle */
+
+#define FILL_RECT(_bpp, _pixel_type) { \
+ int y, x; \
+ for (y = 0; y < operation_height; y++) { \
+ for (x = 0; x < operation_width; x++) { \
+ int index = ((dst_y + y) * dst_width + dst_x + x) * _bpp; \
+ *(_pixel_type*)&dst[index] = (_pixel_type)color; \
+ } \
+ } \
+ }
+
+ switch (format_flags) {
+ case 0:
+ FILL_RECT(1, uint8_t);
+ break;
+ case 1:
+ FILL_RECT(2, uint16_t);
+ break;
+ case 2:
+ FILL_RECT(4, uint32_t);
+ break;
+ }
+ break;
+
+ default:
+ printf("non-implemented SM501 2D operation. %d\n", operation);
+ abort();
+ break;
+ }
+}
+
static uint32_t sm501_system_config_read(void *opaque, target_phys_addr_t addr)
{
SM501State * s = (SM501State *)opaque;
@@ -969,6 +1044,92 @@ static CPUWriteMemoryFunc * const sm501_disp_ctrl_writefn[] = {
&sm501_disp_ctrl_write,
};
+static uint32_t sm501_2d_engine_read(void *opaque, target_phys_addr_t addr)
+{
+ SM501State * s = (SM501State *)opaque;
+ uint32_t ret = 0;
+ SM501_DPRINTF("sm501 2d engine regs : read addr=%x\n", (int)addr);
+
+ switch(addr) {
+ case SM501_2D_SOURCE_BASE:
+ ret = s->twoD_source_base;
+ break;
+ default:
+ printf("sm501 disp ctrl : not implemented register read."
+ " addr=%x\n", (int)addr);
+ abort();
+ }
+
+ return ret;
+}
+
+static void sm501_2d_engine_write(void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ SM501State * s = (SM501State *)opaque;
+ SM501_DPRINTF("sm501 2d engine regs : write addr=%x, val=%x\n",
+ addr, value);
+
+ switch(addr) {
+ case SM501_2D_DESTINATION:
+ s->twoD_destination = value;
+ break;
+ case SM501_2D_DIMENSION:
+ s->twoD_dimension = value;
+ break;
+ case SM501_2D_CONTROL:
+ s->twoD_control = value;
+
+ /* do 2d operation if start flag is set. */
+ if (value & 0x80000000) {
+ sm501_2d_operation(s);
+ s->twoD_control &= ~0x80000000; /* start flag down */
+ }
+
+ break;
+ case SM501_2D_PITCH:
+ s->twoD_pitch = value;
+ break;
+ case SM501_2D_FOREGROUND:
+ s->twoD_foreground = value;
+ break;
+ case SM501_2D_STRETCH:
+ s->twoD_stretch = value;
+ break;
+ case SM501_2D_COLOR_COMPARE_MASK:
+ s->twoD_color_compare_mask = value;
+ break;
+ case SM501_2D_MASK:
+ s->twoD_mask = value;
+ break;
+ case SM501_2D_WINDOW_WIDTH:
+ s->twoD_window_width = value;
+ break;
+ case SM501_2D_SOURCE_BASE:
+ s->twoD_source_base = value;
+ break;
+ case SM501_2D_DESTINATION_BASE:
+ s->twoD_destination_base = value;
+ break;
+ default:
+ printf("sm501 2d engine : not implemented register write."
+ " addr=%x, val=%x\n", (int)addr, value);
+ abort();
+ }
+}
+
+static CPUReadMemoryFunc * const sm501_2d_engine_readfn[] = {
+ NULL,
+ NULL,
+ &sm501_2d_engine_read,
+};
+
+static CPUWriteMemoryFunc * const sm501_2d_engine_writefn[] = {
+ NULL,
+ NULL,
+ &sm501_2d_engine_write,
+};
+
/* draw line functions for all console modes */
#include "pixel_ops.h"
@@ -1195,6 +1356,7 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
DeviceState *dev;
int sm501_system_config_index;
int sm501_disp_ctrl_index;
+ int sm501_2d_engine_index;
/* allocate management data region */
s = (SM501State *)qemu_mallocz(sizeof(SM501State));
@@ -1223,6 +1385,10 @@ void sm501_init(uint32_t base, uint32_t local_mem_bytes, qemu_irq irq,
sm501_disp_ctrl_writefn, s);
cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_DC,
0x1000, sm501_disp_ctrl_index);
+ sm501_2d_engine_index = cpu_register_io_memory(sm501_2d_engine_readfn,
+ sm501_2d_engine_writefn, s);
+ cpu_register_physical_memory(base + MMIO_BASE_OFFSET + SM501_2D_ENGINE,
+ 0x54, sm501_2d_engine_index);
/* bridge to usb host emulation module */
dev = qdev_create(NULL, "sysbus-ohci");
diff --git a/hw/tmp105.c b/hw/tmp105.c
index 8343aff..f7e6f2b 100644
--- a/hw/tmp105.c
+++ b/hw/tmp105.c
@@ -173,16 +173,12 @@ static void tmp105_event(i2c_slave *i2c, enum i2c_event event)
s->len = 0;
}
-static void tmp105_post_save(void *opaque)
-{
- TMP105State *s = opaque;
- s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
-}
-
static int tmp105_post_load(void *opaque, int version_id)
{
TMP105State *s = opaque;
+ s->faults = tmp105_faultq[(s->config >> 3) & 3]; /* F */
+
tmp105_interrupt_update(s);
return 0;
}
@@ -192,7 +188,6 @@ static const VMStateDescription vmstate_tmp105 = {
.version_id = 0,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
- .post_save = tmp105_post_save,
.post_load = tmp105_post_load,
.fields = (VMStateField []) {
VMSTATE_UINT8(len, TMP105State),
diff --git a/hw/vga.c b/hw/vga.c
index db72115..87a1bb0 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1171,7 +1171,7 @@ static inline int get_depth_index(DisplayState *s)
}
}
-static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
+static vga_draw_glyph8_func * const vga_draw_glyph8_table[NB_DEPTHS] = {
vga_draw_glyph8_8,
vga_draw_glyph8_16,
vga_draw_glyph8_16,
@@ -1181,7 +1181,7 @@ static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
vga_draw_glyph8_16,
};
-static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
+static vga_draw_glyph8_func * const vga_draw_glyph16_table[NB_DEPTHS] = {
vga_draw_glyph16_8,
vga_draw_glyph16_16,
vga_draw_glyph16_16,
@@ -1191,7 +1191,7 @@ static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
vga_draw_glyph16_16,
};
-static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
+static vga_draw_glyph9_func * const vga_draw_glyph9_table[NB_DEPTHS] = {
vga_draw_glyph9_8,
vga_draw_glyph9_16,
vga_draw_glyph9_16,
@@ -1251,7 +1251,7 @@ static void vga_get_text_resolution(VGACommonState *s, int *pwidth, int *pheight
typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
-static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
+static rgb_to_pixel_dup_func * const rgb_to_pixel_dup_table[NB_DEPTHS] = {
rgb_to_pixel8_dup,
rgb_to_pixel15_dup,
rgb_to_pixel16_dup,
@@ -1447,7 +1447,7 @@ enum {
VGA_DRAW_LINE_NB,
};
-static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
+static vga_draw_line_func * const vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
vga_draw_line2_8,
vga_draw_line2_16,
vga_draw_line2_16,
diff --git a/ia64-dis.c b/ia64-dis.c
index a025178..da73a98 100644
--- a/ia64-dis.c
+++ b/ia64-dis.c
@@ -990,9 +990,8 @@ const struct ia64_operand elf64_ia64_operands[IA64_OPND_COUNT] =
the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this file; see the file COPYING. If not, write to the
- Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with this file; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>. */
/* The primary opcode table is made up of the following: */
struct ia64_main_table
@@ -9906,9 +9905,8 @@ static const struct ia64_dis_names ia64_dis_names[] = {
the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this file; see the file COPYING. If not, write to the
- Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
- 02110-1301, USA. */
+ along with this file; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>. */
static const struct ia64_templ_desc ia64_templ_desc[16] =
{
diff --git a/kvm-all.c b/kvm-all.c
index 6962b2b..c238f54 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -593,11 +593,6 @@ int kvm_init(int smp_cpus)
int ret;
int i;
- if (smp_cpus > 1) {
- fprintf(stderr, "No SMP KVM support, use '-smp 1'\n");
- return -EINVAL;
- }
-
s = qemu_mallocz(sizeof(KVMState));
#ifdef KVM_CAP_SET_GUEST_DEBUG
@@ -769,6 +764,8 @@ static void kvm_handle_internal_error(CPUState *env, struct kvm_run *run)
cpu_dump_state(env, stderr, fprintf, 0);
if (run->internal.suberror == KVM_INTERNAL_ERROR_EMULATION) {
fprintf(stderr, "emulation failure\n");
+ if (!kvm_arch_stop_on_emulation_error(env))
+ return;
}
/* FIXME: Should trigger a qmp message to let management know
* something went wrong.
@@ -796,14 +793,22 @@ void kvm_flush_coalesced_mmio_buffer(void)
#endif
}
-void kvm_cpu_synchronize_state(CPUState *env)
+static void do_kvm_cpu_synchronize_state(void *_env)
{
+ CPUState *env = _env;
+
if (!env->kvm_vcpu_dirty) {
kvm_arch_get_registers(env);
env->kvm_vcpu_dirty = 1;
}
}
+void kvm_cpu_synchronize_state(CPUState *env)
+{
+ if (!env->kvm_vcpu_dirty)
+ run_on_cpu(env, do_kvm_cpu_synchronize_state, env);
+}
+
void kvm_cpu_synchronize_post_reset(CPUState *env)
{
kvm_arch_put_registers(env, KVM_PUT_RESET_STATE);
@@ -832,15 +837,22 @@ int kvm_cpu_exec(CPUState *env)
}
#endif
+ if (kvm_arch_process_irqchip_events(env)) {
+ ret = 0;
+ break;
+ }
+
if (env->kvm_vcpu_dirty) {
kvm_arch_put_registers(env, KVM_PUT_RUNTIME_STATE);
env->kvm_vcpu_dirty = 0;
}
kvm_arch_pre_run(env, run);
+ cpu_single_env = NULL;
qemu_mutex_unlock_iothread();
ret = kvm_vcpu_ioctl(env, KVM_RUN, 0);
qemu_mutex_lock_iothread();
+ cpu_single_env = env;
kvm_arch_post_run(env, run);
if (ret == -EINTR || ret == -EAGAIN) {
diff --git a/kvm.h b/kvm.h
index 70bfbf8..a28e7aa 100644
--- a/kvm.h
+++ b/kvm.h
@@ -90,6 +90,8 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run);
int kvm_arch_pre_run(CPUState *env, struct kvm_run *run);
+int kvm_arch_process_irqchip_events(CPUState *env);
+
int kvm_arch_get_registers(CPUState *env);
/* state subset only touched by the VCPU itself during runtime */
@@ -138,6 +140,8 @@ void kvm_arch_remove_all_hw_breakpoints(void);
void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg);
+bool kvm_arch_stop_on_emulation_error(CPUState *env);
+
int kvm_check_extension(KVMState *s, unsigned int extension);
uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,
diff --git a/pc-bios/README b/pc-bios/README
index 437ef1c..fc940a7 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -14,9 +14,8 @@
- OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
firmware implementation. The goal is to implement a 100% IEEE
1275-1994 (referred to as Open Firmware) compliant firmware.
- The included image for PowerPC (for 32 and 64 bit PPC CPUs) is
- built from OpenBIOS SVN revision 721, the Sparc32 and Sparc64 ones
- are built from OpenBIOS SVN revision 683.
+ The included image for PowerPC (for 32 and 64 bit PPC CPUs), Sparc32
+ and Sparc64 are built from OpenBIOS SVN revision 771.
- The PXE roms come from Rom-o-Matic gPXE 0.9.9 with BANNER_TIMEOUT=0
diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index 7a8f0d0..f27ea89 100644
--- a/pc-bios/bios.bin
+++ b/pc-bios/bios.bin
Binary files differ
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index 340fc69..34e188e 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index 4f2f45f..4c2a9f7 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index 632f938..fdb739b 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/qemu-common.h b/qemu-common.h
index 4ba0cda..a4888e5 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -249,6 +249,14 @@ void qemu_notify_event(void);
void qemu_cpu_kick(void *env);
int qemu_cpu_self(void *env);
+/* work queue */
+struct qemu_work_item {
+ struct qemu_work_item *next;
+ void (*func)(void *data);
+ void *data;
+ int done;
+};
+
#ifdef CONFIG_USER_ONLY
#define qemu_init_vcpu(env) do { } while (0)
#else
diff --git a/roms/seabios b/roms/seabios
-Subproject 8f469b9676127ba6bb52609d89ec774e61db0ee
+Subproject 7d09d0e3ba11310e973d4302c7fcc3fc2184e04
diff --git a/savevm.c b/savevm.c
index 31a419c..dc20390 100644
--- a/savevm.c
+++ b/savevm.c
@@ -991,6 +991,7 @@ typedef struct SaveStateEntry {
QTAILQ_ENTRY(SaveStateEntry) entry;
char idstr[256];
int instance_id;
+ int alias_id;
int version_id;
int section_id;
SaveSetParamsHandler *set_params;
@@ -1079,11 +1080,16 @@ void unregister_savevm(const char *idstr, void *opaque)
}
}
-int vmstate_register(int instance_id, const VMStateDescription *vmsd,
- void *opaque)
+int vmstate_register_with_alias_id(int instance_id,
+ const VMStateDescription *vmsd,
+ void *opaque, int alias_id,
+ int required_for_version)
{
SaveStateEntry *se;
+ /* If this triggers, alias support can be dropped for the vmsd. */
+ assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id);
+
se = qemu_mallocz(sizeof(SaveStateEntry));
pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);
se->version_id = vmsd->version_id;
@@ -1093,6 +1099,7 @@ int vmstate_register(int instance_id, const VMStateDescription *vmsd,
se->load_state = NULL;
se->opaque = opaque;
se->vmsd = vmsd;
+ se->alias_id = alias_id;
if (instance_id == -1) {
se->instance_id = calculate_new_instance_id(vmsd->name);
@@ -1104,6 +1111,12 @@ int vmstate_register(int instance_id, const VMStateDescription *vmsd,
return 0;
}
+int vmstate_register(int instance_id, const VMStateDescription *vmsd,
+ void *opaque)
+{
+ return vmstate_register_with_alias_id(instance_id, vmsd, opaque, -1, 0);
+}
+
void vmstate_unregister(const VMStateDescription *vmsd, void *opaque)
{
SaveStateEntry *se, *new_se;
@@ -1231,9 +1244,6 @@ void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
}
field++;
}
- if (vmsd->post_save) {
- vmsd->post_save(opaque);
- }
}
static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
@@ -1436,7 +1446,8 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id)
QTAILQ_FOREACH(se, &savevm_handlers, entry) {
if (!strcmp(se->idstr, idstr) &&
- instance_id == se->instance_id)
+ (instance_id == se->instance_id ||
+ instance_id == se->alias_id))
return se;
}
return NULL;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index f73b47b..d6b12ed 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -111,7 +111,7 @@ uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function, int reg)
* so add missing bits according to the AMD spec:
*/
cpuid_1_edx = kvm_arch_get_supported_cpuid(env, 1, R_EDX);
- ret |= cpuid_1_edx & 0xdfeff7ff;
+ ret |= cpuid_1_edx & 0x183f7ff;
break;
}
break;
@@ -949,6 +949,8 @@ int kvm_arch_put_registers(CPUState *env, int level)
{
int ret;
+ assert(cpu_is_stopped(env) || qemu_cpu_self(env));
+
ret = kvm_getput_regs(env, 1);
if (ret < 0)
return ret;
@@ -991,6 +993,8 @@ int kvm_arch_get_registers(CPUState *env)
{
int ret;
+ assert(cpu_is_stopped(env) || qemu_cpu_self(env));
+
ret = kvm_getput_regs(env, 0);
if (ret < 0)
return ret;
@@ -1069,6 +1073,22 @@ int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
return 0;
}
+int kvm_arch_process_irqchip_events(CPUState *env)
+{
+ if (env->interrupt_request & CPU_INTERRUPT_INIT) {
+ kvm_cpu_synchronize_state(env);
+ do_cpu_init(env);
+ env->exception_index = EXCP_HALTED;
+ }
+
+ if (env->interrupt_request & CPU_INTERRUPT_SIPI) {
+ kvm_cpu_synchronize_state(env);
+ do_cpu_sipi(env);
+ }
+
+ return env->halted;
+}
+
static int kvm_handle_halt(CPUState *env)
{
if (!((env->interrupt_request & CPU_INTERRUPT_HARD) &&
@@ -1269,3 +1289,10 @@ void kvm_arch_update_guest_debug(CPUState *env, struct kvm_guest_debug *dbg)
}
}
#endif /* KVM_CAP_SET_GUEST_DEBUG */
+
+bool kvm_arch_stop_on_emulation_error(CPUState *env)
+{
+ return !(env->cr[0] & CR0_PE_MASK) ||
+ ((env->segs[R_CS].selector & 3) != 3);
+}
+
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index aa3d432..2625cb8 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -224,6 +224,11 @@ int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
return 0;
}
+int kvm_arch_process_irqchip_events(CPUState *env)
+{
+ return 0;
+}
+
static int kvmppc_handle_halt(CPUState *env)
{
if (!(env->interrupt_request & CPU_INTERRUPT_HARD) && (msr_ee)) {
@@ -321,3 +326,8 @@ uint32_t kvmppc_get_tbfreq(void)
retval = atoi(ns);
return retval;
}
+
+bool kvm_arch_stop_on_emulation_error(CPUState *env)
+{
+ return true;
+}
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 72e77b0..a2d7741 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -175,6 +175,11 @@ int kvm_arch_post_run(CPUState *env, struct kvm_run *run)
return 0;
}
+int kvm_arch_process_irqchip_events(CPUState *env)
+{
+ return 0;
+}
+
static void kvm_s390_interrupt_internal(CPUState *env, int type, uint32_t parm,
uint64_t parm64, int vm)
{
@@ -480,3 +485,8 @@ int kvm_arch_handle_exit(CPUState *env, struct kvm_run *run)
return ret;
}
+
+bool kvm_arch_stop_on_emulation_error(CPUState *env)
+{
+ return true;
+}
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 22f3ad0..27b020b 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -79,7 +79,7 @@
#define TT_DPROT 0x6c
#define TT_SPILL 0x80
#define TT_FILL 0xc0
-#define TT_WOTHER 0x10
+#define TT_WOTHER (1 << 5)
#define TT_TRAP 0x100
#endif
diff --git a/target-sparc/exec.h b/target-sparc/exec.h
index 1e9de82..c84e055 100644
--- a/target-sparc/exec.h
+++ b/target-sparc/exec.h
@@ -5,11 +5,6 @@
register struct CPUSPARCState *env asm(AREG0);
-#define DT0 (env->dt0)
-#define DT1 (env->dt1)
-#define QT0 (env->qt0)
-#define QT1 (env->qt1)
-
#include "cpu.h"
#include "exec-all.h"
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 4642122..582de10 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -1490,7 +1490,7 @@ void cpu_dump_state(CPUState *env, FILE *f,
}
#ifdef TARGET_SPARC64
cpu_fprintf(f, "pstate: %08x ccr: %02x (icc: ", env->pstate,
- cpu_get_ccr(env));
+ (unsigned)cpu_get_ccr(env));
cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << PSR_CARRY_SHIFT);
cpu_fprintf(f, " xcc: ");
cpu_print_cc(f, cpu_fprintf, cpu_get_ccr(env) << (PSR_CARRY_SHIFT - 4));
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index fcfd3f3..b1451d3 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -44,6 +44,11 @@
#endif
#endif
+#define DT0 (env->dt0)
+#define DT1 (env->dt1)
+#define QT0 (env->qt0)
+#define QT1 (env->qt1)
+
#if defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
static void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
int is_asi, int size);
@@ -2877,7 +2882,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
return;
}
case 0x57: // I-MMU demap
- demap_tlb(env->itlb, val, "immu", env);
+ demap_tlb(env->itlb, addr, "immu", env);
return;
case 0x58: // D-MMU regs
{
@@ -2942,7 +2947,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
return;
}
case 0x5f: // D-MMU demap
- demap_tlb(env->dtlb, val, "dmmu", env);
+ demap_tlb(env->dtlb, addr, "dmmu", env);
return;
case 0x49: // Interrupt data receive
// XXX