diff options
77 files changed, 1688 insertions, 834 deletions
diff --git a/.gitignore b/.gitignore index 3efb4ecc13..26703e12d6 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,8 @@ QMP/qmp-commands.txt *.vr *.d *.o +*.swp +*.orig .pc patches pc-bios/bios-pq/status @@ -60,3 +62,4 @@ pc-bios/optionrom/multiboot.bin pc-bios/optionrom/multiboot.raw .stgit-* cscope.* +tags diff --git a/Makefile.objs b/Makefile.objs index 353b1a8318..b21f9d3894 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -141,7 +141,7 @@ common-obj-y += $(addprefix ui/, $(ui-obj-y)) common-obj-y += iov.o acl.o common-obj-$(CONFIG_THREAD) += qemu-thread.o -common-obj-$(CONFIG_IOTHREAD) += compatfd.o +common-obj-$(CONFIG_POSIX) += compatfd.o common-obj-y += notify.o event_notifier.o common-obj-y += qemu-timer.o qemu-timer-common.o @@ -195,6 +195,7 @@ hw-obj-$(CONFIG_FDC) += fdc.o hw-obj-$(CONFIG_ACPI) += acpi.o acpi_piix4.o hw-obj-$(CONFIG_APM) += pm_smbus.o apm.o hw-obj-$(CONFIG_DMA) += dma.o +hw-obj-$(CONFIG_HPET) += hpet.o # PPC devices hw-obj-$(CONFIG_OPENPIC) += openpic.o @@ -258,6 +259,7 @@ hw-obj-$(CONFIG_VGA_PCI) += vga-pci.o hw-obj-$(CONFIG_VGA_ISA) += vga-isa.o hw-obj-$(CONFIG_VGA_ISA_MM) += vga-isa-mm.o hw-obj-$(CONFIG_VMWARE_VGA) += vmware_vga.o +hw-obj-$(CONFIG_VMMOUSE) += vmmouse.o hw-obj-$(CONFIG_RC4030) += rc4030.o hw-obj-$(CONFIG_DP8393X) += dp8393x.o diff --git a/Makefile.target b/Makefile.target index 48e6c00a5d..5a0fd40696 100644 --- a/Makefile.target +++ b/Makefile.target @@ -37,7 +37,7 @@ ifndef CONFIG_HAIKU LIBS+=-lm endif -kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS) +kvm.o kvm-all.o vhost.o vhost_net.o kvmclock.o: QEMU_CFLAGS+=$(KVM_CFLAGS) config-target.h: config-target.h-timestamp config-target.h-timestamp: config-target.mak @@ -215,10 +215,10 @@ obj-$(CONFIG_KVM) += ivshmem.o obj-i386-y += vga.o obj-i386-y += mc146818rtc.o i8259.o pc.o obj-i386-y += cirrus_vga.o apic.o ioapic.o piix_pci.o -obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o +obj-i386-y += vmport.o applesmc.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 += pc_piix.o +obj-i386-y += pc_piix.o kvmclock.o obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o # shared objects diff --git a/configure b/configure index 598e8e1ebb..a3f53456f4 100755 --- a/configure +++ b/configure @@ -2057,6 +2057,12 @@ EOF if compile_prog "" "" ; then signalfd=yes +elif test "$kvm" = "yes" -a "$io_thread" != "yes"; then + echo + echo "ERROR: Host kernel lacks signalfd() support," + echo "but KVM depends on it when the IO thread is disabled." + echo + exit 1 fi # check if eventfd is supported diff --git a/cpu-all.h b/cpu-all.h index ffbd6a4df8..87b0f86667 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -959,6 +959,12 @@ int cpu_physical_memory_get_dirty_tracking(void); int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, target_phys_addr_t end_addr); +int cpu_physical_log_start(target_phys_addr_t start_addr, + ram_addr_t size); + +int cpu_physical_log_stop(target_phys_addr_t start_addr, + ram_addr_t size); + void dump_exec_info(FILE *f, fprintf_function cpu_fprintf); #endif /* !CONFIG_USER_ONLY */ diff --git a/cpu-common.h b/cpu-common.h index 6d4a898ad1..54d21d4717 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -96,6 +96,10 @@ struct CPUPhysMemoryClient { target_phys_addr_t end_addr); int (*migration_log)(struct CPUPhysMemoryClient *client, int enable); + int (*log_start)(struct CPUPhysMemoryClient *client, + target_phys_addr_t phys_addr, ram_addr_t size); + int (*log_stop)(struct CPUPhysMemoryClient *client, + target_phys_addr_t phys_addr, ram_addr_t size); QLIST_ENTRY(CPUPhysMemoryClient) list; }; diff --git a/cpu-defs.h b/cpu-defs.h index 8d4bf86c53..db809ed465 100644 --- a/cpu-defs.h +++ b/cpu-defs.h @@ -205,6 +205,7 @@ typedef struct CPUWatchpoint { uint32_t stopped; /* Artificially stopped */ \ struct QemuThread *thread; \ struct QemuCond *halt_cond; \ + int thread_kicked; \ struct qemu_work_item *queued_work_first, *queued_work_last; \ const char *cpu_model_str; \ struct KVMState *kvm_state; \ diff --git a/cpu-exec.c b/cpu-exec.c index 8c9fb8b1a2..b03b3a749a 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -196,28 +196,6 @@ static inline TranslationBlock *tb_find_fast(void) return tb; } -static CPUDebugExcpHandler *debug_excp_handler; - -CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler) -{ - CPUDebugExcpHandler *old_handler = debug_excp_handler; - - debug_excp_handler = handler; - return old_handler; -} - -static void cpu_handle_debug_exception(CPUState *env) -{ - CPUWatchpoint *wp; - - if (!env->watchpoint_hit) - QTAILQ_FOREACH(wp, &env->watchpoints, entry) - wp->flags &= ~BP_WATCHPOINT_HIT; - - if (debug_excp_handler) - debug_excp_handler(env); -} - /* main execution loop */ volatile sig_atomic_t exit_request; @@ -248,13 +226,11 @@ int cpu_exec(CPUState *env1) } #if defined(TARGET_I386) - if (!kvm_enabled()) { - /* put eflags in CPU temporary format */ - CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - DF = 1 - (2 * ((env->eflags >> 10) & 1)); - CC_OP = CC_OP_EFLAGS; - env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); - } + /* put eflags in CPU temporary format */ + CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); + DF = 1 - (2 * ((env->eflags >> 10) & 1)); + CC_OP = CC_OP_EFLAGS; + env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); #elif defined(TARGET_SPARC) #elif defined(TARGET_M68K) env->cc_op = CC_OP_FLAGS; @@ -279,7 +255,7 @@ int cpu_exec(CPUState *env1) if (setjmp(env->jmp_env) == 0) { #if defined(__sparc__) && !defined(CONFIG_SOLARIS) #undef env - env = cpu_single_env; + env = cpu_single_env; #define env cpu_single_env #endif /* if an exception is pending, we execute it here */ @@ -287,8 +263,6 @@ int cpu_exec(CPUState *env1) if (env->exception_index >= EXCP_INTERRUPT) { /* exit request from the cpu execution loop */ ret = env->exception_index; - if (ret == EXCP_DEBUG) - cpu_handle_debug_exception(env); break; } else { #if defined(CONFIG_USER_ONLY) @@ -340,11 +314,6 @@ int cpu_exec(CPUState *env1) } } - if (kvm_enabled()) { - kvm_cpu_exec(env); - longjmp(env->jmp_env, 1); - } - next_tb = 0; /* force lookup of first TB */ for(;;) { interrupt_request = env->interrupt_request; diff --git a/cpus.c b/cpus.c index 4c9928e2ce..0f339459a5 100644 --- a/cpus.c +++ b/cpus.c @@ -34,9 +34,6 @@ #include "cpus.h" #include "compatfd.h" -#ifdef CONFIG_LINUX -#include <sys/prctl.h> -#endif #ifdef SIGRTMIN #define SIG_IPI (SIGRTMIN+4) @@ -44,10 +41,24 @@ #define SIG_IPI SIGUSR1 #endif +#ifdef CONFIG_LINUX + +#include <sys/prctl.h> + #ifndef PR_MCE_KILL #define PR_MCE_KILL 33 #endif +#ifndef PR_MCE_KILL_SET +#define PR_MCE_KILL_SET 1 +#endif + +#ifndef PR_MCE_KILL_EARLY +#define PR_MCE_KILL_EARLY 1 +#endif + +#endif /* CONFIG_LINUX */ + static CPUState *next_cpu; /***********************************************************/ @@ -119,44 +130,116 @@ static void do_vm_stop(int reason) static int cpu_can_run(CPUState *env) { - if (env->stop) + if (env->stop) { return 0; - if (env->stopped || !vm_running) + } + if (env->stopped || !vm_running) { return 0; + } return 1; } -static int cpu_has_work(CPUState *env) +static bool cpu_thread_is_idle(CPUState *env) { - if (env->stop) - return 1; - if (env->queued_work_first) - return 1; - if (env->stopped || !vm_running) - return 0; - if (!env->halted) - return 1; - if (qemu_cpu_has_work(env)) - return 1; - return 0; + if (env->stop || env->queued_work_first) { + return false; + } + if (env->stopped || !vm_running) { + return true; + } + if (!env->halted || qemu_cpu_has_work(env)) { + return false; + } + return true; } -static int any_cpu_has_work(void) +static bool all_cpu_threads_idle(void) { CPUState *env; - for (env = first_cpu; env != NULL; env = env->next_cpu) - if (cpu_has_work(env)) - return 1; - return 0; + for (env = first_cpu; env != NULL; env = env->next_cpu) { + if (!cpu_thread_is_idle(env)) { + return false; + } + } + return true; } -static void cpu_debug_handler(CPUState *env) +static CPUDebugExcpHandler *debug_excp_handler; + +CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler) +{ + CPUDebugExcpHandler *old_handler = debug_excp_handler; + + debug_excp_handler = handler; + return old_handler; +} + +static void cpu_handle_debug_exception(CPUState *env) { + CPUWatchpoint *wp; + + if (!env->watchpoint_hit) { + QTAILQ_FOREACH(wp, &env->watchpoints, entry) { + wp->flags &= ~BP_WATCHPOINT_HIT; + } + } + if (debug_excp_handler) { + debug_excp_handler(env); + } + gdb_set_stop_cpu(env); - debug_requested = EXCP_DEBUG; - vm_stop(EXCP_DEBUG); + qemu_system_debug_request(); +#ifdef CONFIG_IOTHREAD + env->stopped = 1; +#endif +} + +#ifdef CONFIG_LINUX +static void sigbus_reraise(void) +{ + sigset_t set; + struct sigaction action; + + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_DFL; + if (!sigaction(SIGBUS, &action, NULL)) { + raise(SIGBUS); + sigemptyset(&set); + sigaddset(&set, SIGBUS); + sigprocmask(SIG_UNBLOCK, &set, NULL); + } + perror("Failed to re-raise SIGBUS!\n"); + abort(); +} + +static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo, + void *ctx) +{ + if (kvm_on_sigbus(siginfo->ssi_code, + (void *)(intptr_t)siginfo->ssi_addr)) { + sigbus_reraise(); + } +} + +static void qemu_init_sigbus(void) +{ + struct sigaction action; + + memset(&action, 0, sizeof(action)); + action.sa_flags = SA_SIGINFO; + action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler; + sigaction(SIGBUS, &action, NULL); + + prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0); +} + +#else /* !CONFIG_LINUX */ + +static void qemu_init_sigbus(void) +{ } +#endif /* !CONFIG_LINUX */ #ifndef _WIN32 static int io_thread_fd = -1; @@ -167,9 +250,9 @@ static void qemu_event_increment(void) static const uint64_t val = 1; ssize_t ret; - if (io_thread_fd == -1) + if (io_thread_fd == -1) { return; - + } do { ret = write(io_thread_fd, &val, sizeof(val)); } while (ret < 0 && errno == EINTR); @@ -200,17 +283,17 @@ static int qemu_event_init(void) int fds[2]; err = qemu_eventfd(fds); - if (err == -1) + if (err == -1) { return -errno; - + } err = fcntl_setfl(fds[0], O_NONBLOCK); - if (err < 0) + if (err < 0) { goto fail; - + } err = fcntl_setfl(fds[1], O_NONBLOCK); - if (err < 0) + if (err < 0) { goto fail; - + } qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL, (void *)(unsigned long)fds[0]); @@ -222,7 +305,109 @@ fail: close(fds[1]); return err; } -#else + +static void dummy_signal(int sig) +{ +} + +/* If we have signalfd, we mask out the signals we want to handle and then + * use signalfd to listen for them. We rely on whatever the current signal + * handler is to dispatch the signals when we receive them. + */ +static void sigfd_handler(void *opaque) +{ + int fd = (unsigned long) opaque; + struct qemu_signalfd_siginfo info; + struct sigaction action; + ssize_t len; + + while (1) { + do { + len = read(fd, &info, sizeof(info)); + } while (len == -1 && errno == EINTR); + + if (len == -1 && errno == EAGAIN) { + break; + } + + if (len != sizeof(info)) { + printf("read from sigfd returned %zd: %m\n", len); + return; + } + + sigaction(info.ssi_signo, NULL, &action); + if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) { + action.sa_sigaction(info.ssi_signo, + (siginfo_t *)&info, NULL); + } else if (action.sa_handler) { + action.sa_handler(info.ssi_signo); + } + } +} + +static int qemu_signalfd_init(sigset_t mask) +{ + int sigfd; + + sigfd = qemu_signalfd(&mask); + if (sigfd == -1) { + fprintf(stderr, "failed to create signalfd\n"); + return -errno; + } + + fcntl_setfl(sigfd, O_NONBLOCK); + + qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL, + (void *)(unsigned long) sigfd); + + return 0; +} + +static void qemu_kvm_eat_signals(CPUState *env) +{ + struct timespec ts = { 0, 0 }; + siginfo_t siginfo; + sigset_t waitset; + sigset_t chkset; + int r; + + sigemptyset(&waitset); + sigaddset(&waitset, SIG_IPI); + sigaddset(&waitset, SIGBUS); + + do { + r = sigtimedwait(&waitset, &siginfo, &ts); + if (r == -1 && !(errno == EAGAIN || errno == EINTR)) { + perror("sigtimedwait"); + exit(1); + } + + switch (r) { + case SIGBUS: + if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) { + sigbus_reraise(); + } + break; + default: + break; + } + + r = sigpending(&chkset); + if (r == -1) { + perror("sigpending"); + exit(1); + } + } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS)); + +#ifndef CONFIG_IOTHREAD + if (sigismember(&chkset, SIGIO) || sigismember(&chkset, SIGALRM)) { + qemu_notify_event(); + } +#endif +} + +#else /* _WIN32 */ + HANDLE qemu_event_handle; static void dummy_event_handler(void *opaque) @@ -248,12 +433,78 @@ static void qemu_event_increment(void) exit (1); } } -#endif + +static void qemu_kvm_eat_signals(CPUState *env) +{ +} +#endif /* _WIN32 */ #ifndef CONFIG_IOTHREAD +static void qemu_kvm_init_cpu_signals(CPUState *env) +{ +#ifndef _WIN32 + int r; + sigset_t set; + struct sigaction sigact; + + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_handler = dummy_signal; + sigaction(SIG_IPI, &sigact, NULL); + + sigemptyset(&set); + sigaddset(&set, SIG_IPI); + sigaddset(&set, SIGIO); + sigaddset(&set, SIGALRM); + pthread_sigmask(SIG_BLOCK, &set, NULL); + + pthread_sigmask(SIG_BLOCK, NULL, &set); + sigdelset(&set, SIG_IPI); + sigdelset(&set, SIGBUS); + sigdelset(&set, SIGIO); + sigdelset(&set, SIGALRM); + r = kvm_set_signal_mask(env, &set); + if (r) { + fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r)); + exit(1); + } +#endif +} + +#ifndef _WIN32 +static sigset_t block_synchronous_signals(void) +{ + sigset_t set; + + sigemptyset(&set); + sigaddset(&set, SIGBUS); + if (kvm_enabled()) { + /* + * We need to process timer signals synchronously to avoid a race + * between exit_request check and KVM vcpu entry. + */ + sigaddset(&set, SIGIO); + sigaddset(&set, SIGALRM); + } + + return set; +} +#endif + int qemu_init_main_loop(void) { - cpu_set_debug_excp_handler(cpu_debug_handler); +#ifndef _WIN32 + sigset_t blocked_signals; + int ret; + + blocked_signals = block_synchronous_signals(); + + ret = qemu_signalfd_init(blocked_signals); + if (ret) { + return ret; + } +#endif + + qemu_init_sigbus(); return qemu_event_init(); } @@ -265,12 +516,19 @@ void qemu_main_loop_start(void) void qemu_init_vcpu(void *_env) { CPUState *env = _env; + int r; env->nr_cores = smp_cores; env->nr_threads = smp_threads; - if (kvm_enabled()) - kvm_init_vcpu(env); - return; + + if (kvm_enabled()) { + r = kvm_init_vcpu(env); + if (r < 0) { + fprintf(stderr, "kvm_init_vcpu failed: %s\n", strerror(-r)); + exit(1); + } + qemu_kvm_init_cpu_signals(env); + } } int qemu_cpu_self(void *env) @@ -293,7 +551,17 @@ void pause_all_vcpus(void) void qemu_cpu_kick(void *env) { - return; +} + +void qemu_cpu_kick_self(void) +{ +#ifndef _WIN32 + assert(cpu_single_env); + + raise(SIG_IPI); +#else + abort(); +#endif } void qemu_notify_event(void) @@ -307,11 +575,16 @@ void qemu_notify_event(void) if (next_cpu && env != next_cpu) { cpu_exit(next_cpu); } + exit_request = 1; } void qemu_mutex_lock_iothread(void) {} void qemu_mutex_unlock_iothread(void) {} +void cpu_stop_current(void) +{ +} + void vm_stop(int reason) { do_vm_stop(reason); @@ -337,61 +610,65 @@ static QemuCond qemu_system_cond; static QemuCond qemu_pause_cond; static QemuCond qemu_work_cond; -static void tcg_init_ipi(void); -static void kvm_init_ipi(CPUState *env); -static sigset_t block_io_signals(void); - -/* If we have signalfd, we mask out the signals we want to handle and then - * use signalfd to listen for them. We rely on whatever the current signal - * handler is to dispatch the signals when we receive them. - */ -static void sigfd_handler(void *opaque) +static void cpu_signal(int sig) { - int fd = (unsigned long) opaque; - struct qemu_signalfd_siginfo info; - struct sigaction action; - ssize_t len; - - while (1) { - do { - len = read(fd, &info, sizeof(info)); - } while (len == -1 && errno == EINTR); + if (cpu_single_env) { + cpu_exit(cpu_single_env); + } + exit_request = 1; +} - if (len == -1 && errno == EAGAIN) { - break; - } +static void qemu_kvm_init_cpu_signals(CPUState *env) +{ + int r; + sigset_t set; + struct sigaction sigact; - if (len != sizeof(info)) { - printf("read from sigfd returned %zd: %m\n", len); - return; - } + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_handler = dummy_signal; + sigaction(SIG_IPI, &sigact, NULL); - sigaction(info.ssi_signo, NULL, &action); - if ((action.sa_flags & SA_SIGINFO) && action.sa_sigaction) { - action.sa_sigaction(info.ssi_signo, - (siginfo_t *)&info, NULL); - } else if (action.sa_handler) { - action.sa_handler(info.ssi_signo); - } + pthread_sigmask(SIG_BLOCK, NULL, &set); + sigdelset(&set, SIG_IPI); + sigdelset(&set, SIGBUS); + r = kvm_set_signal_mask(env, &set); + if (r) { + fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(-r)); + exit(1); } } -static int qemu_signalfd_init(sigset_t mask) +static void qemu_tcg_init_cpu_signals(void) { - int sigfd; + sigset_t set; + struct sigaction sigact; - sigfd = qemu_signalfd(&mask); - if (sigfd == -1) { - fprintf(stderr, "failed to create signalfd\n"); - return -errno; - } + memset(&sigact, 0, sizeof(sigact)); + sigact.sa_handler = cpu_signal; + sigaction(SIG_IPI, &sigact, NULL); - fcntl_setfl(sigfd, O_NONBLOCK); + sigemptyset(&set); + sigaddset(&set, SIG_IPI); + pthread_sigmask(SIG_UNBLOCK, &set, NULL); +} - qemu_set_fd_handler2(sigfd, NULL, sigfd_handler, NULL, - (void *)(unsigned long) sigfd); +static sigset_t block_io_signals(void) +{ + sigset_t set; - return 0; + /* SIGUSR2 used by posix-aio-compat.c */ + sigemptyset(&set); + sigaddset(&set, SIGUSR2); + pthread_sigmask(SIG_UNBLOCK, &set, NULL); + + sigemptyset(&set); + sigaddset(&set, SIGIO); + sigaddset(&set, SIGALRM); + sigaddset(&set, SIG_IPI); + sigaddset(&set, SIGBUS); + pthread_sigmask(SIG_BLOCK, &set, NULL); + + return set; } int qemu_init_main_loop(void) @@ -399,21 +676,25 @@ int qemu_init_main_loop(void) int ret; sigset_t blocked_signals; - cpu_set_debug_excp_handler(cpu_debug_handler); + qemu_init_sigbus(); blocked_signals = block_io_signals(); ret = qemu_signalfd_init(blocked_signals); - if (ret) + if (ret) { return ret; + } /* Note eventfd must be drained before signalfd handlers run */ ret = qemu_event_init(); - if (ret) + if (ret) { return ret; + } - qemu_cond_init(&qemu_pause_cond); + qemu_cond_init(&qemu_cpu_cond); qemu_cond_init(&qemu_system_cond); + qemu_cond_init(&qemu_pause_cond); + qemu_cond_init(&qemu_work_cond); qemu_mutex_init(&qemu_fair_mutex); qemu_mutex_init(&qemu_global_mutex); qemu_mutex_lock(&qemu_global_mutex); @@ -440,10 +721,11 @@ void run_on_cpu(CPUState *env, void (*func)(void *data), void *data) wi.func = func; wi.data = data; - if (!env->queued_work_first) + if (!env->queued_work_first) { env->queued_work_first = &wi; - else + } else { env->queued_work_last->next = &wi; + } env->queued_work_last = &wi; wi.next = NULL; wi.done = false; @@ -461,8 +743,9 @@ static void flush_queued_work(CPUState *env) { struct qemu_work_item *wi; - if (!env->queued_work_first) + if (!env->queued_work_first) { return; + } while ((wi = env->queued_work_first)) { env->queued_work_first = wi->next; @@ -481,14 +764,16 @@ static void qemu_wait_io_event_common(CPUState *env) qemu_cond_signal(&qemu_pause_cond); } flush_queued_work(env); + env->thread_kicked = false; } static void qemu_tcg_wait_io_event(void) { CPUState *env; - while (!any_cpu_has_work()) + while (all_cpu_threads_idle()) { qemu_cond_timedwait(tcg_halt_cond, &qemu_global_mutex, 1000); + } qemu_mutex_unlock(&qemu_global_mutex); @@ -507,134 +792,72 @@ static void qemu_tcg_wait_io_event(void) } } -static void sigbus_reraise(void) -{ - sigset_t set; - struct sigaction action; - - memset(&action, 0, sizeof(action)); - action.sa_handler = SIG_DFL; - if (!sigaction(SIGBUS, &action, NULL)) { - raise(SIGBUS); - sigemptyset(&set); - sigaddset(&set, SIGBUS); - sigprocmask(SIG_UNBLOCK, &set, NULL); - } - perror("Failed to re-raise SIGBUS!\n"); - abort(); -} - -static void sigbus_handler(int n, struct qemu_signalfd_siginfo *siginfo, - void *ctx) -{ -#if defined(TARGET_I386) - if (kvm_on_sigbus(siginfo->ssi_code, (void *)(intptr_t)siginfo->ssi_addr)) -#endif - sigbus_reraise(); -} - -static void qemu_kvm_eat_signal(CPUState *env, int timeout) -{ - struct timespec ts; - int r, e; - siginfo_t siginfo; - sigset_t waitset; - sigset_t chkset; - - ts.tv_sec = timeout / 1000; - ts.tv_nsec = (timeout % 1000) * 1000000; - - sigemptyset(&waitset); - sigaddset(&waitset, SIG_IPI); - sigaddset(&waitset, SIGBUS); - - do { - qemu_mutex_unlock(&qemu_global_mutex); - - r = sigtimedwait(&waitset, &siginfo, &ts); - e = errno; - - qemu_mutex_lock(&qemu_global_mutex); - - if (r == -1 && !(e == EAGAIN || e == EINTR)) { - fprintf(stderr, "sigtimedwait: %s\n", strerror(e)); - exit(1); - } - - switch (r) { - case SIGBUS: -#ifdef TARGET_I386 - if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) -#endif - sigbus_reraise(); - break; - default: - break; - } - - r = sigpending(&chkset); - if (r == -1) { - fprintf(stderr, "sigpending: %s\n", strerror(e)); - exit(1); - } - } while (sigismember(&chkset, SIG_IPI) || sigismember(&chkset, SIGBUS)); -} - static void qemu_kvm_wait_io_event(CPUState *env) { - while (!cpu_has_work(env)) + while (cpu_thread_is_idle(env)) { qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000); + } - qemu_kvm_eat_signal(env, 0); + qemu_kvm_eat_signals(env); qemu_wait_io_event_common(env); } -static int qemu_cpu_exec(CPUState *env); - -static void *kvm_cpu_thread_fn(void *arg) +static void *qemu_kvm_cpu_thread_fn(void *arg) { CPUState *env = arg; + int r; qemu_mutex_lock(&qemu_global_mutex); qemu_thread_self(env->thread); - if (kvm_enabled()) - kvm_init_vcpu(env); - kvm_init_ipi(env); + r = kvm_init_vcpu(env); + if (r < 0) { + fprintf(stderr, "kvm_init_vcpu failed: %s\n", strerror(-r)); + exit(1); + } + + qemu_kvm_init_cpu_signals(env); /* signal CPU creation */ env->created = 1; qemu_cond_signal(&qemu_cpu_cond); /* and wait for machine initialization */ - while (!qemu_system_ready) + while (!qemu_system_ready) { qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); + } while (1) { - if (cpu_can_run(env)) - qemu_cpu_exec(env); + if (cpu_can_run(env)) { + r = kvm_cpu_exec(env); + if (r == EXCP_DEBUG) { + cpu_handle_debug_exception(env); + } + } qemu_kvm_wait_io_event(env); } return NULL; } -static void *tcg_cpu_thread_fn(void *arg) +static void *qemu_tcg_cpu_thread_fn(void *arg) { CPUState *env = arg; - tcg_init_ipi(); + qemu_tcg_init_cpu_signals(); qemu_thread_self(env->thread); /* signal CPU creation */ qemu_mutex_lock(&qemu_global_mutex); - for (env = first_cpu; env != NULL; env = env->next_cpu) + for (env = first_cpu; env != NULL; env = env->next_cpu) { env->created = 1; + } qemu_cond_signal(&qemu_cpu_cond); /* and wait for machine initialization */ - while (!qemu_system_ready) + while (!qemu_system_ready) { qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100); + } while (1) { cpu_exec_all(); @@ -647,89 +870,32 @@ static void *tcg_cpu_thread_fn(void *arg) void qemu_cpu_kick(void *_env) { CPUState *env = _env; - qemu_cond_broadcast(env->halt_cond); - qemu_thread_signal(env->thread, SIG_IPI); -} - -int qemu_cpu_self(void *_env) -{ - CPUState *env = _env; - QemuThread this; - - qemu_thread_self(&this); - - return qemu_thread_equal(&this, env->thread); -} - -static void cpu_signal(int sig) -{ - if (cpu_single_env) - cpu_exit(cpu_single_env); - exit_request = 1; -} - -static void tcg_init_ipi(void) -{ - sigset_t set; - struct sigaction sigact; - - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = cpu_signal; - sigaction(SIG_IPI, &sigact, NULL); - sigemptyset(&set); - sigaddset(&set, SIG_IPI); - pthread_sigmask(SIG_UNBLOCK, &set, NULL); -} - -static void dummy_signal(int sig) -{ + qemu_cond_broadcast(env->halt_cond); + if (!env->thread_kicked) { + qemu_thread_signal(env->thread, SIG_IPI); + env->thread_kicked = true; + } } -static void kvm_init_ipi(CPUState *env) +void qemu_cpu_kick_self(void) { - int r; - sigset_t set; - struct sigaction sigact; - - memset(&sigact, 0, sizeof(sigact)); - sigact.sa_handler = dummy_signal; - sigaction(SIG_IPI, &sigact, NULL); + assert(cpu_single_env); - pthread_sigmask(SIG_BLOCK, NULL, &set); - sigdelset(&set, SIG_IPI); - sigdelset(&set, SIGBUS); - r = kvm_set_signal_mask(env, &set); - if (r) { - fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r)); - exit(1); + if (!cpu_single_env->thread_kicked) { + qemu_thread_signal(cpu_single_env->thread, SIG_IPI); + cpu_single_env->thread_kicked = true; } } -static sigset_t block_io_signals(void) +int qemu_cpu_self(void *_env) { - sigset_t set; - struct sigaction action; - - /* SIGUSR2 used by posix-aio-compat.c */ - sigemptyset(&set); - sigaddset(&set, SIGUSR2); - pthread_sigmask(SIG_UNBLOCK, &set, NULL); - - sigemptyset(&set); - sigaddset(&set, SIGIO); - sigaddset(&set, SIGALRM); - sigaddset(&set, SIG_IPI); - sigaddset(&set, SIGBUS); - pthread_sigmask(SIG_BLOCK, &set, NULL); + CPUState *env = _env; + QemuThread this; - memset(&action, 0, sizeof(action)); - action.sa_flags = SA_SIGINFO; - action.sa_sigaction = (void (*)(int, siginfo_t*, void*))sigbus_handler; - sigaction(SIGBUS, &action, NULL); - prctl(PR_MCE_KILL, 1, 1, 0, 0); + qemu_thread_self(&this); - return set; + return qemu_thread_equal(&this, env->thread); } void qemu_mutex_lock_iothread(void) @@ -756,8 +922,9 @@ static int all_vcpus_paused(void) CPUState *penv = first_cpu; while (penv) { - if (!penv->stopped) + if (!penv->stopped) { return 0; + } penv = (CPUState *)penv->next_cpu; } @@ -796,17 +963,19 @@ void resume_all_vcpus(void) } } -static void tcg_init_vcpu(void *_env) +static void qemu_tcg_init_vcpu(void *_env) { CPUState *env = _env; + /* share a single thread for all cpus with TCG */ if (!tcg_cpu_thread) { env->thread = qemu_mallocz(sizeof(QemuThread)); env->halt_cond = qemu_mallocz(sizeof(QemuCond)); qemu_cond_init(env->halt_cond); - qemu_thread_create(env->thread, tcg_cpu_thread_fn, env); - while (env->created == 0) + qemu_thread_create(env->thread, qemu_tcg_cpu_thread_fn, env); + while (env->created == 0) { qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); + } tcg_cpu_thread = env->thread; tcg_halt_cond = env->halt_cond; } else { @@ -815,14 +984,15 @@ static void tcg_init_vcpu(void *_env) } } -static void kvm_start_vcpu(CPUState *env) +static void qemu_kvm_start_vcpu(CPUState *env) { env->thread = qemu_mallocz(sizeof(QemuThread)); env->halt_cond = qemu_mallocz(sizeof(QemuCond)); qemu_cond_init(env->halt_cond); - qemu_thread_create(env->thread, kvm_cpu_thread_fn, env); - while (env->created == 0) + qemu_thread_create(env->thread, qemu_kvm_cpu_thread_fn, env); + while (env->created == 0) { qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100); + } } void qemu_init_vcpu(void *_env) @@ -831,10 +1001,11 @@ void qemu_init_vcpu(void *_env) env->nr_cores = smp_cores; env->nr_threads = smp_threads; - if (kvm_enabled()) - kvm_start_vcpu(env); - else - tcg_init_vcpu(env); + if (kvm_enabled()) { + qemu_kvm_start_vcpu(env); + } else { + qemu_tcg_init_vcpu(env); + } } void qemu_notify_event(void) @@ -842,10 +1013,12 @@ void qemu_notify_event(void) qemu_event_increment(); } -static void qemu_system_vmstop_request(int reason) +void cpu_stop_current(void) { - vmstop_requested = reason; - qemu_notify_event(); + if (cpu_single_env) { + cpu_single_env->stopped = 1; + cpu_exit(cpu_single_env); + } } void vm_stop(int reason) @@ -859,10 +1032,7 @@ void vm_stop(int reason) * FIXME: should not return to device code in case * vm_stop() has been requested. */ - if (cpu_single_env) { - cpu_exit(cpu_single_env); - cpu_single_env->stop = 1; - } + cpu_stop_current(); return; } do_vm_stop(reason); @@ -870,7 +1040,7 @@ void vm_stop(int reason) #endif -static int qemu_cpu_exec(CPUState *env) +static int tcg_cpu_exec(CPUState *env) { int ret; #ifdef CONFIG_PROFILER @@ -910,18 +1080,29 @@ static int qemu_cpu_exec(CPUState *env) bool cpu_exec_all(void) { - if (next_cpu == NULL) + int r; + + if (next_cpu == NULL) { next_cpu = first_cpu; + } for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) { CPUState *env = next_cpu; qemu_clock_enable(vm_clock, (env->singlestep_enabled & SSTEP_NOTIMER) == 0); - if (qemu_alarm_pending()) + if (qemu_alarm_pending()) { break; + } if (cpu_can_run(env)) { - if (qemu_cpu_exec(env) == EXCP_DEBUG) { + if (kvm_enabled()) { + r = kvm_cpu_exec(env); + qemu_kvm_eat_signals(env); + } else { + r = tcg_cpu_exec(env); + } + if (r == EXCP_DEBUG) { + cpu_handle_debug_exception(env); break; } } else if (env->stop) { @@ -929,7 +1110,7 @@ bool cpu_exec_all(void) } } exit_request = 0; - return any_cpu_has_work(); + return !all_cpu_threads_idle(); } void set_numa_modes(void) diff --git a/cpus.h b/cpus.h index bf4d9bb87a..e0211260c3 100644 --- a/cpus.h +++ b/cpus.h @@ -6,12 +6,11 @@ int qemu_init_main_loop(void); void qemu_main_loop_start(void); void resume_all_vcpus(void); void pause_all_vcpus(void); +void cpu_stop_current(void); /* vl.c */ extern int smp_cores; extern int smp_threads; -extern int debug_requested; -extern int vmstop_requested; void vm_state_notify(int running, int reason); bool cpu_exec_all(void); void set_numa_modes(void); diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak index 323fafbf7f..3e0eddfd02 100644 --- a/default-configs/i386-softmmu.mak +++ b/default-configs/i386-softmmu.mak @@ -4,6 +4,7 @@ include pci.mak CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y CONFIG_VMWARE_VGA=y +CONFIG_VMMOUSE=y CONFIG_SERIAL=y CONFIG_PARALLEL=y CONFIG_I8254=y @@ -18,3 +19,4 @@ CONFIG_IDE_PIIX=y CONFIG_NE2000_ISA=y CONFIG_PIIX_PCI=y CONFIG_SOUND=y +CONFIG_HPET=y diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak index eff26d2a24..1cc1b61d54 100644 --- a/default-configs/x86_64-softmmu.mak +++ b/default-configs/x86_64-softmmu.mak @@ -4,6 +4,7 @@ include pci.mak CONFIG_VGA_PCI=y CONFIG_VGA_ISA=y CONFIG_VMWARE_VGA=y +CONFIG_VMMMOUSE=y CONFIG_SERIAL=y CONFIG_PARALLEL=y CONFIG_I8254=y @@ -18,3 +19,4 @@ CONFIG_IDE_PIIX=y CONFIG_NE2000_ISA=y CONFIG_PIIX_PCI=y CONFIG_SOUND=y +CONFIG_HPET=y diff --git a/exec-all.h b/exec-all.h index e3a82bc997..496c001c03 100644 --- a/exec-all.h +++ b/exec-all.h @@ -180,7 +180,6 @@ static inline unsigned int tb_phys_hash_func(tb_page_addr_t pc) return (pc >> 2) & (CODE_GEN_PHYS_HASH_SIZE - 1); } -TranslationBlock *tb_alloc(target_ulong pc); void tb_free(TranslationBlock *tb); void tb_flush(CPUState *env); void tb_link_page(TranslationBlock *tb, diff --git a/exec.c b/exec.c index e950df25c3..d611100dc3 100644 --- a/exec.c +++ b/exec.c @@ -649,6 +649,32 @@ void cpu_exec_init(CPUState *env) #endif } +/* Allocate a new translation block. Flush the translation buffer if + too many translation blocks or too much generated code. */ +static TranslationBlock *tb_alloc(target_ulong pc) +{ + TranslationBlock *tb; + + if (nb_tbs >= code_gen_max_blocks || + (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size) + return NULL; + tb = &tbs[nb_tbs++]; + tb->pc = pc; + tb->cflags = 0; + return tb; +} + +void tb_free(TranslationBlock *tb) +{ + /* In practice this is mostly used for single use temporary TB + Ignore the hard cases and just back up if this TB happens to + be the last one generated. */ + if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) { + code_gen_ptr = tb->tc_ptr; + nb_tbs--; + } +} + static inline void invalidate_page_bitmap(PageDesc *p) { if (p->code_bitmap) { @@ -1226,32 +1252,6 @@ static inline void tb_alloc_page(TranslationBlock *tb, #endif /* TARGET_HAS_SMC */ } -/* Allocate a new translation block. Flush the translation buffer if - too many translation blocks or too much generated code. */ -TranslationBlock *tb_alloc(target_ulong pc) -{ - TranslationBlock *tb; - - if (nb_tbs >= code_gen_max_blocks || - (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size) - return NULL; - tb = &tbs[nb_tbs++]; - tb->pc = pc; - tb->cflags = 0; - return tb; -} - -void tb_free(TranslationBlock *tb) -{ - /* In practice this is mostly used for single use temporary TB - Ignore the hard cases and just back up if this TB happens to - be the last one generated. */ - if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) { - code_gen_ptr = tb->tc_ptr; - nb_tbs--; - } -} - /* add a new TB and link it to the physical page tables. phys_page2 is (-1) to indicate that only one page contains the TB. */ void tb_link_page(TranslationBlock *tb, @@ -2078,6 +2078,36 @@ int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, return ret; } +int cpu_physical_log_start(target_phys_addr_t start_addr, + ram_addr_t size) +{ + CPUPhysMemoryClient *client; + QLIST_FOREACH(client, &memory_client_list, list) { + if (client->log_start) { + int r = client->log_start(client, start_addr, size); + if (r < 0) { + return r; + } + } + } + return 0; +} + +int cpu_physical_log_stop(target_phys_addr_t start_addr, + ram_addr_t size) +{ + CPUPhysMemoryClient *client; + QLIST_FOREACH(client, &memory_client_list, list) { + if (client->log_stop) { + int r = client->log_stop(client, start_addr, size); + if (r < 0) { + return r; + } + } + } + return 0; +} + static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) { ram_addr_t ram_addr; diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index eb644b2273..2d025bfa36 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -57,6 +57,107 @@ typedef struct { } commonNaNT; /*---------------------------------------------------------------------------- +| The pattern for a default generated half-precision NaN. +*----------------------------------------------------------------------------*/ +#if defined(TARGET_ARM) +#define float16_default_nan make_float16(0x7E00) +#elif SNAN_BIT_IS_ONE +#define float16_default_nan make_float16(0x7DFF) +#else +#define float16_default_nan make_float16(0xFE00) +#endif + +/*---------------------------------------------------------------------------- +| Returns 1 if the half-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float16_is_quiet_nan(float16 a_) +{ + uint16_t a = float16_val(a_); +#if SNAN_BIT_IS_ONE + return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF); +#else + return ((a & ~0x8000) >= 0x7c80); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the half-precision floating-point value `a' is a signaling +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float16_is_signaling_nan(float16 a_) +{ + uint16_t a = float16_val(a_); +#if SNAN_BIT_IS_ONE + return ((a & ~0x8000) >= 0x7c80); +#else + return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns a quiet NaN if the half-precision floating point value `a' is a +| signaling NaN; otherwise returns `a'. +*----------------------------------------------------------------------------*/ +float16 float16_maybe_silence_nan(float16 a_) +{ + if (float16_is_signaling_nan(a_)) { +#if SNAN_BIT_IS_ONE +# if defined(TARGET_MIPS) || defined(TARGET_SH4) + return float16_default_nan; +# else +# error Rules for silencing a signaling NaN are target-specific +# endif +#else + uint16_t a = float16_val(a_); + a |= (1 << 9); + return make_float16(a); +#endif + } + return a_; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the half-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float16ToCommonNaN( float16 a STATUS_PARAM ) +{ + commonNaNT z; + + if ( float16_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR ); + z.sign = float16_val(a) >> 15; + z.low = 0; + z.high = ((bits64) float16_val(a))<<54; + return z; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the half- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float16 commonNaNToFloat16(commonNaNT a STATUS_PARAM) +{ + uint16_t mantissa = a.high>>54; + + if (STATUS(default_nan_mode)) { + return float16_default_nan; + } + + if (mantissa) { + return make_float16(((((uint16_t) a.sign) << 15) + | (0x1F << 10) | mantissa)); + } else { + return float16_default_nan; + } +} + +/*---------------------------------------------------------------------------- | The pattern for a default generated single-precision NaN. *----------------------------------------------------------------------------*/ #if defined(TARGET_SPARC) @@ -144,9 +245,14 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) | precision floating-point format. *----------------------------------------------------------------------------*/ -static float32 commonNaNToFloat32( commonNaNT a ) +static float32 commonNaNToFloat32( commonNaNT a STATUS_PARAM) { bits32 mantissa = a.high>>41; + + if ( STATUS(default_nan_mode) ) { + return float32_default_nan; + } + if ( mantissa ) return make_float32( ( ( (bits32) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) ); @@ -398,10 +504,14 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) | precision floating-point format. *----------------------------------------------------------------------------*/ -static float64 commonNaNToFloat64( commonNaNT a ) +static float64 commonNaNToFloat64( commonNaNT a STATUS_PARAM) { bits64 mantissa = a.high>>12; + if ( STATUS(default_nan_mode) ) { + return float64_default_nan; + } + if ( mantissa ) return make_float64( ( ( (bits64) a.sign )<<63 ) @@ -555,10 +665,16 @@ static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM) | double-precision floating-point format. *----------------------------------------------------------------------------*/ -static floatx80 commonNaNToFloatx80( commonNaNT a ) +static floatx80 commonNaNToFloatx80( commonNaNT a STATUS_PARAM) { floatx80 z; + if ( STATUS(default_nan_mode) ) { + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if (a.high) z.low = a.high; else @@ -703,10 +819,16 @@ static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM) | precision floating-point format. *----------------------------------------------------------------------------*/ -static float128 commonNaNToFloat128( commonNaNT a ) +static float128 commonNaNToFloat128( commonNaNT a STATUS_PARAM) { float128 z; + if ( STATUS(default_nan_mode) ) { + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + shift128Right( a.high, a.low, 16, &z.high, &z.low ); z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 ); return z; diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 17842f43da..30b07e9b44 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -67,6 +67,33 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM) #endif /*---------------------------------------------------------------------------- +| Returns the fraction bits of the half-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE uint32_t extractFloat16Frac(float16 a) +{ + return float16_val(a) & 0x3ff; +} + +/*---------------------------------------------------------------------------- +| Returns the exponent bits of the half-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE int16 extractFloat16Exp(float16 a) +{ + return (float16_val(a) >> 10) & 0x1f; +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat16Sign(float16 a) +{ + return float16_val(a)>>15; +} + +/*---------------------------------------------------------------------------- | Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 | and 7, and returns the properly rounded 32-bit integer corresponding to the | input. If `zSign' is 1, the input is negated before being converted to an @@ -1534,7 +1561,7 @@ float64 float32_to_float64( float32 a STATUS_PARAM ) aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR )); + if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloat64( aSign, 0x7FF, 0 ); } if ( aExp == 0 ) { @@ -1566,7 +1593,7 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM ) aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) ); + if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) { @@ -1600,7 +1627,7 @@ float128 float32_to_float128( float32 a STATUS_PARAM ) aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) ); + if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloat128( aSign, 0x7FFF, 0, 0 ); } if ( aExp == 0 ) { @@ -2172,21 +2199,21 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) static const float64 float32_exp2_coefficients[15] = { - make_float64( 0x3ff0000000000000ll ), /* 1 */ - make_float64( 0x3fe0000000000000ll ), /* 2 */ - make_float64( 0x3fc5555555555555ll ), /* 3 */ - make_float64( 0x3fa5555555555555ll ), /* 4 */ - make_float64( 0x3f81111111111111ll ), /* 5 */ - make_float64( 0x3f56c16c16c16c17ll ), /* 6 */ - make_float64( 0x3f2a01a01a01a01all ), /* 7 */ - make_float64( 0x3efa01a01a01a01all ), /* 8 */ - make_float64( 0x3ec71de3a556c734ll ), /* 9 */ - make_float64( 0x3e927e4fb7789f5cll ), /* 10 */ - make_float64( 0x3e5ae64567f544e4ll ), /* 11 */ - make_float64( 0x3e21eed8eff8d898ll ), /* 12 */ - make_float64( 0x3de6124613a86d09ll ), /* 13 */ - make_float64( 0x3da93974a8c07c9dll ), /* 14 */ - make_float64( 0x3d6ae7f3e733b81fll ), /* 15 */ + const_float64( 0x3ff0000000000000ll ), /* 1 */ + const_float64( 0x3fe0000000000000ll ), /* 2 */ + const_float64( 0x3fc5555555555555ll ), /* 3 */ + const_float64( 0x3fa5555555555555ll ), /* 4 */ + const_float64( 0x3f81111111111111ll ), /* 5 */ + const_float64( 0x3f56c16c16c16c17ll ), /* 6 */ + const_float64( 0x3f2a01a01a01a01all ), /* 7 */ + const_float64( 0x3efa01a01a01a01all ), /* 8 */ + const_float64( 0x3ec71de3a556c734ll ), /* 9 */ + const_float64( 0x3e927e4fb7789f5cll ), /* 10 */ + const_float64( 0x3e5ae64567f544e4ll ), /* 11 */ + const_float64( 0x3e21eed8eff8d898ll ), /* 12 */ + const_float64( 0x3de6124613a86d09ll ), /* 13 */ + const_float64( 0x3da93974a8c07c9dll ), /* 14 */ + const_float64( 0x3d6ae7f3e733b81fll ), /* 15 */ }; float32 float32_exp2( float32 a STATUS_PARAM ) @@ -2689,7 +2716,7 @@ float32 float64_to_float32( float64 a STATUS_PARAM ) aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { - if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) ); + if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloat32( aSign, 0xFF, 0 ); } shift64RightJamming( aSig, 22, &aSig ); @@ -2713,29 +2740,28 @@ float32 float64_to_float32( float64 a STATUS_PARAM ) | than the desired result exponent whenever `zSig' is a complete, normalized | significand. *----------------------------------------------------------------------------*/ -static bits16 packFloat16(flag zSign, int16 zExp, bits16 zSig) +static float16 packFloat16(flag zSign, int16 zExp, bits16 zSig) { - return (((bits32)zSign) << 15) + (((bits32)zExp) << 10) + zSig; + return make_float16( + (((bits32)zSign) << 15) + (((bits32)zExp) << 10) + zSig); } /* Half precision floats come in two formats: standard IEEE and "ARM" format. The latter gains extra exponent range by omitting the NaN/Inf encodings. */ - -float32 float16_to_float32( bits16 a, flag ieee STATUS_PARAM ) + +float32 float16_to_float32(float16 a, flag ieee STATUS_PARAM) { flag aSign; int16 aExp; bits32 aSig; - aSign = a >> 15; - aExp = (a >> 10) & 0x1f; - aSig = a & 0x3ff; + aSign = extractFloat16Sign(a); + aExp = extractFloat16Exp(a); + aSig = extractFloat16Frac(a); if (aExp == 0x1f && ieee) { if (aSig) { - /* Make sure correct exceptions are raised. */ - float32ToCommonNaN(a STATUS_VAR); - aSig |= 0x200; + return commonNaNToFloat32(float16ToCommonNaN(a STATUS_VAR) STATUS_VAR); } return packFloat32(aSign, 0xff, aSig << 13); } @@ -2753,7 +2779,7 @@ float32 float16_to_float32( bits16 a, flag ieee STATUS_PARAM ) return packFloat32( aSign, aExp + 0x70, aSig << 13); } -bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM) +float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM) { flag aSign; int16 aExp; @@ -2768,24 +2794,30 @@ bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM) aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { if (aSig) { - /* Make sure correct exceptions are raised. */ - float32ToCommonNaN(a STATUS_VAR); - aSig |= 0x00400000; + /* Input is a NaN */ + float16 r = commonNaNToFloat16( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (!ieee) { + return packFloat16(aSign, 0, 0); + } + return r; + } + /* Infinity */ + if (!ieee) { + float_raise(float_flag_invalid STATUS_VAR); + return packFloat16(aSign, 0x1f, 0x3ff); } - return packFloat16(aSign, 0x1f, aSig >> 13); + return packFloat16(aSign, 0x1f, 0); } - if (aExp == 0 && aSign == 0) { + if (aExp == 0 && aSig == 0) { return packFloat16(aSign, 0, 0); } /* Decimal point between bits 22 and 23. */ aSig |= 0x00800000; aExp -= 0x7f; if (aExp < -14) { - mask = 0x007fffff; - if (aExp < -24) { - aExp = -25; - } else { - mask >>= 24 + aExp; + mask = 0x00ffffff; + if (aExp >= -24) { + mask >>= 25 + aExp; } } else { mask = 0x00001fff; @@ -2827,7 +2859,7 @@ bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM) } } else { if (aExp > 16) { - float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); + float_raise(float_flag_invalid | float_flag_inexact STATUS_VAR); return packFloat16(aSign, 0x1f, 0x3ff); } } @@ -2861,7 +2893,7 @@ floatx80 float64_to_floatx80( float64 a STATUS_PARAM ) aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { - if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) ); + if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) { @@ -2896,7 +2928,7 @@ float128 float64_to_float128( float64 a STATUS_PARAM ) aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { - if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) ); + if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloat128( aSign, 0x7FFF, 0, 0 ); } if ( aExp == 0 ) { @@ -3843,7 +3875,7 @@ float32 floatx80_to_float32( floatx80 a STATUS_PARAM ) aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { if ( (bits64) ( aSig<<1 ) ) { - return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) ); + return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } return packFloat32( aSign, 0xFF, 0 ); } @@ -3871,7 +3903,7 @@ float64 floatx80_to_float64( floatx80 a STATUS_PARAM ) aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { if ( (bits64) ( aSig<<1 ) ) { - return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) ); + return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } return packFloat64( aSign, 0x7FF, 0 ); } @@ -3900,7 +3932,7 @@ float128 floatx80_to_float128( floatx80 a STATUS_PARAM ) aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) { - return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) ); + return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 ); return packFloat128( aSign, aExp, zSig0, zSig1 ); @@ -4863,7 +4895,7 @@ float32 float128_to_float32( float128 a STATUS_PARAM ) aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) { - return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) ); + return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } return packFloat32( aSign, 0xFF, 0 ); } @@ -4897,7 +4929,7 @@ float64 float128_to_float64( float128 a STATUS_PARAM ) aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) { - return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) ); + return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } return packFloat64( aSign, 0x7FF, 0 ); } @@ -4932,7 +4964,7 @@ floatx80 float128_to_floatx80( float128 a STATUS_PARAM ) aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) { - return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) ); + return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 4a5345ceca..e57ee1efb0 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -120,23 +120,37 @@ enum { //#define USE_SOFTFLOAT_STRUCT_TYPES #ifdef USE_SOFTFLOAT_STRUCT_TYPES typedef struct { + uint16_t v; +} float16; +#define float16_val(x) (((float16)(x)).v) +#define make_float16(x) __extension__ ({ float16 f16_val = {x}; f16_val; }) +#define const_float16(x) { x } +typedef struct { uint32_t v; } float32; /* The cast ensures an error if the wrong type is passed. */ #define float32_val(x) (((float32)(x)).v) #define make_float32(x) __extension__ ({ float32 f32_val = {x}; f32_val; }) +#define const_float32(x) { x } typedef struct { uint64_t v; } float64; #define float64_val(x) (((float64)(x)).v) #define make_float64(x) __extension__ ({ float64 f64_val = {x}; f64_val; }) +#define const_float64(x) { x } #else +typedef uint16_t float16; typedef uint32_t float32; typedef uint64_t float64; +#define float16_val(x) (x) #define float32_val(x) (x) #define float64_val(x) (x) +#define make_float16(x) (x) #define make_float32(x) (x) #define make_float64(x) (x) +#define const_float16(x) (x) +#define const_float32(x) (x) +#define const_float64(x) (x) #endif #ifdef FLOATX80 typedef struct { @@ -253,8 +267,15 @@ float128 int64_to_float128( int64_t STATUS_PARAM ); /*---------------------------------------------------------------------------- | Software half-precision conversion routines. *----------------------------------------------------------------------------*/ -bits16 float32_to_float16( float32, flag STATUS_PARAM ); -float32 float16_to_float32( bits16, flag STATUS_PARAM ); +float16 float32_to_float16( float32, flag STATUS_PARAM ); +float32 float16_to_float32( float16, flag STATUS_PARAM ); + +/*---------------------------------------------------------------------------- +| Software half-precision operations. +*----------------------------------------------------------------------------*/ +int float16_is_quiet_nan( float16 ); +int float16_is_signaling_nan( float16 ); +float16 float16_maybe_silence_nan( float16 ); /*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision conversion routines. diff --git a/gdbstub.c b/gdbstub.c index d6556c9a2f..ed51a8a5bb 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -2194,14 +2194,14 @@ static void gdb_vm_state_change(void *opaque, int running, int reason) const char *type; int ret; - if (running || (reason != EXCP_DEBUG && reason != EXCP_INTERRUPT) || - s->state == RS_INACTIVE || s->state == RS_SYSCALL) + if (running || (reason != VMSTOP_DEBUG && reason != VMSTOP_USER) || + s->state == RS_INACTIVE || s->state == RS_SYSCALL) { return; - + } /* disable single step if it was enable */ cpu_single_step(env, 0); - if (reason == EXCP_DEBUG) { + if (reason == VMSTOP_DEBUG) { if (env->watchpoint_hit) { switch (env->watchpoint_hit->flags & BP_MEM_ACCESS) { case BP_MEM_READ: @@ -2252,7 +2252,7 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...) gdb_current_syscall_cb = cb; s->state = RS_SYSCALL; #ifndef CONFIG_USER_ONLY - vm_stop(EXCP_DEBUG); + vm_stop(VMSTOP_DEBUG); #endif s->state = RS_IDLE; va_start(va, fmt); @@ -2326,7 +2326,7 @@ static void gdb_read_byte(GDBState *s, int ch) if (vm_running) { /* when the CPU is running, we cannot do anything except stop it when receiving a char */ - vm_stop(EXCP_INTERRUPT); + vm_stop(VMSTOP_USER); } else #endif { @@ -2588,7 +2588,7 @@ static void gdb_chr_event(void *opaque, int event) { switch (event) { case CHR_EVENT_OPENED: - vm_stop(EXCP_INTERRUPT); + vm_stop(VMSTOP_USER); gdb_has_xml = 0; break; default: @@ -2628,8 +2628,9 @@ static int gdb_monitor_write(CharDriverState *chr, const uint8_t *buf, int len) #ifndef _WIN32 static void gdb_sigterm_handler(int signal) { - if (vm_running) - vm_stop(EXCP_INTERRUPT); + if (vm_running) { + vm_stop(VMSTOP_USER); + } } #endif diff --git a/hw/apic.c b/hw/apic.c index 2f8376a307..218d1bb6da 100644 --- a/hw/apic.c +++ b/hw/apic.c @@ -372,19 +372,36 @@ static int apic_get_arb_pri(APICState *s) return 0; } -/* signal the CPU if an irq is pending */ -static void apic_update_irq(APICState *s) + +/* + * <0 - low prio interrupt, + * 0 - no interrupt, + * >0 - interrupt number + */ +static int apic_irq_pending(APICState *s) { int irrv, ppr; - if (!(s->spurious_vec & APIC_SV_ENABLE)) - return; irrv = get_highest_priority_int(s->irr); - if (irrv < 0) - return; + if (irrv < 0) { + return 0; + } ppr = apic_get_ppr(s); - if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) + if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) { + return -1; + } + + return irrv; +} + +/* signal the CPU if an irq is pending */ +static void apic_update_irq(APICState *s) +{ + if (!(s->spurious_vec & APIC_SV_ENABLE)) { return; - cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + } + if (apic_irq_pending(s) > 0) { + cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD); + } } void apic_reset_irq_delivered(void) @@ -590,12 +607,13 @@ int apic_get_interrupt(DeviceState *d) if (!(s->spurious_vec & APIC_SV_ENABLE)) return -1; - /* XXX: spurious IRQ handling */ - intno = get_highest_priority_int(s->irr); - if (intno < 0) + intno = apic_irq_pending(s); + + if (intno == 0) { return -1; - if (s->tpr && intno <= s->tpr) + } else if (intno < 0) { return s->spurious_vec & 0xff; + } reset_bit(s->irr, intno); set_bit(s->isr, intno); apic_update_irq(s); diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c index 5f45b5dee7..2724f7b480 100644 --- a/hw/cirrus_vga.c +++ b/hw/cirrus_vga.c @@ -31,7 +31,6 @@ #include "pci.h" #include "console.h" #include "vga_int.h" -#include "kvm.h" #include "loader.h" /* diff --git a/hw/hpet.c b/hw/hpet.c index 8fb6811a2c..82a9a21978 100644 --- a/hw/hpet.c +++ b/hw/hpet.c @@ -74,8 +74,6 @@ typedef struct HPETState { uint8_t hpet_id; /* instance id */ } HPETState; -struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX}; - static uint32_t hpet_in_legacy_mode(HPETState *s) { return s->config & HPET_CFG_LEGACY; diff --git a/hw/i2c.h b/hw/i2c.h index 83fd91714a..5514402029 100644 --- a/hw/i2c.h +++ b/hw/i2c.h @@ -59,11 +59,6 @@ void i2c_register_slave(I2CSlaveInfo *type); DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, uint8_t addr); -/* max7310.c */ -void max7310_reset(i2c_slave *i2c); -qemu_irq *max7310_gpio_in_get(i2c_slave *i2c); -void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler); - /* wm8750.c */ void wm8750_data_req_set(DeviceState *dev, void (*data_req)(void *, int, int), void *opaque); diff --git a/hw/ide/core.c b/hw/ide/core.c index dd63664c0d..9c91a49767 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -465,7 +465,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op) s->bus->dma->ops->set_unit(s->bus->dma, s->unit); s->bus->dma->ops->add_status(s->bus->dma, op); bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); - vm_stop(0); + vm_stop(VMSTOP_DISKFULL); } else { if (op & BM_STATUS_DMA_RETRY) { dma_buf_commit(s, 0); diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 0cb1afbf2e..6f349a574a 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -146,6 +146,18 @@ ISADevice *isa_create(const char *name) return DO_UPCAST(ISADevice, qdev, dev); } +ISADevice *isa_try_create(const char *name) +{ + DeviceState *dev; + + if (!isabus) { + hw_error("Tried to create isa device %s with no isa bus present.", + name); + } + dev = qdev_try_create(&isabus->qbus, name); + return DO_UPCAST(ISADevice, qdev, dev); +} + ISADevice *isa_create_simple(const char *name) { ISADevice *dev; diff --git a/hw/isa.h b/hw/isa.h index 19aa94c9fd..e26abfa063 100644 --- a/hw/isa.h +++ b/hw/isa.h @@ -32,6 +32,7 @@ void isa_init_ioport(ISADevice *dev, uint16_t ioport); void isa_init_ioport_range(ISADevice *dev, uint16_t start, uint16_t length); void isa_qdev_register(ISADeviceInfo *info); ISADevice *isa_create(const char *name); +ISADevice *isa_try_create(const char *name); ISADevice *isa_create_simple(const char *name); extern target_phys_addr_t isa_mem_base; diff --git a/hw/kvmclock.c b/hw/kvmclock.c new file mode 100644 index 0000000000..b6ceddfba6 --- /dev/null +++ b/hw/kvmclock.c @@ -0,0 +1,125 @@ +/* + * QEMU KVM support, paravirtual clock device + * + * Copyright (C) 2011 Siemens AG + * + * Authors: + * Jan Kiszka <jan.kiszka@siemens.com> + * + * This work is licensed under the terms of the GNU GPL version 2. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu-common.h" +#include "sysemu.h" +#include "sysbus.h" +#include "kvm.h" +#include "kvmclock.h" + +#if defined(CONFIG_KVM_PARA) && defined(KVM_CAP_ADJUST_CLOCK) + +#include <linux/kvm.h> +#include <linux/kvm_para.h> + +typedef struct KVMClockState { + SysBusDevice busdev; + uint64_t clock; + bool clock_valid; +} KVMClockState; + +static void kvmclock_pre_save(void *opaque) +{ + KVMClockState *s = opaque; + struct kvm_clock_data data; + int ret; + + if (s->clock_valid) { + return; + } + ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data); + if (ret < 0) { + fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret)); + data.clock = 0; + } + s->clock = data.clock; + /* + * If the VM is stopped, declare the clock state valid to avoid re-reading + * it on next vmsave (which would return a different value). Will be reset + * when the VM is continued. + */ + s->clock_valid = !vm_running; +} + +static int kvmclock_post_load(void *opaque, int version_id) +{ + KVMClockState *s = opaque; + struct kvm_clock_data data; + + data.clock = s->clock; + data.flags = 0; + return kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data); +} + +static void kvmclock_vm_state_change(void *opaque, int running, int reason) +{ + KVMClockState *s = opaque; + + if (running) { + s->clock_valid = false; + } +} + +static int kvmclock_init(SysBusDevice *dev) +{ + KVMClockState *s = FROM_SYSBUS(KVMClockState, dev); + + qemu_add_vm_change_state_handler(kvmclock_vm_state_change, s); + return 0; +} + +static const VMStateDescription kvmclock_vmsd = { + .name = "kvmclock", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .pre_save = kvmclock_pre_save, + .post_load = kvmclock_post_load, + .fields = (VMStateField[]) { + VMSTATE_UINT64(clock, KVMClockState), + VMSTATE_END_OF_LIST() + } +}; + +static SysBusDeviceInfo kvmclock_info = { + .qdev.name = "kvmclock", + .qdev.size = sizeof(KVMClockState), + .qdev.vmsd = &kvmclock_vmsd, + .qdev.no_user = 1, + .init = kvmclock_init, +}; + +/* Note: Must be called after VCPU initialization. */ +void kvmclock_create(void) +{ + if (kvm_enabled() && + first_cpu->cpuid_kvm_features & (1ULL << KVM_FEATURE_CLOCKSOURCE)) { + sysbus_create_simple("kvmclock", -1, NULL); + } +} + +static void kvmclock_register_device(void) +{ + if (kvm_enabled()) { + sysbus_register_withprop(&kvmclock_info); + } +} + +device_init(kvmclock_register_device); + +#else /* !(CONFIG_KVM_PARA && KVM_CAP_ADJUST_CLOCK) */ + +void kvmclock_create(void) +{ +} +#endif /* !(CONFIG_KVM_PARA && KVM_CAP_ADJUST_CLOCK) */ diff --git a/hw/kvmclock.h b/hw/kvmclock.h new file mode 100644 index 0000000000..7a83cbe8f6 --- /dev/null +++ b/hw/kvmclock.h @@ -0,0 +1,14 @@ +/* + * QEMU KVM support, paravirtual clock device + * + * Copyright (C) 2011 Siemens AG + * + * Authors: + * Jan Kiszka <jan.kiszka@siemens.com> + * + * This work is licensed under the terms of the GNU GPL version 2. + * See the COPYING file in the top-level directory. + * + */ + +void kvmclock_create(void); diff --git a/hw/mainstone.c b/hw/mainstone.c index 58e3f8670d..aec8d34b4f 100644 --- a/hw/mainstone.c +++ b/hw/mainstone.c @@ -14,10 +14,32 @@ #include "net.h" #include "devices.h" #include "boards.h" -#include "mainstone.h" #include "sysemu.h" #include "flash.h" #include "blockdev.h" +#include "sysbus.h" + +/* Device addresses */ +#define MST_FPGA_PHYS 0x08000000 +#define MST_ETH_PHYS 0x10000300 +#define MST_FLASH_0 0x00000000 +#define MST_FLASH_1 0x04000000 + +/* IRQ definitions */ +#define MMC_IRQ 0 +#define USIM_IRQ 1 +#define USBC_IRQ 2 +#define ETHERNET_IRQ 3 +#define AC97_IRQ 4 +#define PEN_IRQ 5 +#define MSINS_IRQ 6 +#define EXBRD_IRQ 7 +#define S0_CD_IRQ 9 +#define S0_STSCHG_IRQ 10 +#define S0_IRQ 11 +#define S1_CD_IRQ 13 +#define S1_STSCHG_IRQ 14 +#define S1_IRQ 15 static struct keymap map[0xE0] = { [0 ... 0xDF] = { -1, -1 }, @@ -77,7 +99,7 @@ static void mainstone_common_init(ram_addr_t ram_size, uint32_t sector_len = 256 * 1024; target_phys_addr_t mainstone_flash_base[] = { MST_FLASH_0, MST_FLASH_1 }; PXA2xxState *cpu; - qemu_irq *mst_irq; + DeviceState *mst_irq; DriveInfo *dinfo; int i; int be; @@ -117,16 +139,18 @@ static void mainstone_common_init(ram_addr_t ram_size, } } - mst_irq = mst_irq_init(cpu, MST_FPGA_PHYS, PXA2XX_PIC_GPIO_0); + mst_irq = sysbus_create_simple("mainstone-fpga", MST_FPGA_PHYS, + cpu->pic[PXA2XX_PIC_GPIO_0]); /* setup keypad */ printf("map addr %p\n", &map); pxa27x_register_keypad(cpu->kp, map, 0xe0); /* MMC/SD host */ - pxa2xx_mmci_handlers(cpu->mmc, NULL, mst_irq[MMC_IRQ]); + pxa2xx_mmci_handlers(cpu->mmc, NULL, qdev_get_gpio_in(mst_irq, MMC_IRQ)); - smc91c111_init(&nd_table[0], MST_ETH_PHYS, mst_irq[ETHERNET_IRQ]); + smc91c111_init(&nd_table[0], MST_ETH_PHYS, + qdev_get_gpio_in(mst_irq, ETHERNET_IRQ)); mainstone_binfo.kernel_filename = kernel_filename; mainstone_binfo.kernel_cmdline = kernel_cmdline; diff --git a/hw/mainstone.h b/hw/mainstone.h deleted file mode 100644 index 9618c0632a..0000000000 --- a/hw/mainstone.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * PXA270-based Intel Mainstone platforms. - * - * Copyright (c) 2007 by Armin Kuster <akuster@kama-aina.net> or - * <akuster@mvista.com> - * - * This code is licensed under the GNU GPL v2. - */ - -#ifndef __MAINSTONE_H__ -#define __MAINSTONE_H__ - -/* Device addresses */ -#define MST_FPGA_PHYS 0x08000000 -#define MST_ETH_PHYS 0x10000300 -#define MST_FLASH_0 0x00000000 -#define MST_FLASH_1 0x04000000 - -/* IRQ definitions */ -#define MMC_IRQ 0 -#define USIM_IRQ 1 -#define USBC_IRQ 2 -#define ETHERNET_IRQ 3 -#define AC97_IRQ 4 -#define PEN_IRQ 5 -#define MSINS_IRQ 6 -#define EXBRD_IRQ 7 -#define S0_CD_IRQ 9 -#define S0_STSCHG_IRQ 10 -#define S0_IRQ 11 -#define S1_CD_IRQ 13 -#define S1_STSCHG_IRQ 14 -#define S1_IRQ 15 - -extern qemu_irq -*mst_irq_init(PXA2xxState *cpu, uint32_t base, int irq); - -#endif /* __MAINSTONE_H__ */ diff --git a/hw/max7310.c b/hw/max7310.c index c302eb6aa4..c1bdb2ee0c 100644 --- a/hw/max7310.c +++ b/hw/max7310.c @@ -23,9 +23,9 @@ typedef struct { qemu_irq *gpio_in; } MAX7310State; -void max7310_reset(i2c_slave *i2c) +static void max7310_reset(DeviceState *dev) { - MAX7310State *s = (MAX7310State *) i2c; + MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, I2C_SLAVE_FROM_QDEV(dev)); s->level &= s->direction; s->direction = 0xff; s->polarity = 0xf0; @@ -179,33 +179,17 @@ static int max7310_init(i2c_slave *i2c) { MAX7310State *s = FROM_I2C_SLAVE(MAX7310State, i2c); - s->gpio_in = qemu_allocate_irqs(max7310_gpio_set, s, - ARRAY_SIZE(s->handler)); - - max7310_reset(&s->i2c); + qdev_init_gpio_in(&i2c->qdev, max7310_gpio_set, 8); + qdev_init_gpio_out(&i2c->qdev, s->handler, 8); return 0; } -qemu_irq *max7310_gpio_in_get(i2c_slave *i2c) -{ - MAX7310State *s = (MAX7310State *) i2c; - return s->gpio_in; -} - -void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler) -{ - MAX7310State *s = (MAX7310State *) i2c; - if (line >= ARRAY_SIZE(s->handler) || line < 0) - hw_error("bad GPIO line"); - - s->handler[line] = handler; -} - static I2CSlaveInfo max7310_info = { .qdev.name = "max7310", .qdev.size = sizeof(MAX7310State), .qdev.vmsd = &vmstate_max7310, + .qdev.reset = max7310_reset, .init = max7310_init, .event = max7310_event, .recv = max7310_rx, diff --git a/hw/mips_malta.c b/hw/mips_malta.c index 2d3f242cc8..930c51c74d 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -957,7 +957,11 @@ void mips_malta_init (ram_addr_t ram_size, if (cirrus_vga_enabled) { pci_cirrus_vga_init(pci_bus); } else if (vmsvga_enabled) { - pci_vmsvga_init(pci_bus); + if (!pci_vmsvga_init(pci_bus)) { + fprintf(stderr, "Warning: vmware_vga not available," + " using standard VGA instead\n"); + pci_vga_init(pci_bus); + } } else if (std_vga_enabled) { pci_vga_init(pci_bus); } diff --git a/hw/mst_fpga.c b/hw/mst_fpga.c index 5252fc5e1c..afed2acd44 100644 --- a/hw/mst_fpga.c +++ b/hw/mst_fpga.c @@ -8,8 +8,7 @@ * This code is licensed under the GNU GPL v2. */ #include "hw.h" -#include "pxa.h" -#include "mainstone.h" +#include "sysbus.h" /* Mainstone FPGA for extern irqs */ #define FPGA_GPIO_PIN 0 @@ -28,8 +27,9 @@ #define MST_PCMCIA1 0xe4 typedef struct mst_irq_state{ - qemu_irq *parent; - qemu_irq *pins; + SysBusDevice busdev; + + qemu_irq parent; uint32_t prev_level; uint32_t leddat1; @@ -47,33 +47,21 @@ typedef struct mst_irq_state{ }mst_irq_state; static void -mst_fpga_update_gpio(mst_irq_state *s) -{ - uint32_t level, diff; - int bit; - level = s->prev_level ^ s->intsetclr; - - for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { - bit = ffs(diff) - 1; - qemu_set_irq(s->pins[bit], (level >> bit) & 1 ); - } - s->prev_level = level; -} - -static void mst_fpga_set_irq(void *opaque, int irq, int level) { mst_irq_state *s = (mst_irq_state *)opaque; + uint32_t oldint = s->intsetclr; if (level) s->prev_level |= 1u << irq; else s->prev_level &= ~(1u << irq); - if(s->intmskena & (1u << irq)) { - s->intsetclr = 1u << irq; - qemu_set_irq(s->parent[0], level); - } + if ((s->intmskena & (1u << irq)) && level) + s->intsetclr |= 1u << irq; + + if (oldint != (s->intsetclr & s->intmskena)) + qemu_set_irq(s->parent, s->intsetclr & s->intmskena); } @@ -109,7 +97,7 @@ mst_fpga_readb(void *opaque, target_phys_addr_t addr) return s->pcmcia1; default: printf("Mainstone - mst_fpga_readb: Bad register offset " - REG_FMT " \n", addr); + "0x" TARGET_FMT_plx " \n", addr); } return 0; } @@ -147,10 +135,11 @@ mst_fpga_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) break; case MST_INTMSKENA: /* Mask interupt */ s->intmskena = (value & 0xFEEFF); - mst_fpga_update_gpio(s); + qemu_set_irq(s->parent, s->intsetclr & s->intmskena); break; case MST_INTSETCLR: /* clear or set interrupt */ s->intsetclr = (value & 0xFEEFF); + qemu_set_irq(s->parent, s->intsetclr); break; case MST_PCMCIA0: s->pcmcia0 = value; @@ -160,7 +149,7 @@ mst_fpga_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) break; default: printf("Mainstone - mst_fpga_writeb: Bad register offset " - REG_FMT " \n", addr); + "0x" TARGET_FMT_plx " \n", addr); } } @@ -175,66 +164,67 @@ static CPUWriteMemoryFunc * const mst_fpga_writefn[] = { mst_fpga_writeb, }; -static void -mst_fpga_save(QEMUFile *f, void *opaque) -{ - struct mst_irq_state *s = (mst_irq_state *) opaque; - - qemu_put_be32s(f, &s->prev_level); - qemu_put_be32s(f, &s->leddat1); - qemu_put_be32s(f, &s->leddat2); - qemu_put_be32s(f, &s->ledctrl); - qemu_put_be32s(f, &s->gpswr); - qemu_put_be32s(f, &s->mscwr1); - qemu_put_be32s(f, &s->mscwr2); - qemu_put_be32s(f, &s->mscwr3); - qemu_put_be32s(f, &s->mscrd); - qemu_put_be32s(f, &s->intmskena); - qemu_put_be32s(f, &s->intsetclr); - qemu_put_be32s(f, &s->pcmcia0); - qemu_put_be32s(f, &s->pcmcia1); -} -static int -mst_fpga_load(QEMUFile *f, void *opaque, int version_id) +static int mst_fpga_post_load(void *opaque, int version_id) { mst_irq_state *s = (mst_irq_state *) opaque; - qemu_get_be32s(f, &s->prev_level); - qemu_get_be32s(f, &s->leddat1); - qemu_get_be32s(f, &s->leddat2); - qemu_get_be32s(f, &s->ledctrl); - qemu_get_be32s(f, &s->gpswr); - qemu_get_be32s(f, &s->mscwr1); - qemu_get_be32s(f, &s->mscwr2); - qemu_get_be32s(f, &s->mscwr3); - qemu_get_be32s(f, &s->mscrd); - qemu_get_be32s(f, &s->intmskena); - qemu_get_be32s(f, &s->intsetclr); - qemu_get_be32s(f, &s->pcmcia0); - qemu_get_be32s(f, &s->pcmcia1); + qemu_set_irq(s->parent, s->intsetclr & s->intmskena); return 0; } -qemu_irq *mst_irq_init(PXA2xxState *cpu, uint32_t base, int irq) +static int mst_fpga_init(SysBusDevice *dev) { mst_irq_state *s; int iomemtype; - qemu_irq *qi; - s = (mst_irq_state *) - qemu_mallocz(sizeof(mst_irq_state)); + s = FROM_SYSBUS(mst_irq_state, dev); - s->parent = &cpu->pic[irq]; + sysbus_init_irq(dev, &s->parent); /* alloc the external 16 irqs */ - qi = qemu_allocate_irqs(mst_fpga_set_irq, s, MST_NUM_IRQS); - s->pins = qi; + qdev_init_gpio_in(&dev->qdev, mst_fpga_set_irq, MST_NUM_IRQS); iomemtype = cpu_register_io_memory(mst_fpga_readfn, mst_fpga_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base, 0x00100000, iomemtype); - register_savevm(NULL, "mainstone_fpga", 0, 0, mst_fpga_save, - mst_fpga_load, s); - return qi; + sysbus_init_mmio(dev, 0x00100000, iomemtype); + return 0; +} + +static VMStateDescription vmstate_mst_fpga_regs = { + .name = "mainstone_fpga", + .version_id = 0, + .minimum_version_id = 0, + .minimum_version_id_old = 0, + .post_load = mst_fpga_post_load, + .fields = (VMStateField []) { + VMSTATE_UINT32(prev_level, mst_irq_state), + VMSTATE_UINT32(leddat1, mst_irq_state), + VMSTATE_UINT32(leddat2, mst_irq_state), + VMSTATE_UINT32(ledctrl, mst_irq_state), + VMSTATE_UINT32(gpswr, mst_irq_state), + VMSTATE_UINT32(mscwr1, mst_irq_state), + VMSTATE_UINT32(mscwr2, mst_irq_state), + VMSTATE_UINT32(mscwr3, mst_irq_state), + VMSTATE_UINT32(mscrd, mst_irq_state), + VMSTATE_UINT32(intmskena, mst_irq_state), + VMSTATE_UINT32(intsetclr, mst_irq_state), + VMSTATE_UINT32(pcmcia0, mst_irq_state), + VMSTATE_UINT32(pcmcia1, mst_irq_state), + VMSTATE_END_OF_LIST(), + }, +}; + +static SysBusDeviceInfo mst_fpga_info = { + .init = mst_fpga_init, + .qdev.name = "mainstone-fpga", + .qdev.desc = "Mainstone II FPGA", + .qdev.size = sizeof(mst_irq_state), + .qdev.vmsd = &vmstate_mst_fpga_regs, +}; + +static void mst_fpga_register(void) +{ + sysbus_register_withprop(&mst_fpga_info); } +device_init(mst_fpga_register); diff --git a/hw/pc.c b/hw/pc.c index 4dfdc0be53..56bf1d63f0 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -84,6 +84,7 @@ struct e820_table { } __attribute((__packed__, __aligned__(4))); static struct e820_table e820_table; +struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX}; void isa_irq_handler(void *opaque, int n, int level) { @@ -1053,10 +1054,15 @@ void pc_vga_init(PCIBus *pci_bus) isa_cirrus_vga_init(); } } else if (vmsvga_enabled) { - if (pci_bus) - pci_vmsvga_init(pci_bus); - else + if (pci_bus) { + if (!pci_vmsvga_init(pci_bus)) { + fprintf(stderr, "Warning: vmware_vga not available," + " using standard VGA instead\n"); + pci_vga_init(pci_bus); + } + } else { fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); + } #ifdef CONFIG_SPICE } else if (qxl_enabled) { if (pci_bus) @@ -1091,7 +1097,7 @@ void pc_basic_device_init(qemu_irq *isa_irq, PITState *pit; qemu_irq rtc_irq = NULL; qemu_irq *a20_line; - ISADevice *i8042, *port92; + ISADevice *i8042, *port92, *vmmouse; qemu_irq *cpu_exit_irq; register_ioport_write(0x80, 1, 1, ioport80_write, NULL); @@ -1099,12 +1105,14 @@ void pc_basic_device_init(qemu_irq *isa_irq, register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL); if (!no_hpet) { - DeviceState *hpet = sysbus_create_simple("hpet", HPET_BASE, NULL); + DeviceState *hpet = sysbus_try_create_simple("hpet", HPET_BASE, NULL); - for (i = 0; i < 24; i++) { - sysbus_connect_irq(sysbus_from_qdev(hpet), i, isa_irq[i]); + if (hpet) { + for (i = 0; i < 24; i++) { + sysbus_connect_irq(sysbus_from_qdev(hpet), i, isa_irq[i]); + } + rtc_irq = qdev_get_gpio_in(hpet, 0); } - rtc_irq = qdev_get_gpio_in(hpet, 0); } *rtc_state = rtc_init(2000, rtc_irq); @@ -1128,7 +1136,11 @@ void pc_basic_device_init(qemu_irq *isa_irq, a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2); i8042 = isa_create_simple("i8042"); i8042_setup_a20_line(i8042, &a20_line[0]); - vmmouse_init(i8042); + vmport_init(); + vmmouse = isa_try_create("vmmouse"); + if (vmmouse) { + qdev_prop_set_ptr(&vmmouse->qdev, "ps2_mouse", i8042); + } port92 = isa_create_simple("port92"); port92_init(port92, &a20_line[1]); diff --git a/hw/pc.h b/hw/pc.h index a048768d21..d5d2f42f96 100644 --- a/hw/pc.h +++ b/hw/pc.h @@ -65,11 +65,13 @@ void hpet_pit_disable(void); void hpet_pit_enable(void); /* vmport.c */ -void vmport_init(void); +static inline void vmport_init(void) +{ + isa_create_simple("vmport"); +} void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque); - -/* vmmouse.c */ -void *vmmouse_init(void *m); +void vmmouse_get_data(uint32_t *data); +void vmmouse_set_data(const uint32_t *data); /* pckbd.c */ diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 7b744730f7..291845478d 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -32,6 +32,7 @@ #include "boards.h" #include "ide.h" #include "kvm.h" +#include "kvmclock.h" #include "sysemu.h" #include "sysbus.h" #include "arch_init.h" @@ -66,7 +67,8 @@ static void pc_init1(ram_addr_t ram_size, const char *kernel_cmdline, const char *initrd_filename, const char *cpu_model, - int pci_enabled) + int pci_enabled, + int kvmclock_enabled) { int i; ram_addr_t below_4g_mem_size, above_4g_mem_size; @@ -86,7 +88,9 @@ static void pc_init1(ram_addr_t ram_size, pc_cpus_init(cpu_model); - vmport_init(); + if (kvmclock_enabled) { + kvmclock_create(); + } /* allocate ram and load rom/bios */ pc_memory_init(ram_size, kernel_filename, kernel_cmdline, initrd_filename, @@ -195,7 +199,19 @@ static void pc_init_pci(ram_addr_t ram_size, { pc_init1(ram_size, boot_device, kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 1); + initrd_filename, cpu_model, 1, 1); +} + +static void pc_init_pci_no_kvmclock(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, 0); } static void pc_init_isa(ram_addr_t ram_size, @@ -209,7 +225,7 @@ static void pc_init_isa(ram_addr_t ram_size, cpu_model = "486"; pc_init1(ram_size, boot_device, kernel_filename, kernel_cmdline, - initrd_filename, cpu_model, 0); + initrd_filename, cpu_model, 0, 1); } static QEMUMachine pc_machine = { @@ -224,7 +240,7 @@ static QEMUMachine pc_machine = { static QEMUMachine pc_machine_v0_13 = { .name = "pc-0.13", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_no_kvmclock, .max_cpus = 255, .compat_props = (GlobalProperty[]) { { @@ -251,7 +267,7 @@ static QEMUMachine pc_machine_v0_13 = { static QEMUMachine pc_machine_v0_12 = { .name = "pc-0.12", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_no_kvmclock, .max_cpus = 255, .compat_props = (GlobalProperty[]) { { @@ -282,7 +298,7 @@ static QEMUMachine pc_machine_v0_12 = { static QEMUMachine pc_machine_v0_11 = { .name = "pc-0.11", .desc = "Standard PC, qemu 0.11", - .init = pc_init_pci, + .init = pc_init_pci_no_kvmclock, .max_cpus = 255, .compat_props = (GlobalProperty[]) { { @@ -321,7 +337,7 @@ static QEMUMachine pc_machine_v0_11 = { static QEMUMachine pc_machine_v0_10 = { .name = "pc-0.10", .desc = "Standard PC, qemu 0.10", - .init = pc_init_pci, + .init = pc_init_pci_no_kvmclock, .max_cpus = 255, .compat_props = (GlobalProperty[]) { { diff --git a/hw/pci.c b/hw/pci.c index d5bbba975b..5e6e216487 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -1708,6 +1708,21 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, return DO_UPCAST(PCIDevice, qdev, dev); } +PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn, + bool multifunction, + const char *name) +{ + DeviceState *dev; + + dev = qdev_try_create(&bus->qbus, name); + if (!dev) { + return NULL; + } + qdev_prop_set_uint32(dev, "addr", devfn); + qdev_prop_set_bit(dev, "multifunction", multifunction); + return DO_UPCAST(PCIDevice, qdev, dev); +} + PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name) @@ -1727,6 +1742,11 @@ PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name) return pci_create_simple_multifunction(bus, devfn, false, name); } +PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name) +{ + return pci_try_create_multifunction(bus, devfn, false, name); +} + static int pci_find_space(PCIDevice *pdev, uint8_t size) { int config_size = pci_config_size(pdev); diff --git a/hw/pci.h b/hw/pci.h index 0d2753f27e..113e556e2d 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -453,8 +453,12 @@ PCIDevice *pci_create_multifunction(PCIBus *bus, int devfn, bool multifunction, PCIDevice *pci_create_simple_multifunction(PCIBus *bus, int devfn, bool multifunction, const char *name); +PCIDevice *pci_try_create_multifunction(PCIBus *bus, int devfn, + bool multifunction, + const char *name); PCIDevice *pci_create(PCIBus *bus, int devfn, const char *name); PCIDevice *pci_create_simple(PCIBus *bus, int devfn, const char *name); +PCIDevice *pci_try_create(PCIBus *bus, int devfn, const char *name); static inline int pci_is_express(const PCIDevice *d) { diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c index d966846f94..9ebbce60d7 100644 --- a/hw/pxa2xx.c +++ b/hw/pxa2xx.c @@ -1262,10 +1262,12 @@ typedef struct { } PXA2xxI2CSlaveState; struct PXA2xxI2CState { + SysBusDevice busdev; PXA2xxI2CSlaveState *slave; i2c_bus *bus; qemu_irq irq; - target_phys_addr_t offset; + uint32_t offset; + uint32_t region_size; uint16_t control; uint16_t status; @@ -1499,27 +1501,42 @@ static I2CSlaveInfo pxa2xx_i2c_slave_info = { PXA2xxI2CState *pxa2xx_i2c_init(target_phys_addr_t base, qemu_irq irq, uint32_t region_size) { - int iomemtype; DeviceState *dev; - PXA2xxI2CState *s = qemu_mallocz(sizeof(PXA2xxI2CState)); + SysBusDevice *i2c_dev; + PXA2xxI2CState *s; + + i2c_dev = sysbus_from_qdev(qdev_create(NULL, "pxa2xx_i2c")); + qdev_prop_set_uint32(&i2c_dev->qdev, "size", region_size + 1); + qdev_prop_set_uint32(&i2c_dev->qdev, "offset", + base - (base & (~region_size) & TARGET_PAGE_MASK)); + + qdev_init_nofail(&i2c_dev->qdev); + + sysbus_mmio_map(i2c_dev, 0, base & ~region_size); + sysbus_connect_irq(i2c_dev, 0, irq); + s = FROM_SYSBUS(PXA2xxI2CState, i2c_dev); /* FIXME: Should the slave device really be on a separate bus? */ dev = i2c_create_slave(i2c_init_bus(NULL, "dummy"), "pxa2xx-i2c-slave", 0); s->slave = FROM_I2C_SLAVE(PXA2xxI2CSlaveState, I2C_SLAVE_FROM_QDEV(dev)); s->slave->host = s; - s->irq = irq; - s->bus = i2c_init_bus(NULL, "i2c"); - s->offset = base - (base & (~region_size) & TARGET_PAGE_MASK); + return s; +} + +static int pxa2xx_i2c_initfn(SysBusDevice *dev) +{ + PXA2xxI2CState *s = FROM_SYSBUS(PXA2xxI2CState, dev); + int iomemtype; + + s->bus = i2c_init_bus(&dev->qdev, "i2c"); iomemtype = cpu_register_io_memory(pxa2xx_i2c_readfn, pxa2xx_i2c_writefn, s, DEVICE_NATIVE_ENDIAN); - cpu_register_physical_memory(base & ~region_size, - region_size + 1, iomemtype); - - vmstate_register(NULL, base, &vmstate_pxa2xx_i2c, s); + sysbus_init_mmio(dev, s->region_size, iomemtype); + sysbus_init_irq(dev, &s->irq); - return s; + return 0; } i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s) @@ -1527,6 +1544,19 @@ i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s) return s->bus; } +static SysBusDeviceInfo pxa2xx_i2c_info = { + .init = pxa2xx_i2c_initfn, + .qdev.name = "pxa2xx_i2c", + .qdev.desc = "PXA2xx I2C Bus Controller", + .qdev.size = sizeof(PXA2xxI2CState), + .qdev.vmsd = &vmstate_pxa2xx_i2c, + .qdev.props = (Property[]) { + DEFINE_PROP_UINT32("size", PXA2xxI2CState, region_size, 0x10000), + DEFINE_PROP_UINT32("offset", PXA2xxI2CState, offset, 0), + DEFINE_PROP_END_OF_LIST(), + }, +}; + /* PXA Inter-IC Sound Controller */ static void pxa2xx_i2s_reset(PXA2xxI2SState *i2s) { @@ -2287,6 +2317,7 @@ static void pxa2xx_register_devices(void) { i2c_register_slave(&pxa2xx_i2c_slave_info); sysbus_register_dev("pxa2xx-ssp", sizeof(PXA2xxSSPState), pxa2xx_ssp_init); + sysbus_register_withprop(&pxa2xx_i2c_info); } device_init(pxa2xx_register_devices) diff --git a/hw/qdev.c b/hw/qdev.c index c7fec44a83..1aa1ea0e26 100644 --- a/hw/qdev.c +++ b/hw/qdev.c @@ -106,6 +106,18 @@ static DeviceState *qdev_create_from_info(BusState *bus, DeviceInfo *info) initialize the actual device emulation. */ DeviceState *qdev_create(BusState *bus, const char *name) { + DeviceState *dev; + + dev = qdev_try_create(bus, name); + if (!dev) { + hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name); + } + + return dev; +} + +DeviceState *qdev_try_create(BusState *bus, const char *name) +{ DeviceInfo *info; if (!bus) { @@ -114,7 +126,7 @@ DeviceState *qdev_create(BusState *bus, const char *name) info = qdev_find_info(bus->info, name); if (!info) { - hw_error("Unknown device '%s' for bus '%s'\n", name, bus->info->name); + return NULL; } return qdev_create_from_info(bus, info); diff --git a/hw/qdev.h b/hw/qdev.h index 9808f85119..8a13ec95cc 100644 --- a/hw/qdev.h +++ b/hw/qdev.h @@ -122,6 +122,7 @@ typedef struct GlobalProperty { /*** Board API. This should go away once we have a machine config file. ***/ DeviceState *qdev_create(BusState *bus, const char *name); +DeviceState *qdev_try_create(BusState *bus, const char *name); int qdev_device_help(QemuOpts *opts); DeviceState *qdev_device_add(QemuOpts *opts); int qdev_init(DeviceState *dev) QEMU_WARN_UNUSED_RESULT; diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 488eedd2cd..b05e6547df 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -239,7 +239,7 @@ static int scsi_handle_rw_error(SCSIDiskReq *r, int error, int type) r->status |= SCSI_REQ_STATUS_RETRY | type; bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); - vm_stop(0); + vm_stop(VMSTOP_DISKFULL); } else { if (type == SCSI_REQ_STATUS_RETRY_READ) { r->req.bus->complete(r->req.bus, SCSI_REASON_DATA, r->req.tag, 0); diff --git a/hw/sysbus.c b/hw/sysbus.c index 1583bd8589..acad72abe4 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -173,11 +173,43 @@ DeviceState *sysbus_create_varargs(const char *name, return dev; } +DeviceState *sysbus_try_create_varargs(const char *name, + target_phys_addr_t addr, ...) +{ + DeviceState *dev; + SysBusDevice *s; + va_list va; + qemu_irq irq; + int n; + + dev = qdev_try_create(NULL, name); + if (!dev) { + return NULL; + } + s = sysbus_from_qdev(dev); + qdev_init_nofail(dev); + if (addr != (target_phys_addr_t)-1) { + sysbus_mmio_map(s, 0, addr); + } + va_start(va, addr); + n = 0; + while (1) { + irq = va_arg(va, qemu_irq); + if (!irq) { + break; + } + sysbus_connect_irq(s, n, irq); + n++; + } + return dev; +} + static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) { SysBusDevice *s = sysbus_from_qdev(dev); int i; + monitor_printf(mon, "%*sirq %d\n", indent, "", s->num_irq); for (i = 0; i < s->num_mmio; i++) { monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n", indent, "", s->mmio[i].addr, s->mmio[i].size); diff --git a/hw/sysbus.h b/hw/sysbus.h index e9eb618a72..4e8cb16d42 100644 --- a/hw/sysbus.h +++ b/hw/sysbus.h @@ -57,6 +57,8 @@ void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr); /* Legacy helper function for creating devices. */ DeviceState *sysbus_create_varargs(const char *name, target_phys_addr_t addr, ...); +DeviceState *sysbus_try_create_varargs(const char *name, + target_phys_addr_t addr, ...); static inline DeviceState *sysbus_create_simple(const char *name, target_phys_addr_t addr, qemu_irq irq) @@ -64,4 +66,11 @@ static inline DeviceState *sysbus_create_simple(const char *name, return sysbus_create_varargs(name, addr, irq, NULL); } +static inline DeviceState *sysbus_try_create_simple(const char *name, + target_phys_addr_t addr, + qemu_irq irq) +{ + return sysbus_try_create_varargs(name, addr, irq, NULL); +} + #endif /* !HW_SYSBUS_H */ diff --git a/hw/tc6393xb.c b/hw/tc6393xb.c index c3fbe4e205..ed49e944df 100644 --- a/hw/tc6393xb.c +++ b/hw/tc6393xb.c @@ -8,7 +8,6 @@ * This code is licensed under the GNU GPL v2. */ #include "hw.h" -#include "pxa.h" #include "devices.h" #include "flash.h" #include "console.h" @@ -381,7 +380,7 @@ static void tc6393xb_nand_writeb(TC6393xbState *s, target_phys_addr_t addr, uint case NAND_DATA + 2: case NAND_DATA + 3: nand_setio(s->flash, value); - s->nand.isr &= 1; + s->nand.isr |= 1; tc6393xb_nand_irq(s); return; case NAND_MODE: diff --git a/hw/tosa.c b/hw/tosa.c index 0bfab1634a..b8b6c4f390 100644 --- a/hw/tosa.c +++ b/hw/tosa.c @@ -25,6 +25,7 @@ #define TOSA_RAM 0x04000000 #define TOSA_ROM 0x00800000 +#define TOSA_GPIO_USB_IN (5) #define TOSA_GPIO_nSD_DETECT (9) #define TOSA_GPIO_ON_RESET (19) #define TOSA_GPIO_CF_IRQ (21) /* CF slot0 Ready */ @@ -115,6 +116,9 @@ static void tosa_gpio_setup(PXA2xxState *cpu, qdev_connect_gpio_out(scp1, TOSA_GPIO_WLAN_LED, outsignals[3]); qdev_connect_gpio_out(scp1, TOSA_GPIO_TC6393XB_L3V_ON, tc6393xb_l3v_get(tmio)); + + /* UDC Vbus */ + qemu_irq_raise(qdev_get_gpio_in(cpu->gpio, TOSA_GPIO_USB_IN)); } static uint32_t tosa_ssp_tansfer(SSISlave *dev, uint32_t value) diff --git a/hw/vga.c b/hw/vga.c index e2151a2458..c22b8af833 100644 --- a/hw/vga.c +++ b/hw/vga.c @@ -28,7 +28,6 @@ #include "vga_int.h" #include "pixel_ops.h" #include "qemu-timer.h" -#include "kvm.h" //#define DEBUG_VGA //#define DEBUG_VGA_MEM @@ -1573,34 +1572,36 @@ static void vga_sync_dirty_bitmap(VGACommonState *s) void vga_dirty_log_start(VGACommonState *s) { - if (kvm_enabled() && s->map_addr) - kvm_log_start(s->map_addr, s->map_end - s->map_addr); + if (s->map_addr) { + cpu_physical_log_start(s->map_addr, s->map_end - s->map_addr); + } - if (kvm_enabled() && s->lfb_vram_mapped) { - kvm_log_start(isa_mem_base + 0xa0000, 0x8000); - kvm_log_start(isa_mem_base + 0xa8000, 0x8000); + if (s->lfb_vram_mapped) { + cpu_physical_log_start(isa_mem_base + 0xa0000, 0x8000); + cpu_physical_log_start(isa_mem_base + 0xa8000, 0x8000); } #ifdef CONFIG_BOCHS_VBE - if (kvm_enabled() && s->vbe_mapped) { - kvm_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size); + if (s->vbe_mapped) { + cpu_physical_log_start(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size); } #endif } void vga_dirty_log_stop(VGACommonState *s) { - if (kvm_enabled() && s->map_addr) - kvm_log_stop(s->map_addr, s->map_end - s->map_addr); + if (s->map_addr) { + cpu_physical_log_stop(s->map_addr, s->map_end - s->map_addr); + } - if (kvm_enabled() && s->lfb_vram_mapped) { - kvm_log_stop(isa_mem_base + 0xa0000, 0x8000); - kvm_log_stop(isa_mem_base + 0xa8000, 0x8000); + if (s->lfb_vram_mapped) { + cpu_physical_log_stop(isa_mem_base + 0xa0000, 0x8000); + cpu_physical_log_stop(isa_mem_base + 0xa8000, 0x8000); } #ifdef CONFIG_BOCHS_VBE - if (kvm_enabled() && s->vbe_mapped) { - kvm_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size); + if (s->vbe_mapped) { + cpu_physical_log_stop(VBE_DISPI_LFB_PHYSICAL_ADDRESS, s->vram_size); } #endif } diff --git a/hw/vhost.c b/hw/vhost.c index 38cc3b365b..0ca3507f44 100644 --- a/hw/vhost.c +++ b/hw/vhost.c @@ -607,6 +607,8 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force) hdev->client.set_memory = vhost_client_set_memory; hdev->client.sync_dirty_bitmap = vhost_client_sync_dirty_bitmap; hdev->client.migration_log = vhost_client_migration_log; + hdev->client.log_start = NULL; + hdev->client.log_stop = NULL; hdev->mem = qemu_mallocz(offsetof(struct vhost_memory, regions)); hdev->log = NULL; hdev->log_size = 0; diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c index ffac5a4d8f..b14fb995e8 100644 --- a/hw/virtio-blk.c +++ b/hw/virtio-blk.c @@ -78,7 +78,7 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error, req->next = s->rq; s->rq = req; bdrv_mon_event(s->bs, BDRV_ACTION_STOP, is_read); - vm_stop(0); + vm_stop(VMSTOP_DISKFULL); } else { virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR); bdrv_mon_event(s->bs, BDRV_ACTION_REPORT, is_read); diff --git a/hw/vmmouse.c b/hw/vmmouse.c index 209711942f..ab8dbd6ccb 100644 --- a/hw/vmmouse.c +++ b/hw/vmmouse.c @@ -25,6 +25,7 @@ #include "console.h" #include "ps2.h" #include "pc.h" +#include "qdev.h" /* debug only vmmouse */ //#define DEBUG_VMMOUSE @@ -52,6 +53,7 @@ typedef struct _VMMouseState { + ISADevice dev; uint32_t queue[VMMOUSE_QUEUE_SIZE]; int32_t queue_size; uint16_t nb_queue; @@ -176,30 +178,6 @@ static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size) memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue); } -static void vmmouse_get_data(uint32_t *data) -{ - CPUState *env = cpu_single_env; - - data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX]; - data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX]; - data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI]; - - DPRINTF("get_data = {%x, %x, %x, %x, %x, %x}\n", - data[0], data[1], data[2], data[3], data[4], data[5]); -} - -static void vmmouse_set_data(const uint32_t *data) -{ - CPUState *env = cpu_single_env; - - DPRINTF("set_data = {%x, %x, %x, %x, %x, %x}\n", - data[0], data[1], data[2], data[3], data[4], data[5]); - - env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1]; - env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3]; - env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5]; -} - static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr) { VMMouseState *s = opaque; @@ -270,22 +248,42 @@ static const VMStateDescription vmstate_vmmouse = { } }; -void *vmmouse_init(void *m) +static void vmmouse_reset(DeviceState *d) { - VMMouseState *s = NULL; - - DPRINTF("vmmouse_init\n"); - - s = qemu_mallocz(sizeof(VMMouseState)); + VMMouseState *s = container_of(d, VMMouseState, dev.qdev); s->status = 0xffff; - s->ps2_mouse = m; s->queue_size = VMMOUSE_QUEUE_SIZE; +} + +static int vmmouse_initfn(ISADevice *dev) +{ + VMMouseState *s = DO_UPCAST(VMMouseState, dev, dev); + + DPRINTF("vmmouse_init\n"); vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s); vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s); vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s); vmstate_register(NULL, 0, &vmstate_vmmouse, s); - return s; + return 0; +} + +static ISADeviceInfo vmmouse_info = { + .init = vmmouse_initfn, + .qdev.name = "vmmouse", + .qdev.size = sizeof(VMMouseState), + .qdev.no_user = 1, + .qdev.reset = vmmouse_reset, + .qdev.props = (Property[]) { + DEFINE_PROP_PTR("ps2_mouse", VMMouseState, ps2_mouse), + DEFINE_PROP_END_OF_LIST(), + } +}; + +static void vmmouse_dev_register(void) +{ + isa_qdev_register(&vmmouse_info); } +device_init(vmmouse_dev_register) diff --git a/hw/vmport.c b/hw/vmport.c index 6c9d7c9651..292d78ffb4 100644 --- a/hw/vmport.c +++ b/hw/vmport.c @@ -26,6 +26,7 @@ #include "pc.h" #include "sysemu.h" #include "kvm.h" +#include "qdev.h" //#define VMPORT_DEBUG @@ -37,6 +38,7 @@ typedef struct _VMPortState { + ISADevice dev; IOPortReadFunc *func[VMPORT_ENTRIES]; void *opaque[VMPORT_ENTRIES]; } VMPortState; @@ -100,12 +102,47 @@ static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr) return ram_size; } -void vmport_init(void) +/* vmmouse helpers */ +void vmmouse_get_data(uint32_t *data) { - register_ioport_read(0x5658, 1, 4, vmport_ioport_read, &port_state); - register_ioport_write(0x5658, 1, 4, vmport_ioport_write, &port_state); + CPUState *env = cpu_single_env; + + data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX]; + data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX]; + data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI]; +} + +void vmmouse_set_data(const uint32_t *data) +{ + CPUState *env = cpu_single_env; + + env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1]; + env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3]; + env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5]; +} + +static int vmport_initfn(ISADevice *dev) +{ + VMPortState *s = DO_UPCAST(VMPortState, dev, dev); + register_ioport_read(0x5658, 1, 4, vmport_ioport_read, &s); + register_ioport_write(0x5658, 1, 4, vmport_ioport_write, &s); + isa_init_ioport(dev, 0x5658); /* Register some generic port commands */ vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, NULL); vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, NULL); + return 0; +} + +static ISADeviceInfo vmport_info = { + .qdev.name = "vmport", + .qdev.size = sizeof(VMPortState), + .qdev.no_user = 1, + .init = vmport_initfn, +}; + +static void vmport_dev_register(void) +{ + isa_qdev_register(&vmport_info); } +device_init(vmport_dev_register) diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 6c59053308..4656767964 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -1309,11 +1309,6 @@ static int pci_vmsvga_initfn(PCIDevice *dev) return 0; } -void pci_vmsvga_init(PCIBus *bus) -{ - pci_create_simple(bus, -1, "vmware-svga"); -} - static PCIDeviceInfo vmsvga_info = { .qdev.name = "vmware-svga", .qdev.size = sizeof(struct pci_vmsvga_state_s), diff --git a/hw/vmware_vga.h b/hw/vmware_vga.h index 2e0813c81b..5132573a56 100644 --- a/hw/vmware_vga.h +++ b/hw/vmware_vga.h @@ -4,6 +4,16 @@ #include "qemu-common.h" /* vmware_vga.c */ -void pci_vmsvga_init(PCIBus *bus); +static inline bool pci_vmsvga_init(PCIBus *bus) +{ + PCIDevice *dev; + + dev = pci_try_create(bus, -1, "vmware-svga"); + if (!dev || qdev_init(&dev->qdev) < 0) { + return false; + } else { + return true; + } +} #endif diff --git a/hw/watchdog.c b/hw/watchdog.c index e9dd56e229..1c900a1189 100644 --- a/hw/watchdog.c +++ b/hw/watchdog.c @@ -132,7 +132,7 @@ void watchdog_perform_action(void) case WDT_PAUSE: /* same as 'stop' command in monitor */ watchdog_mon_event("pause"); - vm_stop(0); + vm_stop(VMSTOP_WATCHDOG); break; case WDT_DEBUG: diff --git a/hw/zaurus.c b/hw/zaurus.c index fca11a5333..c24aeb5763 100644 --- a/hw/zaurus.c +++ b/hw/zaurus.c @@ -16,7 +16,6 @@ * with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "hw.h" -#include "pxa.h" #include "sharpsl.h" #include "sysbus.h" @@ -181,17 +180,34 @@ static int scoop_init(SysBusDevice *dev) return 0; } +static int scoop_post_load(void *opaque, int version_id) +{ + ScoopInfo *s = (ScoopInfo *) opaque; + int i; + uint32_t level; + + level = s->gpio_level & s->gpio_dir; + + for (i = 0; i < 16; i++) { + qemu_set_irq(s->handler[i], (level >> i) & 1); + } + + s->prev_level = level; + + return 0; +} + static bool is_version_0 (void *opaque, int version_id) { return version_id == 0; } - static const VMStateDescription vmstate_scoop_regs = { .name = "scoop", .version_id = 1, .minimum_version_id = 0, .minimum_version_id_old = 0, + .post_load = scoop_post_load, .fields = (VMStateField []) { VMSTATE_UINT16(status, ScoopInfo), VMSTATE_UINT16(power, ScoopInfo), diff --git a/kvm-all.c b/kvm-all.c index 2ec9e0980d..e6a7de4722 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -78,7 +78,7 @@ struct KVMState int many_ioeventfds; }; -static KVMState *kvm_state; +KVMState *kvm_state; static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_INFO(USER_MEMORY), @@ -91,10 +91,6 @@ static KVMSlot *kvm_alloc_slot(KVMState *s) int i; for (i = 0; i < ARRAY_SIZE(s->slots); i++) { - /* KVM private memory slots */ - if (i >= 8 && i < 12) { - continue; - } if (s->slots[i].memory_size == 0) { return &s->slots[i]; } @@ -199,7 +195,6 @@ int kvm_pit_in_kernel(void) return kvm_state->pit_in_kernel; } - int kvm_init_vcpu(CPUState *env) { KVMState *s = kvm_state; @@ -219,6 +214,7 @@ int kvm_init_vcpu(CPUState *env) mmap_size = kvm_ioctl(s, KVM_GET_VCPU_MMAP_SIZE, 0); if (mmap_size < 0) { + ret = mmap_size; DPRINTF("KVM_GET_VCPU_MMAP_SIZE failed\n"); goto err; } @@ -278,13 +274,15 @@ static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr, return kvm_set_user_memory_region(s, mem); } -int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size) +static int kvm_log_start(CPUPhysMemoryClient *client, + target_phys_addr_t phys_addr, ram_addr_t size) { return kvm_dirty_pages_log_change(phys_addr, size, KVM_MEM_LOG_DIRTY_PAGES, KVM_MEM_LOG_DIRTY_PAGES); } -int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size) +static int kvm_log_stop(CPUPhysMemoryClient *client, + target_phys_addr_t phys_addr, ram_addr_t size) { return kvm_dirty_pages_log_change(phys_addr, size, 0, KVM_MEM_LOG_DIRTY_PAGES); @@ -648,6 +646,8 @@ static CPUPhysMemoryClient kvm_cpu_phys_memory_client = { .set_memory = kvm_client_set_memory, .sync_dirty_bitmap = kvm_client_sync_dirty_bitmap, .migration_log = kvm_client_migration_log, + .log_start = kvm_log_start, + .log_stop = kvm_log_stop, }; int kvm_init(void) @@ -774,8 +774,8 @@ err: return ret; } -static int kvm_handle_io(uint16_t port, void *data, int direction, int size, - uint32_t count) +static void kvm_handle_io(uint16_t port, void *data, int direction, int size, + uint32_t count) { int i; uint8_t *ptr = data; @@ -809,8 +809,6 @@ static int kvm_handle_io(uint16_t port, void *data, int direction, int size, ptr += size; } - - return 1; } #ifdef KVM_CAP_INTERNAL_ERROR_DATA @@ -895,29 +893,34 @@ int kvm_cpu_exec(CPUState *env) DPRINTF("kvm_cpu_exec()\n"); - do { -#ifndef CONFIG_IOTHREAD - if (env->exit_request) { - DPRINTF("interrupt exit requested\n"); - ret = 0; - break; - } -#endif + if (kvm_arch_process_irqchip_events(env)) { + env->exit_request = 0; + return EXCP_HLT; + } - if (kvm_arch_process_irqchip_events(env)) { - ret = 0; - break; - } + cpu_single_env = env; + do { 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); + if (env->exit_request) { + DPRINTF("interrupt exit requested\n"); + /* + * KVM requires us to reenter the kernel after IO exits to complete + * instruction emulation. This self-signal will ensure that we + * leave ASAP again. + */ + qemu_cpu_kick_self(); + } 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); @@ -925,7 +928,6 @@ int kvm_cpu_exec(CPUState *env) kvm_flush_coalesced_mmio_buffer(); if (ret == -EINTR || ret == -EAGAIN) { - cpu_exit(env); DPRINTF("io window exit\n"); ret = 0; break; @@ -940,11 +942,12 @@ int kvm_cpu_exec(CPUState *env) switch (run->exit_reason) { case KVM_EXIT_IO: DPRINTF("handle_io\n"); - ret = kvm_handle_io(run->io.port, - (uint8_t *)run + run->io.data_offset, - run->io.direction, - run->io.size, - run->io.count); + kvm_handle_io(run->io.port, + (uint8_t *)run + run->io.data_offset, + run->io.direction, + run->io.size, + run->io.count); + ret = 1; break; case KVM_EXIT_MMIO: DPRINTF("handle_mmio\n"); @@ -960,7 +963,6 @@ int kvm_cpu_exec(CPUState *env) case KVM_EXIT_SHUTDOWN: DPRINTF("shutdown\n"); qemu_system_reset_request(); - ret = 1; break; case KVM_EXIT_UNKNOWN: fprintf(stderr, "KVM: unknown exit, hardware reason %" PRIx64 "\n", @@ -976,8 +978,8 @@ int kvm_cpu_exec(CPUState *env) DPRINTF("kvm_exit_debug\n"); #ifdef KVM_CAP_SET_GUEST_DEBUG if (kvm_arch_debug(&run->debug.arch)) { - env->exception_index = EXCP_DEBUG; - return 0; + ret = EXCP_DEBUG; + goto out; } /* re-enter, this exception was guest-internal */ ret = 1; @@ -992,14 +994,13 @@ int kvm_cpu_exec(CPUState *env) if (ret < 0) { cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE); - vm_stop(0); - env->exit_request = 1; - } - if (env->exit_request) { - env->exit_request = 0; - env->exception_index = EXCP_INTERRUPT; + vm_stop(VMSTOP_PANIC); } + ret = EXCP_INTERRUPT; +out: + env->exit_request = 0; + cpu_single_env = NULL; return ret; } @@ -1365,3 +1366,13 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign) return -ENOSYS; #endif } + +int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr) +{ + return kvm_arch_on_sigbus_vcpu(env, code, addr); +} + +int kvm_on_sigbus(int code, void *addr) +{ + return kvm_arch_on_sigbus(code, addr); +} diff --git a/kvm-stub.c b/kvm-stub.c index 88682f288b..30f6ec3956 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -33,16 +33,6 @@ int kvm_init_vcpu(CPUState *env) return -ENOSYS; } -int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size) -{ - return -ENOSYS; -} - -int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size) -{ - return -ENOSYS; -} - int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size) { return -ENOSYS; @@ -147,6 +137,11 @@ int kvm_set_ioeventfd_mmio_long(int fd, uint32_t adr, uint32_t val, bool assign) return -ENOSYS; } +int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr) +{ + return 1; +} + int kvm_on_sigbus(int code, void *addr) { return 1; diff --git a/kvm.h b/kvm.h index ca57517af2..59b2c29fd9 100644 --- a/kvm.h +++ b/kvm.h @@ -58,9 +58,6 @@ int kvm_init_vcpu(CPUState *env); int kvm_cpu_exec(CPUState *env); #if !defined(CONFIG_USER_ONLY) -int kvm_log_start(target_phys_addr_t phys_addr, ram_addr_t size); -int kvm_log_stop(target_phys_addr_t phys_addr, ram_addr_t size); - void kvm_setup_guest_memory(void *start, size_t size); int kvm_coalesce_mmio_region(target_phys_addr_t start, ram_addr_t size); @@ -81,10 +78,14 @@ int kvm_set_signal_mask(CPUState *env, const sigset_t *sigset); int kvm_pit_in_kernel(void); int kvm_irqchip_in_kernel(void); +int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr); +int kvm_on_sigbus(int code, void *addr); + /* internal API */ struct KVMState; typedef struct KVMState KVMState; +extern KVMState *kvm_state; int kvm_ioctl(KVMState *s, int type, ...); @@ -96,12 +97,11 @@ int kvm_vcpu_ioctl(CPUState *env, int type, ...); extern const KVMCapabilityInfo kvm_arch_required_capabilities[]; -int kvm_arch_post_run(CPUState *env, struct kvm_run *run); +void kvm_arch_pre_run(CPUState *env, struct kvm_run *run); +void kvm_arch_post_run(CPUState *env, struct kvm_run *run); 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); @@ -121,8 +121,8 @@ int kvm_arch_init_vcpu(CPUState *env); void kvm_arch_reset_vcpu(CPUState *env); -int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr); -int kvm_on_sigbus(int code, void *addr); +int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr); +int kvm_arch_on_sigbus(int code, void *addr); struct kvm_guest_debug; struct kvm_debug_exit_arch; diff --git a/linux-user/arm/nwfpe/fpa11_cpdt.c b/linux-user/arm/nwfpe/fpa11_cpdt.c index 1346fd619d..b12e27dcb0 100644 --- a/linux-user/arm/nwfpe/fpa11_cpdt.c +++ b/linux-user/arm/nwfpe/fpa11_cpdt.c @@ -33,7 +33,7 @@ void loadSingle(const unsigned int Fn, target_ulong addr) FPA11 *fpa11 = GET_FPA11(); fpa11->fType[Fn] = typeSingle; /* FIXME - handle failure of get_user() */ - get_user_u32(fpa11->fpreg[Fn].fSingle, addr); + get_user_u32(float32_val(fpa11->fpreg[Fn].fSingle), addr); } static inline diff --git a/linux-user/arm/nwfpe/fpopcode.c b/linux-user/arm/nwfpe/fpopcode.c index 240061dd61..82ac92f0ce 100644 --- a/linux-user/arm/nwfpe/fpopcode.c +++ b/linux-user/arm/nwfpe/fpopcode.c @@ -37,25 +37,25 @@ const floatx80 floatx80Constant[] = { }; const float64 float64Constant[] = { - 0x0000000000000000ULL, /* double 0.0 */ - 0x3ff0000000000000ULL, /* double 1.0 */ - 0x4000000000000000ULL, /* double 2.0 */ - 0x4008000000000000ULL, /* double 3.0 */ - 0x4010000000000000ULL, /* double 4.0 */ - 0x4014000000000000ULL, /* double 5.0 */ - 0x3fe0000000000000ULL, /* double 0.5 */ - 0x4024000000000000ULL /* double 10.0 */ + const_float64(0x0000000000000000ULL), /* double 0.0 */ + const_float64(0x3ff0000000000000ULL), /* double 1.0 */ + const_float64(0x4000000000000000ULL), /* double 2.0 */ + const_float64(0x4008000000000000ULL), /* double 3.0 */ + const_float64(0x4010000000000000ULL), /* double 4.0 */ + const_float64(0x4014000000000000ULL), /* double 5.0 */ + const_float64(0x3fe0000000000000ULL), /* double 0.5 */ + const_float64(0x4024000000000000ULL) /* double 10.0 */ }; const float32 float32Constant[] = { - 0x00000000, /* single 0.0 */ - 0x3f800000, /* single 1.0 */ - 0x40000000, /* single 2.0 */ - 0x40400000, /* single 3.0 */ - 0x40800000, /* single 4.0 */ - 0x40a00000, /* single 5.0 */ - 0x3f000000, /* single 0.5 */ - 0x41200000 /* single 10.0 */ + const_float32(0x00000000), /* single 0.0 */ + const_float32(0x3f800000), /* single 1.0 */ + const_float32(0x40000000), /* single 2.0 */ + const_float32(0x40400000), /* single 3.0 */ + const_float32(0x40800000), /* single 4.0 */ + const_float32(0x40a00000), /* single 5.0 */ + const_float32(0x3f000000), /* single 0.5 */ + const_float32(0x41200000) /* single 10.0 */ }; unsigned int getRegisterCount(const unsigned int opcode) diff --git a/linux-user/signal.c b/linux-user/signal.c index b01bd64011..ce033e90b4 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -1299,7 +1299,7 @@ static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUState *env) __put_user(TARGET_VFP_MAGIC, &vfpframe->magic); __put_user(sizeof(*vfpframe), &vfpframe->size); for (i = 0; i < 32; i++) { - __put_user(env->vfp.regs[i], &vfpframe->ufp.fpregs[i]); + __put_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]); } __put_user(vfp_get_fpscr(env), &vfpframe->ufp.fpscr); __put_user(env->vfp.xregs[ARM_VFP_FPEXC], &vfpframe->ufp_exc.fpexc); @@ -1588,7 +1588,7 @@ static abi_ulong *restore_sigframe_v2_vfp(CPUState *env, abi_ulong *regspace) return 0; } for (i = 0; i < 32; i++) { - __get_user(env->vfp.regs[i], &vfpframe->ufp.fpregs[i]); + __get_user(float64_val(env->vfp.regs[i]), &vfpframe->ufp.fpregs[i]); } __get_user(fpscr, &vfpframe->ufp.fpscr); vfp_set_fpscr(env, fpscr); diff --git a/migration.c b/migration.c index 36125720a4..af3a1f2702 100644 --- a/migration.c +++ b/migration.c @@ -378,7 +378,7 @@ void migrate_fd_put_ready(void *opaque) int old_vm_running = vm_running; DPRINTF("done iterating\n"); - vm_stop(0); + vm_stop(VMSTOP_MIGRATE); if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) { if (old_vm_running) { diff --git a/monitor.c b/monitor.c index 7fc311d720..22ae3bbff0 100644 --- a/monitor.c +++ b/monitor.c @@ -1255,7 +1255,7 @@ static void do_singlestep(Monitor *mon, const QDict *qdict) */ static int do_stop(Monitor *mon, const QDict *qdict, QObject **ret_data) { - vm_stop(EXCP_INTERRUPT); + vm_stop(VMSTOP_USER); return 0; } @@ -2783,7 +2783,7 @@ static void do_loadvm(Monitor *mon, const QDict *qdict) int saved_vm_running = vm_running; const char *name = qdict_get_str(qdict, "name"); - vm_stop(0); + vm_stop(VMSTOP_LOADVM); if (load_vmstate(name) == 0 && saved_vm_running) { vm_start(); diff --git a/qemu-common.h b/qemu-common.h index cb4b7e0d38..40dad5208c 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -288,6 +288,7 @@ void qemu_notify_event(void); /* Unblock cpu */ void qemu_cpu_kick(void *env); +void qemu_cpu_kick_self(void); int qemu_cpu_self(void *env); /* work queue */ diff --git a/savevm.c b/savevm.c index 6d83b0f4dc..a50fd31154 100644 --- a/savevm.c +++ b/savevm.c @@ -1575,7 +1575,7 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f) int ret; saved_vm_running = vm_running; - vm_stop(0); + vm_stop(VMSTOP_SAVEVM); if (qemu_savevm_state_blocked(mon)) { ret = -EINVAL; @@ -1904,7 +1904,7 @@ void do_savevm(Monitor *mon, const QDict *qdict) } saved_vm_running = vm_running; - vm_stop(0); + vm_stop(VMSTOP_SAVEVM); memset(sn, 0, sizeof(*sn)); diff --git a/slirp/mbuf.c b/slirp/mbuf.c index 87508ba013..ce2eb843f5 100644 --- a/slirp/mbuf.c +++ b/slirp/mbuf.c @@ -23,7 +23,7 @@ * Find a nice value for msize * XXX if_maxlinkhdr already in mtu */ -#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + sizeof(struct m_hdr ) + 6) +#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6) void m_init(Slirp *slirp) @@ -65,7 +65,7 @@ m_get(Slirp *slirp) m->m_flags = (flags | M_USEDLIST); /* Initialise it */ - m->m_size = SLIRP_MSIZE - sizeof(struct m_hdr); + m->m_size = SLIRP_MSIZE - offsetof(struct mbuf, m_dat); m->m_data = m->m_dat; m->m_len = 0; m->m_nextpkt = NULL; diff --git a/sysemu.h b/sysemu.h index 23ae17e2e9..0a83ab9e56 100644 --- a/sysemu.h +++ b/sysemu.h @@ -37,6 +37,16 @@ VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, void *opaque); void qemu_del_vm_change_state_handler(VMChangeStateEntry *e); +#define VMSTOP_USER 0 +#define VMSTOP_DEBUG 1 +#define VMSTOP_SHUTDOWN 2 +#define VMSTOP_DISKFULL 3 +#define VMSTOP_WATCHDOG 4 +#define VMSTOP_PANIC 5 +#define VMSTOP_SAVEVM 6 +#define VMSTOP_LOADVM 7 +#define VMSTOP_MIGRATE 8 + void vm_start(void); void vm_stop(int reason); @@ -51,6 +61,8 @@ void cpu_disable_ticks(void); void qemu_system_reset_request(void); void qemu_system_shutdown_request(void); void qemu_system_powerdown_request(void); +void qemu_system_debug_request(void); +void qemu_system_vmstop_request(int reason); int qemu_shutdown_requested(void); int qemu_reset_requested(void); int qemu_powerdown_requested(void); diff --git a/target-arm/cpu.h b/target-arm/cpu.h index 0d963250e7..c9febfac4c 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -157,10 +157,6 @@ typedef struct CPUARMState { /* Internal CPU feature flags. */ uint32_t features; - /* Callback for vectored interrupt controller. */ - int (*get_irq_vector)(struct CPUARMState *); - void *irq_opaque; - /* VFP coprocessor state. */ struct { float64 regs[32]; diff --git a/target-arm/helper.c b/target-arm/helper.c index d46defc118..7f63a280fc 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -2623,18 +2623,44 @@ VFP_CONV_FIX(ul, s, float32, uint32, u) #undef VFP_CONV_FIX /* Half precision conversions. */ -float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env) +static float32 do_fcvt_f16_to_f32(uint32_t a, CPUState *env, float_status *s) { - float_status *s = &env->vfp.fp_status; int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0; - return float16_to_float32(a, ieee, s); + float32 r = float16_to_float32(make_float16(a), ieee, s); + if (ieee) { + return float32_maybe_silence_nan(r); + } + return r; } -uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env) +static uint32_t do_fcvt_f32_to_f16(float32 a, CPUState *env, float_status *s) { - float_status *s = &env->vfp.fp_status; int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0; - return float32_to_float16(a, ieee, s); + float16 r = float32_to_float16(a, ieee, s); + if (ieee) { + r = float16_maybe_silence_nan(r); + } + return float16_val(r); +} + +float32 HELPER(neon_fcvt_f16_to_f32)(uint32_t a, CPUState *env) +{ + return do_fcvt_f16_to_f32(a, env, &env->vfp.standard_fp_status); +} + +uint32_t HELPER(neon_fcvt_f32_to_f16)(float32 a, CPUState *env) +{ + return do_fcvt_f32_to_f16(a, env, &env->vfp.standard_fp_status); +} + +float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env) +{ + return do_fcvt_f16_to_f32(a, env, &env->vfp.fp_status); +} + +uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env) +{ + return do_fcvt_f32_to_f16(a, env, &env->vfp.fp_status); } float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env) diff --git a/target-arm/helpers.h b/target-arm/helpers.h index 4d0de00eab..77f1635728 100644 --- a/target-arm/helpers.h +++ b/target-arm/helpers.h @@ -129,6 +129,8 @@ DEF_HELPER_3(vfp_ultod, f64, f64, i32, env) DEF_HELPER_2(vfp_fcvt_f16_to_f32, f32, i32, env) DEF_HELPER_2(vfp_fcvt_f32_to_f16, i32, f32, env) +DEF_HELPER_2(neon_fcvt_f16_to_f32, f32, i32, env) +DEF_HELPER_2(neon_fcvt_f32_to_f16, i32, f32, env) DEF_HELPER_3(recps_f32, f32, f32, f32, env) DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env) diff --git a/target-arm/neon_helper.c b/target-arm/neon_helper.c index 61890dd69a..dc09968c86 100644 --- a/target-arm/neon_helper.c +++ b/target-arm/neon_helper.c @@ -1484,7 +1484,6 @@ uint64_t HELPER(neon_negl_u16)(uint64_t x) return result; } -#include <stdio.h> uint64_t HELPER(neon_negl_u32)(uint64_t x) { uint32_t low = -x; diff --git a/target-arm/translate.c b/target-arm/translate.c index 3087a5dcdd..362d1d0964 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -5535,17 +5535,17 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tmp = new_tmp(); tmp2 = new_tmp(); tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0)); - gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); + gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1)); - gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env); + gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env); tcg_gen_shli_i32(tmp2, tmp2, 16); tcg_gen_or_i32(tmp2, tmp2, tmp); tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2)); - gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); + gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env); tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3)); neon_store_reg(rd, 0, tmp2); tmp2 = new_tmp(); - gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env); + gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env); tcg_gen_shli_i32(tmp2, tmp2, 16); tcg_gen_or_i32(tmp2, tmp2, tmp); neon_store_reg(rd, 1, tmp2); @@ -5558,17 +5558,17 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn) tmp = neon_load_reg(rm, 0); tmp2 = neon_load_reg(rm, 1); tcg_gen_ext16u_i32(tmp3, tmp); - gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0)); tcg_gen_shri_i32(tmp3, tmp, 16); - gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1)); dead_tmp(tmp); tcg_gen_ext16u_i32(tmp3, tmp2); - gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2)); tcg_gen_shri_i32(tmp3, tmp2, 16); - gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); + gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env); tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3)); dead_tmp(tmp2); dead_tmp(tmp3); diff --git a/target-i386/cpu.h b/target-i386/cpu.h index af701a4412..5f1df8b4d3 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -734,6 +734,7 @@ typedef struct CPUX86State { uint32_t sipi_vector; uint32_t cpuid_kvm_features; uint32_t cpuid_svm_features; + bool tsc_valid; /* in order to simplify APIC support, we leave this pointer to the user */ diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 05010bbc38..0aa0a410da 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -301,6 +301,15 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, #endif } +static void cpu_update_state(void *opaque, int running, int reason) +{ + CPUState *env = opaque; + + if (running) { + env->tsc_valid = false; + } +} + int kvm_arch_init_vcpu(CPUState *env) { struct { @@ -434,6 +443,8 @@ int kvm_arch_init_vcpu(CPUState *env) } #endif + qemu_add_vm_change_state_handler(cpu_update_state, env); + return kvm_vcpu_ioctl(env, KVM_SET_CPUID2, &cpuid_data); } @@ -1061,7 +1072,12 @@ static int kvm_get_msrs(CPUState *env) if (has_msr_hsave_pa) { msrs[n++].index = MSR_VM_HSAVE_PA; } - msrs[n++].index = MSR_IA32_TSC; + + if (!env->tsc_valid) { + msrs[n++].index = MSR_IA32_TSC; + env->tsc_valid = !vm_running; + } + #ifdef TARGET_X86_64 if (lm_capable_kernel) { msrs[n++].index = MSR_CSTAR; @@ -1424,49 +1440,65 @@ int kvm_arch_get_registers(CPUState *env) return 0; } -int kvm_arch_pre_run(CPUState *env, struct kvm_run *run) +void kvm_arch_pre_run(CPUState *env, struct kvm_run *run) { + int ret; + /* Inject NMI */ if (env->interrupt_request & CPU_INTERRUPT_NMI) { env->interrupt_request &= ~CPU_INTERRUPT_NMI; DPRINTF("injected NMI\n"); - kvm_vcpu_ioctl(env, KVM_NMI); - } - - /* Try to inject an interrupt if the guest can accept it */ - if (run->ready_for_interrupt_injection && - (env->interrupt_request & CPU_INTERRUPT_HARD) && - (env->eflags & IF_MASK)) { - int irq; - - env->interrupt_request &= ~CPU_INTERRUPT_HARD; - irq = cpu_get_pic_interrupt(env); - if (irq >= 0) { - struct kvm_interrupt intr; - intr.irq = irq; - /* FIXME: errors */ - DPRINTF("injected interrupt %d\n", irq); - kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr); + ret = kvm_vcpu_ioctl(env, KVM_NMI); + if (ret < 0) { + fprintf(stderr, "KVM: injection failed, NMI lost (%s)\n", + strerror(-ret)); } } - /* If we have an interrupt but the guest is not ready to receive an - * interrupt, request an interrupt window exit. This will - * cause a return to userspace as soon as the guest is ready to - * receive interrupts. */ - if ((env->interrupt_request & CPU_INTERRUPT_HARD)) { - run->request_interrupt_window = 1; - } else { - run->request_interrupt_window = 0; - } + if (!kvm_irqchip_in_kernel()) { + /* Force the VCPU out of its inner loop to process the INIT request */ + if (env->interrupt_request & CPU_INTERRUPT_INIT) { + env->exit_request = 1; + } - DPRINTF("setting tpr\n"); - run->cr8 = cpu_get_apic_tpr(env->apic_state); + /* Try to inject an interrupt if the guest can accept it */ + if (run->ready_for_interrupt_injection && + (env->interrupt_request & CPU_INTERRUPT_HARD) && + (env->eflags & IF_MASK)) { + int irq; + + env->interrupt_request &= ~CPU_INTERRUPT_HARD; + irq = cpu_get_pic_interrupt(env); + if (irq >= 0) { + struct kvm_interrupt intr; + + intr.irq = irq; + DPRINTF("injected interrupt %d\n", irq); + ret = kvm_vcpu_ioctl(env, KVM_INTERRUPT, &intr); + if (ret < 0) { + fprintf(stderr, + "KVM: injection failed, interrupt lost (%s)\n", + strerror(-ret)); + } + } + } - return 0; + /* If we have an interrupt but the guest is not ready to receive an + * interrupt, request an interrupt window exit. This will + * cause a return to userspace as soon as the guest is ready to + * receive interrupts. */ + if ((env->interrupt_request & CPU_INTERRUPT_HARD)) { + run->request_interrupt_window = 1; + } else { + run->request_interrupt_window = 0; + } + + DPRINTF("setting tpr\n"); + run->cr8 = cpu_get_apic_tpr(env->apic_state); + } } -int kvm_arch_post_run(CPUState *env, struct kvm_run *run) +void kvm_arch_post_run(CPUState *env, struct kvm_run *run) { if (run->if_flag) { env->eflags |= IF_MASK; @@ -1475,18 +1507,21 @@ int kvm_arch_post_run(CPUState *env, struct kvm_run *run) } cpu_set_apic_tpr(env->apic_state, run->cr8); cpu_set_apic_base(env->apic_state, run->apic_base); - - return 0; } int kvm_arch_process_irqchip_events(CPUState *env) { + if (kvm_irqchip_in_kernel()) { + return 0; + } + + if (env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI)) { + env->halted = 0; + } 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); @@ -1501,7 +1536,6 @@ static int kvm_handle_halt(CPUState *env) (env->eflags & IF_MASK)) && !(env->interrupt_request & CPU_INTERRUPT_NMI)) { env->halted = 1; - env->exception_index = EXCP_HLT; return 0; } @@ -1839,7 +1873,7 @@ static void kvm_mce_inj_srao_memscrub2(CPUState *env, target_phys_addr_t paddr) #endif -int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr) +int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) { #if defined(KVM_CAP_MCE) void *vaddr; @@ -1889,7 +1923,7 @@ int kvm_on_sigbus_vcpu(CPUState *env, int code, void *addr) return 0; } -int kvm_on_sigbus(int code, void *addr) +int kvm_arch_on_sigbus(int code, void *addr) { #if defined(KVM_CAP_MCE) if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) { diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 710eca1dca..bd4012a4ec 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -256,14 +256,12 @@ int kvm_arch_pre_run(CPUState *env, struct kvm_run *run) return 0; } -int kvm_arch_post_run(CPUState *env, struct kvm_run *run) +void kvm_arch_post_run(CPUState *env, struct kvm_run *run) { - return 0; } -int kvm_arch_process_irqchip_events(CPUState *env) +void kvm_arch_process_irqchip_events(CPUState *env) { - return 0; } static int kvmppc_handle_halt(CPUState *env) @@ -404,3 +402,13 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env) { return true; } + +int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) +{ + return 1; +} + +int kvm_arch_on_sigbus(int code, void *addr) +{ + return 1; +} diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index dfcd94980f..7c08b1cb09 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -154,12 +154,26 @@ static void spr_read_ureg (void *opaque, int gprn, int sprn) #if !defined(CONFIG_USER_ONLY) static void spr_read_decr (void *opaque, int gprn, int sprn) { + if (use_icount) { + gen_io_start(); + } gen_helper_load_decr(cpu_gpr[gprn]); + if (use_icount) { + gen_io_end(); + gen_stop_exception(opaque); + } } static void spr_write_decr (void *opaque, int sprn, int gprn) { + if (use_icount) { + gen_io_start(); + } gen_helper_store_decr(cpu_gpr[gprn]); + if (use_icount) { + gen_io_end(); + gen_stop_exception(opaque); + } } #endif @@ -167,12 +181,26 @@ static void spr_write_decr (void *opaque, int sprn, int gprn) /* Time base */ static void spr_read_tbl (void *opaque, int gprn, int sprn) { + if (use_icount) { + gen_io_start(); + } gen_helper_load_tbl(cpu_gpr[gprn]); + if (use_icount) { + gen_io_end(); + gen_stop_exception(opaque); + } } static void spr_read_tbu (void *opaque, int gprn, int sprn) { + if (use_icount) { + gen_io_start(); + } gen_helper_load_tbu(cpu_gpr[gprn]); + if (use_icount) { + gen_io_end(); + gen_stop_exception(opaque); + } } __attribute__ (( unused )) @@ -190,12 +218,26 @@ static void spr_read_atbu (void *opaque, int gprn, int sprn) #if !defined(CONFIG_USER_ONLY) static void spr_write_tbl (void *opaque, int sprn, int gprn) { + if (use_icount) { + gen_io_start(); + } gen_helper_store_tbl(cpu_gpr[gprn]); + if (use_icount) { + gen_io_end(); + gen_stop_exception(opaque); + } } static void spr_write_tbu (void *opaque, int sprn, int gprn) { + if (use_icount) { + gen_io_start(); + } gen_helper_store_tbu(cpu_gpr[gprn]); + if (use_icount) { + gen_io_end(); + gen_stop_exception(opaque); + } } __attribute__ (( unused )) diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index 38823f54f7..b349812dba 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -169,14 +169,12 @@ int kvm_arch_remove_sw_breakpoint(CPUState *env, struct kvm_sw_breakpoint *bp) return 0; } -int kvm_arch_pre_run(CPUState *env, struct kvm_run *run) +void kvm_arch_pre_run(CPUState *env, struct kvm_run *run) { - return 0; } -int kvm_arch_post_run(CPUState *env, struct kvm_run *run) +void kvm_arch_post_run(CPUState *env, struct kvm_run *run) { - return 0; } int kvm_arch_process_irqchip_events(CPUState *env) @@ -505,3 +503,13 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env) { return true; } + +int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) +{ + return 1; +} + +int kvm_arch_on_sigbus(int code, void *addr) +{ + return 1; +} diff --git a/vl.c b/vl.c index ed2cdfae42..b436952d6c 100644 --- a/vl.c +++ b/vl.c @@ -1217,8 +1217,8 @@ static QTAILQ_HEAD(reset_handlers, QEMUResetEntry) reset_handlers = static int reset_requested; static int shutdown_requested; static int powerdown_requested; -int debug_requested; -int vmstop_requested; +static int debug_requested; +static int vmstop_requested; int qemu_shutdown_requested(void) { @@ -1296,6 +1296,7 @@ void qemu_system_reset_request(void) } else { reset_requested = 1; } + cpu_stop_current(); qemu_notify_event(); } @@ -1311,6 +1312,18 @@ void qemu_system_powerdown_request(void) qemu_notify_event(); } +void qemu_system_debug_request(void) +{ + debug_requested = 1; + qemu_notify_event(); +} + +void qemu_system_vmstop_request(int reason) +{ + vmstop_requested = reason; + qemu_notify_event(); +} + void main_loop_wait(int nonblocking) { IOHandlerRecord *ioh; @@ -1388,52 +1401,51 @@ void main_loop_wait(int nonblocking) } -static int vm_can_run(void) +#ifndef CONFIG_IOTHREAD +static int vm_request_pending(void) { - if (powerdown_requested) - return 0; - if (reset_requested) - return 0; - if (shutdown_requested) - return 0; - if (debug_requested) - return 0; - return 1; + return powerdown_requested || + reset_requested || + shutdown_requested || + debug_requested || + vmstop_requested; } +#endif qemu_irq qemu_system_powerdown; static void main_loop(void) { + bool nonblocking = false; +#ifdef CONFIG_PROFILER + int64_t ti; +#endif int r; qemu_main_loop_start(); for (;;) { - do { - bool nonblocking = false; -#ifdef CONFIG_PROFILER - int64_t ti; -#endif #ifndef CONFIG_IOTHREAD - nonblocking = cpu_exec_all(); + nonblocking = cpu_exec_all(); + if (vm_request_pending()) { + nonblocking = true; + } #endif #ifdef CONFIG_PROFILER - ti = profile_getclock(); + ti = profile_getclock(); #endif - main_loop_wait(nonblocking); + main_loop_wait(nonblocking); #ifdef CONFIG_PROFILER - dev_time += profile_getclock() - ti; + dev_time += profile_getclock() - ti; #endif - } while (vm_can_run()); - if ((r = qemu_debug_requested())) { - vm_stop(r); + if (qemu_debug_requested()) { + vm_stop(VMSTOP_DEBUG); } if (qemu_shutdown_requested()) { monitor_protocol_event(QEVENT_SHUTDOWN, NULL); if (no_shutdown) { - vm_stop(0); + vm_stop(VMSTOP_SHUTDOWN); no_shutdown = 0; } else break; |