diff options
-rw-r--r-- | Makefile.objs | 2 | ||||
-rw-r--r-- | Makefile.target | 4 | ||||
-rw-r--r-- | cpu-all.h | 2 | ||||
-rw-r--r-- | cpu-defs.h | 6 | ||||
-rw-r--r-- | cpu-exec.c | 7 | ||||
-rw-r--r-- | cpus.c | 90 | ||||
-rw-r--r-- | exec-all.h | 3 | ||||
-rw-r--r-- | exec.c | 8 | ||||
-rw-r--r-- | hw/acpi.c | 745 | ||||
-rw-r--r-- | hw/acpi.h | 78 | ||||
-rw-r--r-- | hw/acpi_piix4.c | 599 | ||||
-rw-r--r-- | hw/apb_pci.c | 7 | ||||
-rw-r--r-- | hw/apm.c | 86 | ||||
-rw-r--r-- | hw/apm.h | 22 | ||||
-rw-r--r-- | hw/e1000.c | 4 | ||||
-rw-r--r-- | hw/fdc.c | 35 | ||||
-rw-r--r-- | hw/fdc.h | 5 | ||||
-rw-r--r-- | hw/hw.h | 5 | ||||
-rw-r--r-- | hw/ide/core.c | 2 | ||||
-rw-r--r-- | hw/mc146818rtc.c | 47 | ||||
-rw-r--r-- | hw/mc146818rtc.h | 10 | ||||
-rw-r--r-- | hw/mips_jazz.c | 1 | ||||
-rw-r--r-- | hw/mips_malta.c | 3 | ||||
-rw-r--r-- | hw/mips_r4k.c | 3 | ||||
-rw-r--r-- | hw/pc.c | 423 | ||||
-rw-r--r-- | hw/pc.h | 48 | ||||
-rw-r--r-- | hw/pc_piix.c | 316 | ||||
-rw-r--r-- | hw/pci.c | 8 | ||||
-rw-r--r-- | hw/pci.h | 4 | ||||
-rw-r--r-- | hw/pckbd.c | 4 | ||||
-rw-r--r-- | hw/piix_pci.c | 5 | ||||
-rw-r--r-- | hw/pm_smbus.c | 176 | ||||
-rw-r--r-- | hw/pm_smbus.h | 21 | ||||
-rw-r--r-- | hw/ppc_prep.c | 1 | ||||
-rw-r--r-- | hw/qdev.c | 16 | ||||
-rw-r--r-- | hw/qdev.h | 4 | ||||
-rw-r--r-- | hw/serial.c | 13 | ||||
-rw-r--r-- | hw/sm501.c | 172 | ||||
-rw-r--r-- | hw/tmp105.c | 9 | ||||
-rw-r--r-- | hw/vga.c | 10 | ||||
-rw-r--r-- | ia64-dis.c | 10 | ||||
-rw-r--r-- | kvm-all.c | 24 | ||||
-rw-r--r-- | kvm.h | 4 | ||||
-rw-r--r-- | pc-bios/README | 5 | ||||
-rw-r--r-- | pc-bios/bios.bin | bin | 131072 -> 131072 bytes | |||
-rw-r--r-- | pc-bios/openbios-ppc | bin | 312132 -> 312028 bytes | |||
-rw-r--r-- | pc-bios/openbios-sparc32 | bin | 217668 -> 217664 bytes | |||
-rw-r--r-- | pc-bios/openbios-sparc64 | bin | 1065880 -> 1065872 bytes | |||
-rw-r--r-- | qemu-common.h | 8 | ||||
m--------- | roms/seabios | 0 | ||||
-rw-r--r-- | savevm.c | 23 | ||||
-rw-r--r-- | target-i386/kvm.c | 29 | ||||
-rw-r--r-- | target-ppc/kvm.c | 10 | ||||
-rw-r--r-- | target-s390x/kvm.c | 10 | ||||
-rw-r--r-- | target-sparc/cpu.h | 2 | ||||
-rw-r--r-- | target-sparc/exec.h | 5 | ||||
-rw-r--r-- | target-sparc/helper.c | 2 | ||||
-rw-r--r-- | target-sparc/op_helper.c | 9 |
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 @@ -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) @@ -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; \ @@ -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 */ @@ -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; } @@ -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 @@ -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); @@ -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 */ @@ -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)) { @@ -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), @@ -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 @@ -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]; @@ -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, §ors); 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); @@ -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); @@ -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; } @@ -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); @@ -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 @@ -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) { @@ -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), @@ -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), @@ -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, @@ -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] = { @@ -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) { @@ -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 Binary files differindex 7a8f0d0..f27ea89 100644 --- a/pc-bios/bios.bin +++ b/pc-bios/bios.bin diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc Binary files differindex 340fc69..34e188e 100644 --- a/pc-bios/openbios-ppc +++ b/pc-bios/openbios-ppc diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32 Binary files differindex 4f2f45f..4c2a9f7 100644 --- a/pc-bios/openbios-sparc32 +++ b/pc-bios/openbios-sparc32 diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64 Binary files differindex 632f938..fdb739b 100644 --- a/pc-bios/openbios-sparc64 +++ b/pc-bios/openbios-sparc64 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 @@ -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 |