Merge remote branch 'kwolf/for-anthony' into staging
diff --git a/.gitignore b/.gitignore
index 3efb4ec..26703e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,6 +51,8 @@
*.vr
*.d
*.o
+*.swp
+*.orig
.pc
patches
pc-bios/bios-pq/status
@@ -60,3 +62,4 @@
pc-bios/optionrom/multiboot.raw
.stgit-*
cscope.*
+tags
diff --git a/Makefile.objs b/Makefile.objs
index 353b1a8..b21f9d3 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -141,7 +141,7 @@
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_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_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 48e6c00..5a0fd40 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -37,7 +37,7 @@
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-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 598e8e1..a3f5345 100755
--- a/configure
+++ b/configure
@@ -2057,6 +2057,12 @@
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 ffbd6a4..87b0f86 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -959,6 +959,12 @@
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 6d4a898..54d21d4 100644
--- a/cpu-common.h
+++ b/cpu-common.h
@@ -96,6 +96,10 @@
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 8d4bf86..db809ed 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -205,6 +205,7 @@
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 8c9fb8b..b03b3a7 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -196,28 +196,6 @@
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 @@
}
#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 @@
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 @@
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 @@
}
}
- 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 4c9928e..0f33945 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,45 +130,117 @@
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)
{
- gdb_set_stop_cpu(env);
- debug_requested = EXCP_DEBUG;
- vm_stop(EXCP_DEBUG);
+ 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);
+ 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 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 @@
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,125 +305,11 @@
close(fds[1]);
return err;
}
-#else
-HANDLE qemu_event_handle;
-static void dummy_event_handler(void *opaque)
+static void dummy_signal(int sig)
{
}
-static int qemu_event_init(void)
-{
- qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!qemu_event_handle) {
- fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
- return -1;
- }
- qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
- return 0;
-}
-
-static void qemu_event_increment(void)
-{
- if (!SetEvent(qemu_event_handle)) {
- fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n",
- GetLastError());
- exit (1);
- }
-}
-#endif
-
-#ifndef CONFIG_IOTHREAD
-int qemu_init_main_loop(void)
-{
- cpu_set_debug_excp_handler(cpu_debug_handler);
-
- return qemu_event_init();
-}
-
-void qemu_main_loop_start(void)
-{
-}
-
-void qemu_init_vcpu(void *_env)
-{
- CPUState *env = _env;
-
- env->nr_cores = smp_cores;
- env->nr_threads = smp_threads;
- if (kvm_enabled())
- kvm_init_vcpu(env);
- return;
-}
-
-int qemu_cpu_self(void *env)
-{
- return 1;
-}
-
-void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
-{
- func(data);
-}
-
-void resume_all_vcpus(void)
-{
-}
-
-void pause_all_vcpus(void)
-{
-}
-
-void qemu_cpu_kick(void *env)
-{
- return;
-}
-
-void qemu_notify_event(void)
-{
- CPUState *env = cpu_single_env;
-
- qemu_event_increment ();
- if (env) {
- cpu_exit(env);
- }
- if (next_cpu && env != next_cpu) {
- cpu_exit(next_cpu);
- }
-}
-
-void qemu_mutex_lock_iothread(void) {}
-void qemu_mutex_unlock_iothread(void) {}
-
-void vm_stop(int reason)
-{
- do_vm_stop(reason);
-}
-
-#else /* CONFIG_IOTHREAD */
-
-#include "qemu-thread.h"
-
-QemuMutex qemu_global_mutex;
-static QemuMutex qemu_fair_mutex;
-
-static QemuThread io_thread;
-
-static QemuThread *tcg_cpu_thread;
-static QemuCond *tcg_halt_cond;
-
-static int qemu_system_ready;
-/* cpu creation */
-static QemuCond qemu_cpu_cond;
-/* system init */
-static QemuCond qemu_system_cond;
-static QemuCond qemu_pause_cond;
-static QemuCond qemu_work_cond;
-
-static void tcg_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.
@@ -394,26 +363,338 @@
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)
+{
+}
+
+static int qemu_event_init(void)
+{
+ qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!qemu_event_handle) {
+ fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
+ return -1;
+ }
+ qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
+ return 0;
+}
+
+static void qemu_event_increment(void)
+{
+ if (!SetEvent(qemu_event_handle)) {
+ fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n",
+ GetLastError());
+ exit (1);
+ }
+}
+
+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)
+{
+#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();
+}
+
+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()) {
+ 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)
+{
+ return 1;
+}
+
+void run_on_cpu(CPUState *env, void (*func)(void *data), void *data)
+{
+ func(data);
+}
+
+void resume_all_vcpus(void)
+{
+}
+
+void pause_all_vcpus(void)
+{
+}
+
+void qemu_cpu_kick(void *env)
+{
+}
+
+void qemu_cpu_kick_self(void)
+{
+#ifndef _WIN32
+ assert(cpu_single_env);
+
+ raise(SIG_IPI);
+#else
+ abort();
+#endif
+}
+
+void qemu_notify_event(void)
+{
+ CPUState *env = cpu_single_env;
+
+ qemu_event_increment ();
+ if (env) {
+ cpu_exit(env);
+ }
+ 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);
+}
+
+#else /* CONFIG_IOTHREAD */
+
+#include "qemu-thread.h"
+
+QemuMutex qemu_global_mutex;
+static QemuMutex qemu_fair_mutex;
+
+static QemuThread io_thread;
+
+static QemuThread *tcg_cpu_thread;
+static QemuCond *tcg_halt_cond;
+
+static int qemu_system_ready;
+/* cpu creation */
+static QemuCond qemu_cpu_cond;
+/* system init */
+static QemuCond qemu_system_cond;
+static QemuCond qemu_pause_cond;
+static QemuCond qemu_work_cond;
+
+static void cpu_signal(int sig)
+{
+ if (cpu_single_env) {
+ cpu_exit(cpu_single_env);
+ }
+ exit_request = 1;
+}
+
+static void qemu_kvm_init_cpu_signals(CPUState *env)
+{
+ int r;
+ sigset_t set;
+ struct sigaction sigact;
+
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_handler = dummy_signal;
+ sigaction(SIG_IPI, &sigact, NULL);
+
+ 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 void qemu_tcg_init_cpu_signals(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 sigset_t block_io_signals(void)
+{
+ sigset_t set;
+
+ /* 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)
{
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 @@
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 @@
{
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 @@
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 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,8 +870,22 @@
void qemu_cpu_kick(void *_env)
{
CPUState *env = _env;
+
qemu_cond_broadcast(env->halt_cond);
- qemu_thread_signal(env->thread, SIG_IPI);
+ if (!env->thread_kicked) {
+ qemu_thread_signal(env->thread, SIG_IPI);
+ env->thread_kicked = true;
+ }
+}
+
+void qemu_cpu_kick_self(void)
+{
+ assert(cpu_single_env);
+
+ if (!cpu_single_env->thread_kicked) {
+ qemu_thread_signal(cpu_single_env->thread, SIG_IPI);
+ cpu_single_env->thread_kicked = true;
+ }
}
int qemu_cpu_self(void *_env)
@@ -661,77 +898,6 @@
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)
-{
-}
-
-static void kvm_init_ipi(CPUState *env)
-{
- int r;
- sigset_t set;
- struct sigaction sigact;
-
- memset(&sigact, 0, sizeof(sigact));
- sigact.sa_handler = dummy_signal;
- sigaction(SIG_IPI, &sigact, NULL);
-
- 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 sigset_t block_io_signals(void)
-{
- 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);
-
- 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);
-
- return set;
-}
-
void qemu_mutex_lock_iothread(void)
{
if (kvm_enabled()) {
@@ -756,8 +922,9 @@
CPUState *penv = first_cpu;
while (penv) {
- if (!penv->stopped)
+ if (!penv->stopped) {
return 0;
+ }
penv = (CPUState *)penv->next_cpu;
}
@@ -796,17 +963,19 @@
}
}
-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 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 @@
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 @@
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 @@
* 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 @@
#endif
-static int qemu_cpu_exec(CPUState *env)
+static int tcg_cpu_exec(CPUState *env)
{
int ret;
#ifdef CONFIG_PROFILER
@@ -910,18 +1080,29 @@
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 @@
}
}
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 bf4d9bb..e021126 100644
--- a/cpus.h
+++ b/cpus.h
@@ -6,12 +6,11 @@
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 323fafb..3e0eddf 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -4,6 +4,7 @@
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_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 eff26d2..1cc1b61 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -4,6 +4,7 @@
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_NE2000_ISA=y
CONFIG_PIIX_PCI=y
CONFIG_SOUND=y
+CONFIG_HPET=y
diff --git a/exec-all.h b/exec-all.h
index e3a82bc..496c001 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -180,7 +180,6 @@
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 e950df2..d611100 100644
--- a/exec.c
+++ b/exec.c
@@ -649,6 +649,32 @@
#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 @@
#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 @@
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 eb644b2..2d025bf 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -57,6 +57,107 @@
} 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 @@
| 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 @@
| 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 @@
| 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 @@
| 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 17842f4..30b07e9 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -67,6 +67,33 @@
#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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
| 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 @@
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 @@
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;
}
- return packFloat16(aSign, 0x1f, aSig >> 13);
+ /* Infinity */
+ if (!ieee) {
+ float_raise(float_flag_invalid STATUS_VAR);
+ return packFloat16(aSign, 0x1f, 0x3ff);
+ }
+ 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 @@
}
} 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 4a5345c..e57ee1e 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -120,23 +120,37 @@
//#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 @@
/*----------------------------------------------------------------------------
| 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 d6556c9..ed51a8a 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -2194,14 +2194,14 @@
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 @@
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 @@
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 @@
{
switch (event) {
case CHR_EVENT_OPENED:
- vm_stop(EXCP_INTERRUPT);
+ vm_stop(VMSTOP_USER);
gdb_has_xml = 0;
break;
default:
@@ -2628,8 +2628,9 @@
#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 2f8376a..218d1bb 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -372,19 +372,36 @@
return 0;
}
+
+/*
+ * <0 - low prio interrupt,
+ * 0 - no interrupt,
+ * >0 - interrupt number
+ */
+static int apic_irq_pending(APICState *s)
+{
+ int irrv, ppr;
+ irrv = get_highest_priority_int(s->irr);
+ if (irrv < 0) {
+ return 0;
+ }
+ ppr = apic_get_ppr(s);
+ 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)
{
- int irrv, ppr;
- if (!(s->spurious_vec & APIC_SV_ENABLE))
+ if (!(s->spurious_vec & APIC_SV_ENABLE)) {
return;
- irrv = get_highest_priority_int(s->irr);
- if (irrv < 0)
- return;
- ppr = apic_get_ppr(s);
- if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
- 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 @@
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 5f45b5d..2724f7b 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 8fb6811..82a9a21 100644
--- a/hw/hpet.c
+++ b/hw/hpet.c
@@ -74,8 +74,6 @@
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 83fd917..5514402 100644
--- a/hw/i2c.h
+++ b/hw/i2c.h
@@ -59,11 +59,6 @@
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 dd63664..9c91a49 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -465,7 +465,7 @@
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 0cb1afb..6f349a5 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -146,6 +146,18 @@
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 19aa94c..e26abfa 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -32,6 +32,7 @@
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 0000000..b6ceddf
--- /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 0000000..7a83cbe
--- /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 58e3f86..aec8d34 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 @@
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 @@
}
}
- 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 9618c06..0000000
--- 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 c302eb6..c1bdb2e 100644
--- a/hw/max7310.c
+++ b/hw/max7310.c
@@ -23,9 +23,9 @@
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 @@
{
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 2d3f242..930c51c 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -957,7 +957,11 @@
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 5252fc5..afed2ac 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 @@
}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 @@
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 @@
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 @@
break;
default:
printf("Mainstone - mst_fpga_writeb: Bad register offset "
- REG_FMT " \n", addr);
+ "0x" TARGET_FMT_plx " \n", addr);
}
}
@@ -175,66 +164,67 @@
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 4dfdc0b..56bf1d6 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -84,6 +84,7 @@
} __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 @@
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 @@
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 @@
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 @@
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 a048768..d5d2f42 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -65,11 +65,13 @@
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 7b74473..2918454 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 @@
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 @@
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 @@
{
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 @@
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_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_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_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_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 d5bbba9..5e6e216 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1708,6 +1708,21 @@
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 @@
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 0d2753f..113e556 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -453,8 +453,12 @@
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 d966846..9ebbce6 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -1262,10 +1262,12 @@
} 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 @@
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);
+ sysbus_init_mmio(dev, s->region_size, iomemtype);
+ sysbus_init_irq(dev, &s->irq);
- vmstate_register(NULL, base, &vmstate_pxa2xx_i2c, s);
-
- return s;
+ return 0;
}
i2c_bus *pxa2xx_i2c_bus(PXA2xxI2CState *s)
@@ -1527,6 +1544,19 @@
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 @@
{
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 c7fec44..1aa1ea0 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -106,6 +106,18 @@
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 @@
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 9808f85..8a13ec9 100644
--- a/hw/qdev.h
+++ b/hw/qdev.h
@@ -122,6 +122,7 @@
/*** 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 488eedd..b05e654 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -239,7 +239,7 @@
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 1583bd8..acad72a 100644
--- a/hw/sysbus.c
+++ b/hw/sysbus.c
@@ -173,11 +173,43 @@
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 e9eb618..4e8cb16 100644
--- a/hw/sysbus.h
+++ b/hw/sysbus.h
@@ -57,6 +57,8 @@
/* 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 @@
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 c3fbe4e..ed49e94 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 @@
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 0bfab16..b8b6c4f 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 @@
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 e2151a2..c22b8af 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 @@
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 38cc3b3..0ca3507 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -607,6 +607,8 @@
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 ffac5a4..b14fb99 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -78,7 +78,7 @@
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 2097119..ab8dbd6 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 @@
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 @@
}
};
-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 6c9d7c9..292d78f 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 @@
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 6c59053..4656767 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -1309,11 +1309,6 @@
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 2e0813c..5132573 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 e9dd56e..1c900a1 100644
--- a/hw/watchdog.c
+++ b/hw/watchdog.c
@@ -132,7 +132,7 @@
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 fca11a5..c24aeb5 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 @@
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 2ec9e09..e6a7de4 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -78,7 +78,7 @@
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 @@
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 @@
return kvm_state->pit_in_kernel;
}
-
int kvm_init_vcpu(CPUState *env)
{
KVMState *s = kvm_state;
@@ -219,6 +214,7 @@
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 @@
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 @@
.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 @@
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 @@
ptr += size;
}
-
- return 1;
}
#ifdef KVM_CAP_INTERNAL_ERROR_DATA
@@ -895,29 +893,34 @@
DPRINTF("kvm_cpu_exec()\n");
+ if (kvm_arch_process_irqchip_events(env)) {
+ env->exit_request = 0;
+ return EXCP_HLT;
+ }
+
+ cpu_single_env = env;
+
do {
-#ifndef CONFIG_IOTHREAD
- if (env->exit_request) {
- DPRINTF("interrupt exit requested\n");
- ret = 0;
- break;
- }
-#endif
-
- if (kvm_arch_process_irqchip_events(env)) {
- ret = 0;
- break;
- }
-
if (env->kvm_vcpu_dirty) {
kvm_arch_put_registers(env, KVM_PUT_RUNTIME_STATE);
env->kvm_vcpu_dirty = 0;
}
kvm_arch_pre_run(env, run);
+ 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 @@
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 @@
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 @@
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 @@
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 @@
if (ret < 0) {
cpu_dump_state(env, stderr, fprintf, CPU_DUMP_CODE);
- vm_stop(0);
- env->exit_request = 1;
+ vm_stop(VMSTOP_PANIC);
}
- if (env->exit_request) {
- env->exit_request = 0;
- env->exception_index = EXCP_INTERRUPT;
- }
+ ret = EXCP_INTERRUPT;
+out:
+ env->exit_request = 0;
+ cpu_single_env = NULL;
return ret;
}
@@ -1365,3 +1366,13 @@
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 88682f2..30f6ec3 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -33,16 +33,6 @@
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 @@
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 ca57517..59b2c29 100644
--- a/kvm.h
+++ b/kvm.h
@@ -58,9 +58,6 @@
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_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 @@
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 @@
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 1346fd6..b12e27d 100644
--- a/linux-user/arm/nwfpe/fpa11_cpdt.c
+++ b/linux-user/arm/nwfpe/fpa11_cpdt.c
@@ -33,7 +33,7 @@
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 240061d..82ac92f 100644
--- a/linux-user/arm/nwfpe/fpopcode.c
+++ b/linux-user/arm/nwfpe/fpopcode.c
@@ -37,25 +37,25 @@
};
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 b01bd64..ce033e9 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1299,7 +1299,7 @@
__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 @@
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 3612572..af3a1f2 100644
--- a/migration.c
+++ b/migration.c
@@ -378,7 +378,7 @@
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 7fc311d..22ae3bb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1255,7 +1255,7 @@
*/
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 @@
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 cb4b7e0..40dad52 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -288,6 +288,7 @@
/* 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 6d83b0f..a50fd31 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1575,7 +1575,7 @@
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 @@
}
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 87508ba..ce2eb84 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->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 23ae17e..0a83ab9 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -37,6 +37,16 @@
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 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 0d96325..c9febfa 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -157,10 +157,6 @@
/* 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 d46defc..7f63a28 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2623,18 +2623,44 @@
#undef VFP_CONV_FIX
/* Half precision conversions. */
+static float32 do_fcvt_f16_to_f32(uint32_t a, CPUState *env, float_status *s)
+{
+ int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
+ float32 r = float16_to_float32(make_float16(a), ieee, s);
+ if (ieee) {
+ return float32_maybe_silence_nan(r);
+ }
+ return r;
+}
+
+static uint32_t do_fcvt_f32_to_f16(float32 a, CPUState *env, float_status *s)
+{
+ int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
+ 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)
{
- 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);
+ return do_fcvt_f16_to_f32(a, env, &env->vfp.fp_status);
}
uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env)
{
- 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);
+ 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 4d0de00..77f1635 100644
--- a/target-arm/helpers.h
+++ b/target-arm/helpers.h
@@ -129,6 +129,8 @@
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 61890dd..dc09968 100644
--- a/target-arm/neon_helper.c
+++ b/target-arm/neon_helper.c
@@ -1484,7 +1484,6 @@
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 3087a5d..362d1d0 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -5535,17 +5535,17 @@
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 @@
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 af701a4..5f1df8b 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -734,6 +734,7 @@
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 05010bb..0aa0a41 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -301,6 +301,15 @@
#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 @@
}
#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 @@
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 @@
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;
+ }
+
+ /* 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));
+ }
+ }
+ }
+
+ /* 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);
}
-
- DPRINTF("setting tpr\n");
- run->cr8 = cpu_get_apic_tpr(env->apic_state);
-
- return 0;
}
-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 @@
}
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 @@
(env->eflags & IF_MASK)) &&
!(env->interrupt_request & CPU_INTERRUPT_NMI)) {
env->halted = 1;
- env->exception_index = EXCP_HLT;
return 0;
}
@@ -1839,7 +1873,7 @@
#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 @@
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 710eca1..bd4012a 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -256,14 +256,12 @@
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 @@
{
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 dfcd949..7c08b1c 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -154,12 +154,26 @@
#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 @@
/* 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 @@
#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 38823f5..b349812 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -169,14 +169,12 @@
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 @@
{
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 ed2cdfa..b436952 100644
--- a/vl.c
+++ b/vl.c
@@ -1217,8 +1217,8 @@
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 @@
} else {
reset_requested = 1;
}
+ cpu_stop_current();
qemu_notify_event();
}
@@ -1311,6 +1312,18 @@
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 @@
}
-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;