diff options
-rw-r--r-- | Makefile.android | 8 | ||||
-rw-r--r-- | cpu-all.h | 144 | ||||
-rw-r--r-- | cpu-common.h | 20 | ||||
-rw-r--r-- | cpu-defs.h | 2 | ||||
-rw-r--r-- | cutils.c | 18 | ||||
-rw-r--r-- | exec-all.h | 2 | ||||
-rw-r--r-- | exec.c | 1 | ||||
-rw-r--r-- | gen-icount.h | 2 | ||||
-rw-r--r-- | poison.h | 50 | ||||
-rw-r--r-- | qemu-common.h | 22 | ||||
-rw-r--r-- | qemu-timer.c | 1238 | ||||
-rw-r--r-- | qemu-timer.h | 203 | ||||
-rw-r--r-- | softmmu_template.h | 2 | ||||
-rw-r--r-- | sysemu.h | 1 | ||||
-rw-r--r-- | target-arm/cpu.h | 5 | ||||
-rw-r--r-- | tcg/tcg.c | 3 | ||||
-rw-r--r-- | translate-all.c | 1 | ||||
-rw-r--r-- | vl-android.c | 1138 | ||||
-rw-r--r-- | vl.c | 1116 |
19 files changed, 1576 insertions, 2400 deletions
diff --git a/Makefile.android b/Makefile.android index 8692115..a7006b8 100644 --- a/Makefile.android +++ b/Makefile.android @@ -130,7 +130,7 @@ endif TCG_CFLAGS := -I$(LOCAL_PATH)/tcg -I$(LOCAL_PATH)/tcg/$(TCG_TARGET) -LOCAL_CFLAGS += $(TCG_CFLAGS) \ +LOCAL_CFLAGS += $(TCG_CFLAGS) -DNEED_CPU_H \ -I$(LOCAL_PATH)/target-arm \ -I$(LOCAL_PATH)/fpu \ @@ -151,7 +151,7 @@ LOCAL_MODULE := emulator-hw HW_CFLAGS := -I$(LOCAL_PATH)/hw -LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) +LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) -DNEED_CPU_H LOCAL_CFLAGS += -I$(LOCAL_PATH)/target-arm -I$(LOCAL_PATH)/fpu $(HW_CFLAGS) LOCAL_CFLAGS += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR) @@ -248,7 +248,7 @@ LOCAL_MODULE := emulator-memcheck MCHK_CFLAGS := -I$(LOCAL_PATH)/memcheck -I$(LOCAL_PATH)/elff -LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) +LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS) -DNEED_CPU_H LOCAL_CFLAGS += -I$(LOCAL_PATH)/target-arm -I$(LOCAL_PATH)/fpu $(MCHK_CFLAGS) LOCAL_CFLAGS += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR) @@ -283,6 +283,7 @@ LOCAL_CFLAGS += -I$(LOCAL_PATH) \ -I$(LOCAL_PATH)/fpu \ $(TCG_CFLAGS) \ $(HW_CFLAGS) \ + -DNEED_CPU_H \ ifeq ($(HOST_ARCH),ppc) LOCAL_CFLAGS += -D__powerpc__ @@ -655,6 +656,7 @@ CORE_MISC_SOURCES = vl-android.c \ bt-host.c \ bt-vhci.c \ module.c \ + qemu-timer.c \ android/boot-properties.c \ android/display.c \ android/hw-kmsg.c \ @@ -760,8 +760,6 @@ void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); extern CPUState *first_cpu; extern CPUState *cpu_single_env; -extern int64_t qemu_icount; -extern int use_icount; #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ #define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */ @@ -917,148 +915,6 @@ void qemu_unregister_coalesced_mmio(target_phys_addr_t addr, ram_addr_t size); void qemu_flush_coalesced_mmio_buffer(void); -/*******************************************/ -/* host CPU ticks (if available) */ - -#if defined(_ARCH_PPC) - -static inline int64_t cpu_get_real_ticks(void) -{ - int64_t retval; -#ifdef _ARCH_PPC64 - /* This reads timebase in one 64bit go and includes Cell workaround from: - http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027052.html - */ - __asm__ __volatile__ ( - "mftb %0\n\t" - "cmpwi %0,0\n\t" - "beq- $-8" - : "=r" (retval)); -#else - /* http://ozlabs.org/pipermail/linuxppc-dev/1999-October/003889.html */ - unsigned long junk; - __asm__ __volatile__ ( - "mftbu %1\n\t" - "mftb %L0\n\t" - "mftbu %0\n\t" - "cmpw %0,%1\n\t" - "bne $-16" - : "=r" (retval), "=r" (junk)); -#endif - return retval; -} - -#elif defined(__i386__) - -static inline int64_t cpu_get_real_ticks(void) -{ - int64_t val; - asm volatile ("rdtsc" : "=A" (val)); - return val; -} - -#elif defined(__x86_64__) - -static inline int64_t cpu_get_real_ticks(void) -{ - uint32_t low,high; - int64_t val; - asm volatile("rdtsc" : "=a" (low), "=d" (high)); - val = high; - val <<= 32; - val |= low; - return val; -} - -#elif defined(__hppa__) - -static inline int64_t cpu_get_real_ticks(void) -{ - int val; - asm volatile ("mfctl %%cr16, %0" : "=r"(val)); - return val; -} - -#elif defined(__ia64) - -static inline int64_t cpu_get_real_ticks(void) -{ - int64_t val; - asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); - return val; -} - -#elif defined(__s390__) - -static inline int64_t cpu_get_real_ticks(void) -{ - int64_t val; - asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc"); - return val; -} - -#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) - -static inline int64_t cpu_get_real_ticks (void) -{ -#if defined(_LP64) - uint64_t rval; - asm volatile("rd %%tick,%0" : "=r"(rval)); - return rval; -#else - union { - uint64_t i64; - struct { - uint32_t high; - uint32_t low; - } i32; - } rval; - asm volatile("rd %%tick,%1; srlx %1,32,%0" - : "=r"(rval.i32.high), "=r"(rval.i32.low)); - return rval.i64; -#endif -} - -#elif defined(__mips__) && \ - ((defined(__mips_isa_rev) && __mips_isa_rev >= 2) || defined(__linux__)) -/* - * binutils wants to use rdhwr only on mips32r2 - * but as linux kernel emulate it, it's fine - * to use it. - * - */ -#define MIPS_RDHWR(rd, value) { \ - __asm__ __volatile__ ( \ - ".set push\n\t" \ - ".set mips32r2\n\t" \ - "rdhwr %0, "rd"\n\t" \ - ".set pop" \ - : "=r" (value)); \ -} - -static inline int64_t cpu_get_real_ticks(void) -{ -/* On kernels >= 2.6.25 rdhwr <reg>, $2 and $3 are emulated */ - uint32_t count; - static uint32_t cyc_per_count = 0; - - if (!cyc_per_count) - MIPS_RDHWR("$3", cyc_per_count); - - MIPS_RDHWR("$2", count); - return (int64_t)(count * cyc_per_count); -} - -#else -/* The host CPU doesn't have an easily accessible cycle counter. - Just return a monotonically increasing value. This will be - totally wrong, but hopefully better than nothing. */ -static inline int64_t cpu_get_real_ticks (void) -{ - static int64_t ticks = 0; - return ticks++; -} -#endif /* profiling */ #ifdef CONFIG_PROFILER diff --git a/cpu-common.h b/cpu-common.h index 8f89325..d48ba5b 100644 --- a/cpu-common.h +++ b/cpu-common.h @@ -3,19 +3,25 @@ /* CPU interfaces that are target indpendent. */ -#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) +#if defined(__arm__) || defined(__sparc__) || defined(__mips__) || defined(__hppa__) || defined(__ia64__) #define WORDS_ALIGNED #endif +#ifdef TARGET_PHYS_ADDR_BITS +#include "targphys.h" +#endif + +#ifndef NEED_CPU_H +#include "poison.h" +#endif + #include "bswap.h" +#include "qemu-queue.h" + +#if !defined(CONFIG_USER_ONLY) /* address in the RAM (different from a physical address) */ -#ifdef CONFIG_KQEMU -/* FIXME: This is wrong. */ -typedef uint32_t ram_addr_t; -#else typedef unsigned long ram_addr_t; -#endif /* memory API */ @@ -92,4 +98,6 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr, #define IO_MEM_SUBPAGE (2) #define IO_MEM_SUBWIDTH (4) +#endif + #endif /* !CPU_COMMON_H */ @@ -19,11 +19,9 @@ #ifndef CPU_DEFS_H #define CPU_DEFS_H -#if 0 /* ANDROID */ #ifndef NEED_CPU_H #error cpu.h included from common code #endif -#endif /* ANDROID */ #include "config.h" #include <setjmp.h> @@ -233,3 +233,21 @@ void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count) count -= copy; } } + +#ifndef _WIN32 +/* Sets a specific flag */ +int fcntl_setfl(int fd, int flag) +{ + int flags; + + flags = fcntl(fd, F_GETFL); + if (flags == -1) + return -errno; + + if (fcntl(fd, F_SETFL, flags | flag) == -1) + return -errno; + + return 0; +} +#endif + @@ -406,6 +406,7 @@ static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) return qemu_ram_addr_from_host(p); } +#if 0 /* Deterministic execution requires that IO only be performed on the last instruction of a TB so that interrupts take effect immediately. */ static inline int can_do_io(CPUState *env) @@ -420,6 +421,7 @@ static inline int can_do_io(CPUState *env) return env->can_do_io != 0; } #endif +#endif /* 0 */ #ifdef CONFIG_KQEMU #define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG)) @@ -39,6 +39,7 @@ #include "hw/hw.h" #include "osdep.h" #include "kvm.h" +#include "qemu-timer.h" #if defined(CONFIG_USER_ONLY) #include <qemu.h> #endif diff --git a/gen-icount.h b/gen-icount.h index 3268f72..8879da6 100644 --- a/gen-icount.h +++ b/gen-icount.h @@ -1,3 +1,5 @@ +#include "qemu-timer.h" + /* Helpers for instruction counting code generation. */ static TCGArg *icount_arg; diff --git a/poison.h b/poison.h new file mode 100644 index 0000000..d7db7f4 --- /dev/null +++ b/poison.h @@ -0,0 +1,50 @@ +/* Poison identifiers that should not be used when building + target independent device code. */ + +#ifndef HW_POISON_H +#define HW_POISON_H +#ifdef __GNUC__ + +#pragma GCC poison TARGET_I386 +#pragma GCC poison TARGET_X86_64 +#pragma GCC poison TARGET_ALPHA +#pragma GCC poison TARGET_ARM +#pragma GCC poison TARGET_CRIS +#pragma GCC poison TARGET_M68K +#pragma GCC poison TARGET_MIPS +#pragma GCC poison TARGET_MIPS64 +#pragma GCC poison TARGET_PPC +#pragma GCC poison TARGET_PPCEMB +#pragma GCC poison TARGET_PPC64 +#pragma GCC poison TARGET_ABI32 +#pragma GCC poison TARGET_SH4 +#pragma GCC poison TARGET_SPARC +#pragma GCC poison TARGET_SPARC64 + +#pragma GCC poison TARGET_WORDS_BIGENDIAN +#pragma GCC poison BSWAP_NEEDED + +#pragma GCC poison TARGET_LONG_BITS +#pragma GCC poison TARGET_FMT_lx +#pragma GCC poison TARGET_FMT_ld + +#pragma GCC poison TARGET_PAGE_SIZE +#pragma GCC poison TARGET_PAGE_MASK +#pragma GCC poison TARGET_PAGE_BITS +#pragma GCC poison TARGET_PAGE_ALIGN + +#pragma GCC poison CPUState +#pragma GCC poison env + +#pragma GCC poison CPU_INTERRUPT_HARD +#pragma GCC poison CPU_INTERRUPT_EXITTB +#pragma GCC poison CPU_INTERRUPT_TIMER +#pragma GCC poison CPU_INTERRUPT_FIQ +#pragma GCC poison CPU_INTERRUPT_HALT +#pragma GCC poison CPU_INTERRUPT_SMI +#pragma GCC poison CPU_INTERRUPT_DEBUG +#pragma GCC poison CPU_INTERRUPT_VIRQ +#pragma GCC poison CPU_INTERRUPT_NMI + +#endif +#endif diff --git a/qemu-common.h b/qemu-common.h index 664e83f..7b511ff 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -2,7 +2,21 @@ #ifndef QEMU_COMMON_H #define QEMU_COMMON_H +#include "config-host.h" + #define QEMU_NORETURN __attribute__ ((__noreturn__)) +#ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT +#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +#define QEMU_WARN_UNUSED_RESULT +#endif + +#define QEMU_BUILD_BUG_ON(x) typedef char __build_bug_on__##__LINE__[(x)?-1:1]; + +typedef struct QEMUTimer QEMUTimer; +typedef struct QEMUFile QEMUFile; +typedef struct QEMUBH QEMUBH; +typedef struct DeviceState DeviceState; /* Hack around the mess dyngen-exec.h causes: We need QEMU_NORETURN in files that cannot include the following headers without conflicts. This condition has @@ -13,6 +27,7 @@ #include <stdlib.h> #include <stdio.h> #include <stdarg.h> +#include <stdbool.h> #include <string.h> #include <strings.h> #include <inttypes.h> @@ -24,7 +39,6 @@ #include <fcntl.h> #include <sys/stat.h> #include <assert.h> -#include "config-host.h" #ifndef O_LARGEFILE #define O_LARGEFILE 0 @@ -83,8 +97,6 @@ static inline char *realpath(const char *path, char *resolved_path) #endif /* !defined(NEED_CPU_H) */ /* bottom halves */ -typedef struct QEMUBH QEMUBH; - typedef void QEMUBHFunc(void *opaque); QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque); @@ -114,6 +126,7 @@ int qemu_strnlen(const char *s, int max_len); time_t mktimegm(struct tm *tm); int qemu_fls(int i); int qemu_fdatasync(int fd); +int fcntl_setfl(int fd, int flag); #define qemu_isalnum(c) isalnum((unsigned char)(c)) #define qemu_isalpha(c) isalpha((unsigned char)(c)) @@ -173,11 +186,9 @@ typedef struct TextConsole TextConsole; typedef TextConsole QEMUConsole; typedef struct CharDriverState CharDriverState; typedef struct VLANState VLANState; -typedef struct QEMUFile QEMUFile; typedef struct i2c_bus i2c_bus; typedef struct i2c_slave i2c_slave; typedef struct SMBusDevice SMBusDevice; -typedef struct QEMUTimer QEMUTimer; typedef struct PCIBus PCIBus; typedef struct PCIDevice PCIDevice; typedef struct SerialState SerialState; @@ -186,7 +197,6 @@ typedef struct PCMCIACardState PCMCIACardState; typedef struct MouseTransformInfo MouseTransformInfo; typedef struct uWireSlave uWireSlave; typedef struct I2SCodec I2SCodec; -typedef struct DeviceState DeviceState; typedef struct SSIBus SSIBus; /* CPU save/load. */ diff --git a/qemu-timer.c b/qemu-timer.c new file mode 100644 index 0000000..6ad2858 --- /dev/null +++ b/qemu-timer.c @@ -0,0 +1,1238 @@ +/* + * QEMU System Emulator + * + * Copyright (c) 2003-2008 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysemu.h" +#include "net.h" +#include "monitor.h" +#include "console.h" + +#include "hw/hw.h" + +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <errno.h> +#include <sys/time.h> +#include <signal.h> +#ifdef __FreeBSD__ +#include <sys/param.h> +#endif + +#ifdef __linux__ +#include <sys/ioctl.h> +#include <linux/rtc.h> +/* For the benefit of older linux systems which don't supply it, + we use a local copy of hpet.h. */ +/* #include <linux/hpet.h> */ +#include "hpet.h" +#endif + +#ifdef _WIN32 +#include <windows.h> +#include <mmsystem.h> +#endif + +#include "qemu-timer.h" + +/* Conversion factor from emulated instructions to virtual clock ticks. */ +int icount_time_shift; +/* Arbitrarily pick 1MIPS as the minimum allowable speed. */ +#define MAX_ICOUNT_SHIFT 10 +/* Compensate for varying guest execution speed. */ +int64_t qemu_icount_bias; +static QEMUTimer *icount_rt_timer; +static QEMUTimer *icount_vm_timer; + + +/***********************************************************/ +/* real time host monotonic timer */ + + +static int64_t get_clock_realtime(void) +{ + struct timeval tv; + + gettimeofday(&tv, NULL); + return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); +} + +#ifdef WIN32 + +static int64_t clock_freq; + +static void init_get_clock(void) +{ + LARGE_INTEGER freq; + int ret; + ret = QueryPerformanceFrequency(&freq); + if (ret == 0) { + fprintf(stderr, "Could not calibrate ticks\n"); + exit(1); + } + clock_freq = freq.QuadPart; +} + +static int64_t get_clock(void) +{ + LARGE_INTEGER ti; + QueryPerformanceCounter(&ti); + return muldiv64(ti.QuadPart, get_ticks_per_sec(), clock_freq); +} + +#else + +static int use_rt_clock; + +static void init_get_clock(void) +{ + use_rt_clock = 0; +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \ + || defined(__DragonFly__) || defined(__FreeBSD_kernel__) + { + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { + use_rt_clock = 1; + } + } +#endif +} + +static int64_t get_clock(void) +{ +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \ + || defined(__DragonFly__) || defined(__FreeBSD_kernel__) + if (use_rt_clock) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000000000LL + ts.tv_nsec; + } else +#endif + { + /* XXX: using gettimeofday leads to problems if the date + changes, so it should be avoided. */ + return get_clock_realtime(); + } +} +#endif + +/***********************************************************/ +/* guest cycle counter */ + +typedef struct TimersState { + int64_t cpu_ticks_prev; + int64_t cpu_ticks_offset; + int64_t cpu_clock_offset; + int32_t cpu_ticks_enabled; + int64_t dummy; +} TimersState; + +static void timer_save(QEMUFile *f, void *opaque) +{ + TimersState *s = opaque; + + if (s->cpu_ticks_enabled) { + hw_error("cannot save state if virtual timers are running"); + } + qemu_put_be64(f, s->cpu_ticks_prev); + qemu_put_be64(f, s->cpu_ticks_offset); + qemu_put_be64(f, s->cpu_clock_offset); + } + +static int timer_load(QEMUFile *f, void *opaque, int version_id) +{ + TimersState *s = opaque; + + if (version_id != 1 && version_id != 2) + return -EINVAL; + if (s->cpu_ticks_enabled) { + return -EINVAL; + } + s->cpu_ticks_prev = qemu_get_sbe64(f); + s->cpu_ticks_offset = qemu_get_sbe64(f); + if (version_id == 2) { + s->cpu_clock_offset = qemu_get_sbe64(f); + } + return 0; +} + + +TimersState timers_state; + +/* return the host CPU cycle counter and handle stop/restart */ +int64_t cpu_get_ticks(void) +{ + if (use_icount) { + return cpu_get_icount(); + } + if (!timers_state.cpu_ticks_enabled) { + return timers_state.cpu_ticks_offset; + } else { + int64_t ticks; + ticks = cpu_get_real_ticks(); + if (timers_state.cpu_ticks_prev > ticks) { + /* Note: non increasing ticks may happen if the host uses + software suspend */ + timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks; + } + timers_state.cpu_ticks_prev = ticks; + return ticks + timers_state.cpu_ticks_offset; + } +} + +/* return the host CPU monotonic timer and handle stop/restart */ +static int64_t cpu_get_clock(void) +{ + int64_t ti; + if (!timers_state.cpu_ticks_enabled) { + return timers_state.cpu_clock_offset; + } else { + ti = get_clock(); + return ti + timers_state.cpu_clock_offset; + } +} + +#ifndef CONFIG_IOTHREAD +static int64_t qemu_icount_delta(void) +{ + if (!use_icount) { + return 5000 * (int64_t) 1000000; + } else if (use_icount == 1) { + /* When not using an adaptive execution frequency + we tend to get badly out of sync with real time, + so just delay for a reasonable amount of time. */ + return 0; + } else { + return cpu_get_icount() - cpu_get_clock(); + } +} +#endif + +/* enable cpu_get_ticks() */ +void cpu_enable_ticks(void) +{ + if (!timers_state.cpu_ticks_enabled) { + timers_state.cpu_ticks_offset -= cpu_get_real_ticks(); + timers_state.cpu_clock_offset -= get_clock(); + timers_state.cpu_ticks_enabled = 1; + } +} + +/* disable cpu_get_ticks() : the clock is stopped. You must not call + cpu_get_ticks() after that. */ +void cpu_disable_ticks(void) +{ + if (timers_state.cpu_ticks_enabled) { + timers_state.cpu_ticks_offset = cpu_get_ticks(); + timers_state.cpu_clock_offset = cpu_get_clock(); + timers_state.cpu_ticks_enabled = 0; + } +} + +/***********************************************************/ +/* timers */ + +#define QEMU_CLOCK_REALTIME 0 +#define QEMU_CLOCK_VIRTUAL 1 +#define QEMU_CLOCK_HOST 2 + +struct QEMUClock { + int type; + int enabled; + /* XXX: add frequency */ +}; + +struct QEMUTimer { + QEMUClock *clock; + int64_t expire_time; + QEMUTimerCB *cb; + void *opaque; + struct QEMUTimer *next; +}; + +struct qemu_alarm_timer { + char const *name; + int (*start)(struct qemu_alarm_timer *t); + void (*stop)(struct qemu_alarm_timer *t); + void (*rearm)(struct qemu_alarm_timer *t); + void *priv; + + char expired; + char pending; +}; + +static struct qemu_alarm_timer *alarm_timer; + +int qemu_alarm_pending(void) +{ + return alarm_timer->pending; +} + +static inline int alarm_has_dynticks(struct qemu_alarm_timer *t) +{ + return !!t->rearm; +} + +static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) +{ + if (!alarm_has_dynticks(t)) + return; + + t->rearm(t); +} + +/* TODO: MIN_TIMER_REARM_US should be optimized */ +#define MIN_TIMER_REARM_US 250 + +#ifdef _WIN32 + +struct qemu_alarm_win32 { + MMRESULT timerId; + unsigned int period; +} alarm_win32_data = {0, 0}; + +static int win32_start_timer(struct qemu_alarm_timer *t); +static void win32_stop_timer(struct qemu_alarm_timer *t); +static void win32_rearm_timer(struct qemu_alarm_timer *t); + +#else + +static int unix_start_timer(struct qemu_alarm_timer *t); +static void unix_stop_timer(struct qemu_alarm_timer *t); + +#ifdef __linux__ + +static int dynticks_start_timer(struct qemu_alarm_timer *t); +static void dynticks_stop_timer(struct qemu_alarm_timer *t); +static void dynticks_rearm_timer(struct qemu_alarm_timer *t); + +static int hpet_start_timer(struct qemu_alarm_timer *t); +static void hpet_stop_timer(struct qemu_alarm_timer *t); + +static int rtc_start_timer(struct qemu_alarm_timer *t); +static void rtc_stop_timer(struct qemu_alarm_timer *t); + +#endif /* __linux__ */ + +#endif /* _WIN32 */ + +/* Correlation between real and virtual time is always going to be + fairly approximate, so ignore small variation. + When the guest is idle real and virtual time will be aligned in + the IO wait loop. */ +#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10) + +static void icount_adjust(void) +{ + int64_t cur_time; + int64_t cur_icount; + int64_t delta; + static int64_t last_delta; + /* If the VM is not running, then do nothing. */ + if (!vm_running) + return; + + cur_time = cpu_get_clock(); + cur_icount = qemu_get_clock(vm_clock); + delta = cur_icount - cur_time; + /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ + if (delta > 0 + && last_delta + ICOUNT_WOBBLE < delta * 2 + && icount_time_shift > 0) { + /* The guest is getting too far ahead. Slow time down. */ + icount_time_shift--; + } + if (delta < 0 + && last_delta - ICOUNT_WOBBLE > delta * 2 + && icount_time_shift < MAX_ICOUNT_SHIFT) { + /* The guest is getting too far behind. Speed time up. */ + icount_time_shift++; + } + last_delta = delta; + qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift); +} + +static void icount_adjust_rt(void * opaque) +{ + qemu_mod_timer(icount_rt_timer, + qemu_get_clock(rt_clock) + 1000); + icount_adjust(); +} + +static void icount_adjust_vm(void * opaque) +{ + qemu_mod_timer(icount_vm_timer, + qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10); + icount_adjust(); +} + +int64_t qemu_icount_round(int64_t count) +{ + return (count + (1 << icount_time_shift) - 1) >> icount_time_shift; +} + +static struct qemu_alarm_timer alarm_timers[] = { +#ifndef _WIN32 +#ifdef __linux__ + {"dynticks", dynticks_start_timer, + dynticks_stop_timer, dynticks_rearm_timer, NULL}, + /* HPET - if available - is preferred */ + {"hpet", hpet_start_timer, hpet_stop_timer, NULL, NULL}, + /* ...otherwise try RTC */ + {"rtc", rtc_start_timer, rtc_stop_timer, NULL, NULL}, +#endif + {"unix", unix_start_timer, unix_stop_timer, NULL, NULL}, +#else + {"dynticks", win32_start_timer, + win32_stop_timer, win32_rearm_timer, &alarm_win32_data}, + {"win32", win32_start_timer, + win32_stop_timer, NULL, &alarm_win32_data}, +#endif + {NULL, } +}; + +static void show_available_alarms(void) +{ + int i; + + printf("Available alarm timers, in order of precedence:\n"); + for (i = 0; alarm_timers[i].name; i++) + printf("%s\n", alarm_timers[i].name); +} + +void configure_alarms(char const *opt) +{ + int i; + int cur = 0; + int count = ARRAY_SIZE(alarm_timers) - 1; + char *arg; + char *name; + struct qemu_alarm_timer tmp; + + if (!strcmp(opt, "?")) { + show_available_alarms(); + exit(0); + } + + arg = qemu_strdup(opt); + + /* Reorder the array */ + name = strtok(arg, ","); + while (name) { + for (i = 0; i < count && alarm_timers[i].name; i++) { + if (!strcmp(alarm_timers[i].name, name)) + break; + } + + if (i == count) { + fprintf(stderr, "Unknown clock %s\n", name); + goto next; + } + + if (i < cur) + /* Ignore */ + goto next; + + /* Swap */ + tmp = alarm_timers[i]; + alarm_timers[i] = alarm_timers[cur]; + alarm_timers[cur] = tmp; + + cur++; +next: + name = strtok(NULL, ","); + } + + qemu_free(arg); + + if (cur) { + /* Disable remaining timers */ + for (i = cur; i < count; i++) + alarm_timers[i].name = NULL; + } else { + show_available_alarms(); + exit(1); + } +} + +#define QEMU_NUM_CLOCKS 3 + +QEMUClock *rt_clock; +QEMUClock *vm_clock; +QEMUClock *host_clock; + +static QEMUTimer *active_timers[QEMU_NUM_CLOCKS]; + +static QEMUClock *qemu_new_clock(int type) +{ + QEMUClock *clock; + clock = qemu_mallocz(sizeof(QEMUClock)); + clock->type = type; + clock->enabled = 1; + return clock; +} + +void qemu_clock_enable(QEMUClock *clock, int enabled) +{ + clock->enabled = enabled; +} + +QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque) +{ + QEMUTimer *ts; + + ts = qemu_mallocz(sizeof(QEMUTimer)); + ts->clock = clock; + ts->cb = cb; + ts->opaque = opaque; + return ts; +} + +void qemu_free_timer(QEMUTimer *ts) +{ + qemu_free(ts); +} + +/* stop a timer, but do not dealloc it */ +void qemu_del_timer(QEMUTimer *ts) +{ + QEMUTimer **pt, *t; + + /* NOTE: this code must be signal safe because + qemu_timer_expired() can be called from a signal. */ + pt = &active_timers[ts->clock->type]; + for(;;) { + t = *pt; + if (!t) + break; + if (t == ts) { + *pt = t->next; + break; + } + pt = &t->next; + } +} + +/* modify the current timer so that it will be fired when current_time + >= expire_time. The corresponding callback will be called. */ +void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) +{ + QEMUTimer **pt, *t; + + qemu_del_timer(ts); + + /* add the timer in the sorted list */ + /* NOTE: this code must be signal safe because + qemu_timer_expired() can be called from a signal. */ + pt = &active_timers[ts->clock->type]; + for(;;) { + t = *pt; + if (!t) + break; + if (t->expire_time > expire_time) + break; + pt = &t->next; + } + ts->expire_time = expire_time; + ts->next = *pt; + *pt = ts; + + /* Rearm if necessary */ + if (pt == &active_timers[ts->clock->type]) { + if (!alarm_timer->pending) { + qemu_rearm_alarm_timer(alarm_timer); + } + /* Interrupt execution to force deadline recalculation. */ + if (use_icount) + qemu_notify_event(); + } +} + +int qemu_timer_pending(QEMUTimer *ts) +{ + QEMUTimer *t; + for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) { + if (t == ts) + return 1; + } + return 0; +} + +int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) +{ + if (!timer_head) + return 0; + return (timer_head->expire_time <= current_time); +} + +static void qemu_run_timers(QEMUClock *clock) +{ + QEMUTimer **ptimer_head, *ts; + int64_t current_time; + + if (!clock->enabled) + return; + + current_time = qemu_get_clock (clock); + ptimer_head = &active_timers[clock->type]; + for(;;) { + ts = *ptimer_head; + if (!ts || ts->expire_time > current_time) + break; + /* remove timer from the list before calling the callback */ + *ptimer_head = ts->next; + ts->next = NULL; + + /* run the callback (the timer list can be modified) */ + ts->cb(ts->opaque); + } +} + +int64_t qemu_get_clock(QEMUClock *clock) +{ + switch(clock->type) { + case QEMU_CLOCK_REALTIME: + return get_clock() / 1000000; + default: + case QEMU_CLOCK_VIRTUAL: + if (use_icount) { + return cpu_get_icount(); + } else { + return cpu_get_clock(); + } + case QEMU_CLOCK_HOST: + return get_clock_realtime(); + } +} + +int64_t qemu_get_clock_ns(QEMUClock *clock) +{ + switch(clock->type) { + case QEMU_CLOCK_REALTIME: + return get_clock(); + default: + case QEMU_CLOCK_VIRTUAL: + if (use_icount) { + return cpu_get_icount(); + } else { + return cpu_get_clock(); + } + case QEMU_CLOCK_HOST: + return get_clock_realtime(); + } +} + +void init_clocks(void) +{ + init_get_clock(); + rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME); + vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL); + host_clock = qemu_new_clock(QEMU_CLOCK_HOST); + + rtc_clock = host_clock; +} + +/* save a timer */ +void qemu_put_timer(QEMUFile *f, QEMUTimer *ts) +{ + uint64_t expire_time; + + if (qemu_timer_pending(ts)) { + expire_time = ts->expire_time; + } else { + expire_time = -1; + } + qemu_put_be64(f, expire_time); +} + +void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) +{ + uint64_t expire_time; + + expire_time = qemu_get_be64(f); + if (expire_time != -1) { + qemu_mod_timer(ts, expire_time); + } else { + qemu_del_timer(ts); + } +} + +#if 0 +static const VMStateDescription vmstate_timers = { + .name = "timer", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .fields = (VMStateField []) { + VMSTATE_INT64(cpu_ticks_offset, TimersState), + VMSTATE_INT64(dummy, TimersState), + VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2), + VMSTATE_END_OF_LIST() + } +}; +#endif + +void configure_icount(const char *option) +{ + register_savevm("timer", 0, 2, timer_save, timer_load, NULL); + + if (!option) + return; + + if (strcmp(option, "auto") != 0) { + icount_time_shift = strtol(option, NULL, 0); + use_icount = 1; + return; + } + + use_icount = 2; + + /* 125MIPS seems a reasonable initial guess at the guest speed. + It will be corrected fairly quickly anyway. */ + icount_time_shift = 3; + + /* Have both realtime and virtual time triggers for speed adjustment. + The realtime trigger catches emulated time passing too slowly, + the virtual time trigger catches emulated time passing too fast. + Realtime triggers occur even when idle, so use them less frequently + than VM triggers. */ + icount_rt_timer = qemu_new_timer(rt_clock, icount_adjust_rt, NULL); + qemu_mod_timer(icount_rt_timer, + qemu_get_clock(rt_clock) + 1000); + icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL); + qemu_mod_timer(icount_vm_timer, + qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10); +} + +void qemu_run_all_timers(void) +{ + alarm_timer->pending = 0; + + /* rearm timer, if not periodic */ + if (alarm_timer->expired) { + alarm_timer->expired = 0; + qemu_rearm_alarm_timer(alarm_timer); + } + + /* vm time timers */ + if (vm_running) { + qemu_run_timers(vm_clock); + } + + qemu_run_timers(rt_clock); + qemu_run_timers(host_clock); +} + +#ifdef _WIN32 +static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, + DWORD_PTR dwUser, DWORD_PTR dw1, + DWORD_PTR dw2) +#else +static void host_alarm_handler(int host_signum) +#endif +{ + struct qemu_alarm_timer *t = alarm_timer; + if (!t) + return; + +#if 0 +#define DISP_FREQ 1000 + { + static int64_t delta_min = INT64_MAX; + static int64_t delta_max, delta_cum, last_clock, delta, ti; + static int count; + ti = qemu_get_clock(vm_clock); + if (last_clock != 0) { + delta = ti - last_clock; + if (delta < delta_min) + delta_min = delta; + if (delta > delta_max) + delta_max = delta; + delta_cum += delta; + if (++count == DISP_FREQ) { + printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n", + muldiv64(delta_min, 1000000, get_ticks_per_sec()), + muldiv64(delta_max, 1000000, get_ticks_per_sec()), + muldiv64(delta_cum, 1000000 / DISP_FREQ, get_ticks_per_sec()), + (double)get_ticks_per_sec() / ((double)delta_cum / DISP_FREQ)); + count = 0; + delta_min = INT64_MAX; + delta_max = 0; + delta_cum = 0; + } + } + last_clock = ti; + } +#endif + if (alarm_has_dynticks(t) || + (!use_icount && + qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL], + qemu_get_clock(vm_clock))) || + qemu_timer_expired(active_timers[QEMU_CLOCK_REALTIME], + qemu_get_clock(rt_clock)) || + qemu_timer_expired(active_timers[QEMU_CLOCK_HOST], + qemu_get_clock(host_clock))) { + + t->expired = alarm_has_dynticks(t); + t->pending = 1; + qemu_notify_event(); + } +} + +int64_t qemu_next_deadline(void) +{ + /* To avoid problems with overflow limit this to 2^32. */ + int64_t delta = INT32_MAX; + + if (active_timers[QEMU_CLOCK_VIRTUAL]) { + delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time - + qemu_get_clock(vm_clock); + } + if (active_timers[QEMU_CLOCK_HOST]) { + int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time - + qemu_get_clock(host_clock); + if (hdelta < delta) + delta = hdelta; + } + + if (delta < 0) + delta = 0; + + return delta; +} + +#ifndef _WIN32 + +#if defined(__linux__) + +#define RTC_FREQ 1024 + +static uint64_t qemu_next_deadline_dyntick(void) +{ + int64_t delta; + int64_t rtdelta; + + if (use_icount) + delta = INT32_MAX; + else + delta = (qemu_next_deadline() + 999) / 1000; + + if (active_timers[QEMU_CLOCK_REALTIME]) { + rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time - + qemu_get_clock(rt_clock))*1000; + if (rtdelta < delta) + delta = rtdelta; + } + + if (delta < MIN_TIMER_REARM_US) + delta = MIN_TIMER_REARM_US; + + return delta; +} + +static void enable_sigio_timer(int fd) +{ + struct sigaction act; + + /* timer signal */ + sigfillset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = host_alarm_handler; + + sigaction(SIGIO, &act, NULL); + fcntl_setfl(fd, O_ASYNC); + fcntl(fd, F_SETOWN, getpid()); +} + +static int hpet_start_timer(struct qemu_alarm_timer *t) +{ + struct hpet_info info; + int r, fd; + + fd = open("/dev/hpet", O_RDONLY); + if (fd < 0) + return -1; + + /* Set frequency */ + r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ); + if (r < 0) { + fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n" + "error, but for better emulation accuracy type:\n" + "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n"); + goto fail; + } + + /* Check capabilities */ + r = ioctl(fd, HPET_INFO, &info); + if (r < 0) + goto fail; + + /* Enable periodic mode */ + r = ioctl(fd, HPET_EPI, 0); + if (info.hi_flags && (r < 0)) + goto fail; + + /* Enable interrupt */ + r = ioctl(fd, HPET_IE_ON, 0); + if (r < 0) + goto fail; + + enable_sigio_timer(fd); + t->priv = (void *)(long)fd; + + return 0; +fail: + close(fd); + return -1; +} + +static void hpet_stop_timer(struct qemu_alarm_timer *t) +{ + int fd = (long)t->priv; + + close(fd); +} + +static int rtc_start_timer(struct qemu_alarm_timer *t) +{ + int rtc_fd; + unsigned long current_rtc_freq = 0; + + TFR(rtc_fd = open("/dev/rtc", O_RDONLY)); + if (rtc_fd < 0) + return -1; + ioctl(rtc_fd, RTC_IRQP_READ, ¤t_rtc_freq); + if (current_rtc_freq != RTC_FREQ && + ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { + fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n" + "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n" + "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n"); + goto fail; + } + if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) { + fail: + close(rtc_fd); + return -1; + } + + enable_sigio_timer(rtc_fd); + + t->priv = (void *)(long)rtc_fd; + + return 0; +} + +static void rtc_stop_timer(struct qemu_alarm_timer *t) +{ + int rtc_fd = (long)t->priv; + + close(rtc_fd); +} + +static int dynticks_start_timer(struct qemu_alarm_timer *t) +{ + struct sigevent ev; + timer_t host_timer; + struct sigaction act; + + sigfillset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = host_alarm_handler; + + sigaction(SIGALRM, &act, NULL); + + /* + * Initialize ev struct to 0 to avoid valgrind complaining + * about uninitialized data in timer_create call + */ + memset(&ev, 0, sizeof(ev)); + ev.sigev_value.sival_int = 0; + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGALRM; + + if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { + perror("timer_create"); + + /* disable dynticks */ + fprintf(stderr, "Dynamic Ticks disabled\n"); + + return -1; + } + + t->priv = (void *)(long)host_timer; + + return 0; +} + +static void dynticks_stop_timer(struct qemu_alarm_timer *t) +{ + timer_t host_timer = (timer_t)(long)t->priv; + + timer_delete(host_timer); +} + +static void dynticks_rearm_timer(struct qemu_alarm_timer *t) +{ + timer_t host_timer = (timer_t)(long)t->priv; + struct itimerspec timeout; + int64_t nearest_delta_us = INT64_MAX; + int64_t current_us; + + assert(alarm_has_dynticks(t)); + if (!active_timers[QEMU_CLOCK_REALTIME] && + !active_timers[QEMU_CLOCK_VIRTUAL] && + !active_timers[QEMU_CLOCK_HOST]) + return; + + nearest_delta_us = qemu_next_deadline_dyntick(); + + /* check whether a timer is already running */ + if (timer_gettime(host_timer, &timeout)) { + perror("gettime"); + fprintf(stderr, "Internal timer error: aborting\n"); + exit(1); + } + current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000; + if (current_us && current_us <= nearest_delta_us) + return; + + timeout.it_interval.tv_sec = 0; + timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ + timeout.it_value.tv_sec = nearest_delta_us / 1000000; + timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000; + if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) { + perror("settime"); + fprintf(stderr, "Internal timer error: aborting\n"); + exit(1); + } +} + +#endif /* defined(__linux__) */ + +static int unix_start_timer(struct qemu_alarm_timer *t) +{ + struct sigaction act; + struct itimerval itv; + int err; + + /* timer signal */ + sigfillset(&act.sa_mask); + act.sa_flags = 0; + act.sa_handler = host_alarm_handler; + + sigaction(SIGALRM, &act, NULL); + + itv.it_interval.tv_sec = 0; + /* for i386 kernel 2.6 to get 1 ms */ + itv.it_interval.tv_usec = 999; + itv.it_value.tv_sec = 0; + itv.it_value.tv_usec = 10 * 1000; + + err = setitimer(ITIMER_REAL, &itv, NULL); + if (err) + return -1; + + return 0; +} + +static void unix_stop_timer(struct qemu_alarm_timer *t) +{ + struct itimerval itv; + + memset(&itv, 0, sizeof(itv)); + setitimer(ITIMER_REAL, &itv, NULL); +} + +#endif /* !defined(_WIN32) */ + + +#ifdef _WIN32 + +static int win32_start_timer(struct qemu_alarm_timer *t) +{ + TIMECAPS tc; + struct qemu_alarm_win32 *data = t->priv; + UINT flags; + + memset(&tc, 0, sizeof(tc)); + timeGetDevCaps(&tc, sizeof(tc)); + + data->period = tc.wPeriodMin; + timeBeginPeriod(data->period); + + flags = TIME_CALLBACK_FUNCTION; + if (alarm_has_dynticks(t)) + flags |= TIME_ONESHOT; + else + flags |= TIME_PERIODIC; + + data->timerId = timeSetEvent(1, // interval (ms) + data->period, // resolution + host_alarm_handler, // function + (DWORD)t, // parameter + flags); + + if (!data->timerId) { + fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n", + GetLastError()); + timeEndPeriod(data->period); + return -1; + } + + return 0; +} + +static void win32_stop_timer(struct qemu_alarm_timer *t) +{ + struct qemu_alarm_win32 *data = t->priv; + + timeKillEvent(data->timerId); + timeEndPeriod(data->period); +} + +static void win32_rearm_timer(struct qemu_alarm_timer *t) +{ + struct qemu_alarm_win32 *data = t->priv; + + assert(alarm_has_dynticks(t)); + if (!active_timers[QEMU_CLOCK_REALTIME] && + !active_timers[QEMU_CLOCK_VIRTUAL] && + !active_timers[QEMU_CLOCK_HOST]) + return; + + timeKillEvent(data->timerId); + + data->timerId = timeSetEvent(1, + data->period, + host_alarm_handler, + (DWORD)t, + TIME_ONESHOT | TIME_CALLBACK_FUNCTION); + + if (!data->timerId) { + fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n", + GetLastError()); + + timeEndPeriod(data->period); + exit(1); + } +} + +#endif /* _WIN32 */ + +static void alarm_timer_on_change_state_rearm(void *opaque, int running, int reason) +{ + if (running) + qemu_rearm_alarm_timer((struct qemu_alarm_timer *) opaque); +} + +int init_timer_alarm(void) +{ + struct qemu_alarm_timer *t = NULL; + int i, err = -1; + + for (i = 0; alarm_timers[i].name; i++) { + t = &alarm_timers[i]; + + err = t->start(t); + if (!err) + break; + } + + if (err) { + err = -ENOENT; + goto fail; + } + + /* first event is at time 0 */ + t->pending = 1; + alarm_timer = t; + qemu_add_vm_change_state_handler(alarm_timer_on_change_state_rearm, t); + + return 0; + +fail: + return err; +} + +void quit_timers(void) +{ + struct qemu_alarm_timer *t = alarm_timer; + alarm_timer = NULL; + t->stop(t); +} + +int qemu_calculate_timeout(void) +{ +#ifndef CONFIG_IOTHREAD + int timeout; + + if (!vm_running) + timeout = 5000; + else { + /* XXX: use timeout computed from timers */ + int64_t add; + int64_t delta; + /* Advance virtual time to the next event. */ + delta = qemu_icount_delta(); + if (delta > 0) { + /* If virtual time is ahead of real time then just + wait for IO. */ + timeout = (delta + 999999) / 1000000; + } else { + /* Wait for either IO to occur or the next + timer event. */ + add = qemu_next_deadline(); + /* We advance the timer before checking for IO. + Limit the amount we advance so that early IO + activity won't get the guest too far ahead. */ + if (add > 10000000) + add = 10000000; + delta += add; + qemu_icount += qemu_icount_round (add); + timeout = delta / 1000000; + if (timeout < 0) + timeout = 0; + } + } + + return timeout; +#else /* CONFIG_IOTHREAD */ + return 1000; +#endif +} + +/* Return the virtual CPU time, based on the instruction counter. */ +int64_t cpu_get_icount(void) +{ + int64_t icount; + CPUState *env = cpu_single_env;; + + icount = qemu_icount; + if (env) { + if (!can_do_io(env)) { + fprintf(stderr, "Bad clock read\n"); + } + icount -= (env->icount_decr.u16.low + env->icount_extra); + } + return qemu_icount_bias + (icount << icount_time_shift); +} diff --git a/qemu-timer.h b/qemu-timer.h index c17b4e6..1494f79 100644 --- a/qemu-timer.h +++ b/qemu-timer.h @@ -1,6 +1,8 @@ #ifndef QEMU_TIMER_H #define QEMU_TIMER_H +#include "qemu-common.h" + /* timers */ typedef struct QEMUClock QEMUClock; @@ -26,6 +28,7 @@ extern QEMUClock *host_clock; int64_t qemu_get_clock(QEMUClock *clock); int64_t qemu_get_clock_ns(QEMUClock *clock); +void qemu_clock_enable(QEMUClock *clock, int enabled); QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque); void qemu_free_timer(QEMUTimer *ts); @@ -34,11 +37,22 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time); int qemu_timer_pending(QEMUTimer *ts); int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time); +void qemu_run_all_timers(void); +int qemu_alarm_pending(void); +int64_t qemu_next_deadline(void); +void configure_alarms(char const *opt); +void configure_icount(const char *option); +int qemu_calculate_timeout(void); +void init_clocks(void); +int init_timer_alarm(void); +void quit_timers(void); + static inline int64_t get_ticks_per_sec(void) { return 1000000000LL; } + void qemu_get_timer(QEMUFile *f, QEMUTimer *ts); void qemu_put_timer(QEMUFile *f, QEMUTimer *ts); @@ -57,4 +71,193 @@ void ptimer_stop(ptimer_state *s); void qemu_put_ptimer(QEMUFile *f, ptimer_state *s); void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); +/* icount */ +int64_t qemu_icount_round(int64_t count); +extern int64_t qemu_icount; +extern int use_icount; +extern int icount_time_shift; +extern int64_t qemu_icount_bias; +int64_t cpu_get_icount(void); + +/*******************************************/ +/* host CPU ticks (if available) */ + +#if defined(_ARCH_PPC) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t retval; +#ifdef _ARCH_PPC64 + /* This reads timebase in one 64bit go and includes Cell workaround from: + http://ozlabs.org/pipermail/linuxppc-dev/2006-October/027052.html + */ + __asm__ __volatile__ ("mftb %0\n\t" + "cmpwi %0,0\n\t" + "beq- $-8" + : "=r" (retval)); +#else + /* http://ozlabs.org/pipermail/linuxppc-dev/1999-October/003889.html */ + unsigned long junk; + __asm__ __volatile__ ("mfspr %1,269\n\t" /* mftbu */ + "mfspr %L0,268\n\t" /* mftb */ + "mfspr %0,269\n\t" /* mftbu */ + "cmpw %0,%1\n\t" + "bne $-16" + : "=r" (retval), "=r" (junk)); +#endif + return retval; +} + +#elif defined(__i386__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile ("rdtsc" : "=A" (val)); + return val; +} + +#elif defined(__x86_64__) + +static inline int64_t cpu_get_real_ticks(void) +{ + uint32_t low,high; + int64_t val; + asm volatile("rdtsc" : "=a" (low), "=d" (high)); + val = high; + val <<= 32; + val |= low; + return val; +} + +#elif defined(__hppa__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int val; + asm volatile ("mfctl %%cr16, %0" : "=r"(val)); + return val; +} + +#elif defined(__ia64) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); + return val; +} + +#elif defined(__s390__) + +static inline int64_t cpu_get_real_ticks(void) +{ + int64_t val; + asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc"); + return val; +} + +#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) + +static inline int64_t cpu_get_real_ticks (void) +{ +#if defined(_LP64) + uint64_t rval; + asm volatile("rd %%tick,%0" : "=r"(rval)); + return rval; +#else + union { + uint64_t i64; + struct { + uint32_t high; + uint32_t low; + } i32; + } rval; + asm volatile("rd %%tick,%1; srlx %1,32,%0" + : "=r"(rval.i32.high), "=r"(rval.i32.low)); + return rval.i64; +#endif +} + +#elif defined(__mips__) && \ + ((defined(__mips_isa_rev) && __mips_isa_rev >= 2) || defined(__linux__)) +/* + * binutils wants to use rdhwr only on mips32r2 + * but as linux kernel emulate it, it's fine + * to use it. + * + */ +#define MIPS_RDHWR(rd, value) { \ + __asm__ __volatile__ (".set push\n\t" \ + ".set mips32r2\n\t" \ + "rdhwr %0, "rd"\n\t" \ + ".set pop" \ + : "=r" (value)); \ + } + +static inline int64_t cpu_get_real_ticks(void) +{ + /* On kernels >= 2.6.25 rdhwr <reg>, $2 and $3 are emulated */ + uint32_t count; + static uint32_t cyc_per_count = 0; + + if (!cyc_per_count) { + MIPS_RDHWR("$3", cyc_per_count); + } + + MIPS_RDHWR("$2", count); + return (int64_t)(count * cyc_per_count); +} + +#elif defined(__alpha__) + +static inline int64_t cpu_get_real_ticks(void) +{ + uint64_t cc; + uint32_t cur, ofs; + + asm volatile("rpcc %0" : "=r"(cc)); + cur = cc; + ofs = cc >> 32; + return cur - ofs; +} + +#else +/* The host CPU doesn't have an easily accessible cycle counter. + Just return a monotonically increasing value. This will be + totally wrong, but hopefully better than nothing. */ +static inline int64_t cpu_get_real_ticks (void) +{ + static int64_t ticks = 0; + return ticks++; +} +#endif + +#ifdef NEED_CPU_H +/* Deterministic execution requires that IO only be performed on the last + instruction of a TB so that interrupts take effect immediately. */ +static inline int can_do_io(CPUState *env) +{ + if (!use_icount) + return 1; + + /* If not executing code then assume we are ok. */ + if (!env->current_tb) + return 1; + + return env->can_do_io != 0; +} +#endif + +#ifdef CONFIG_PROFILER +static inline int64_t profile_getclock(void) +{ + return cpu_get_real_ticks(); +} + +extern int64_t qemu_time, qemu_time_start; +extern int64_t tlb_flush_time; +extern int64_t dev_time; +#endif + #endif diff --git a/softmmu_template.h b/softmmu_template.h index 4cd66f0..ab23e02 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -16,6 +16,8 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu-timer.h" + #define DATA_SIZE (1 << SHIFT) #if DATA_SIZE == 8 @@ -139,6 +139,7 @@ extern int graphic_rotate; extern int no_quit; extern int semihosting_enabled; extern int old_param; +extern QEMUClock *rtc_clock; #ifdef CONFIG_KQEMU extern int kqemu_allowed; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index afc0146..240be27 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -14,8 +14,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef CPU_ARM_H #define CPU_ARM_H @@ -41,6 +40,7 @@ #define EXCP_BKPT 7 #define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ #define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ +#define EXCP_STREX 10 #define ARMV7M_EXCP_RESET 1 #define ARMV7M_EXCP_NMI 2 @@ -388,6 +388,7 @@ void cpu_arm_set_cp_io(CPUARMState *env, int cpnum, #define ARM_CPUID_ARM1136_R2 0x4107b362 #define ARM_CPUID_ARM11MPCORE 0x410fb022 #define ARM_CPUID_CORTEXA8 0x410fc080 +#define ARM_CPUID_CORTEXA9 0x410fc090 #define ARM_CPUID_CORTEXM3 0x410fc231 #define ARM_CPUID_ANY 0xffffffff @@ -27,7 +27,7 @@ #include "config.h" -#ifndef CONFIG_DEBUG_TCG +#if !defined(CONFIG_DEBUG_TCG) && !defined(NDEBUG) /* define it to suppress various consistency checks (faster) */ #define NDEBUG #endif @@ -47,6 +47,7 @@ #include "qemu-common.h" #include "cache-utils.h" #include "host-utils.h" +#include "qemu-timer.h" /* Note: the long term plan is to reduce the dependancies on the QEMU CPU definitions. Currently they are used for qemu_ld/st diff --git a/translate-all.c b/translate-all.c index 4d6ea61..c6b369a 100644 --- a/translate-all.c +++ b/translate-all.c @@ -29,6 +29,7 @@ #include "exec-all.h" #include "disas.h" #include "tcg.h" +#include "qemu-timer.h" /* code generation context */ TCGContext tcg_ctx; diff --git a/vl-android.c b/vl-android.c index a3cf02b..4c81d55 100644 --- a/vl-android.c +++ b/vl-android.c @@ -323,14 +323,6 @@ uint64_t node_cpumask[MAX_NODES]; static CPUState *cur_cpu; static CPUState *next_cpu; static int timer_alarm_pending = 1; -/* Conversion factor from emulated instructions to virtual clock ticks. */ -static int icount_time_shift; -/* Arbitrarily pick 1MIPS as the minimum allowable speed. */ -#define MAX_ICOUNT_SHIFT 10 -/* Compensate for varying guest execution speed. */ -static int64_t qemu_icount_bias; -static QEMUTimer *icount_rt_timer; -static QEMUTimer *icount_vm_timer; static QEMUTimer *nographic_timer; uint8_t qemu_uuid[16]; @@ -782,1057 +774,6 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) return res.ll; } -static int64_t get_clock_realtime(void) -{ - struct timeval tv; - - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); -} - -#ifdef WIN32 - -static int64_t clock_freq; - -static void init_get_clock(void) -{ - LARGE_INTEGER freq; - int ret; - ret = QueryPerformanceFrequency(&freq); - if (ret == 0) { - fprintf(stderr, "Could not calibrate ticks\n"); - exit(1); - } - clock_freq = freq.QuadPart; -} - -static int64_t get_clock(void) -{ - LARGE_INTEGER ti; - QueryPerformanceCounter(&ti); - return muldiv64(ti.QuadPart, get_ticks_per_sec(), clock_freq); -} - -#else - -static int use_rt_clock; - -static void init_get_clock(void) -{ - use_rt_clock = 0; -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \ - || defined(__DragonFly__) || defined(__FreeBSD_kernel__) - { - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { - use_rt_clock = 1; - } - } -#endif -} - -static int64_t get_clock(void) -{ -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \ - || defined(__DragonFly__) || defined(__FreeBSD_kernel__) - if (use_rt_clock) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000000LL + ts.tv_nsec; - } else -#endif - { - /* XXX: using gettimeofday leads to problems if the date - changes, so it should be avoided. */ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); - } -} -#endif - -/* Return the virtual CPU time, based on the instruction counter. */ -static int64_t cpu_get_icount(void) -{ - int64_t icount; - CPUState *env = cpu_single_env;; - icount = qemu_icount; - if (env) { - if (!can_do_io(env)) - fprintf(stderr, "Bad clock read\n"); - icount -= (env->icount_decr.u16.low + env->icount_extra); - } - return qemu_icount_bias + (icount << icount_time_shift); -} - -/***********************************************************/ -/* guest cycle counter */ - -typedef struct TimersState { - int64_t cpu_ticks_prev; - int64_t cpu_ticks_offset; - int64_t cpu_clock_offset; - int32_t cpu_ticks_enabled; - int64_t dummy; -} TimersState; - -TimersState timers_state; - -/* return the host CPU cycle counter and handle stop/restart */ -int64_t cpu_get_ticks(void) -{ - if (use_icount) { - return cpu_get_icount(); - } - if (!timers_state.cpu_ticks_enabled) { - return timers_state.cpu_ticks_offset; - } else { - int64_t ticks; - ticks = cpu_get_real_ticks(); - if (timers_state.cpu_ticks_prev > ticks) { - /* Note: non increasing ticks may happen if the host uses - software suspend */ - timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks; - } - timers_state.cpu_ticks_prev = ticks; - return ticks + timers_state.cpu_ticks_offset; - } -} - -/* return the host CPU monotonic timer and handle stop/restart */ -static int64_t cpu_get_clock(void) -{ - int64_t ti; - if (!timers_state.cpu_ticks_enabled) { - return timers_state.cpu_clock_offset; - } else { - ti = get_clock(); - return ti + timers_state.cpu_clock_offset; - } -} - -/* enable cpu_get_ticks() */ -void cpu_enable_ticks(void) -{ - if (!timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset -= cpu_get_real_ticks(); - timers_state.cpu_clock_offset -= get_clock(); - timers_state.cpu_ticks_enabled = 1; - } -} - -/* disable cpu_get_ticks() : the clock is stopped. You must not call - cpu_get_ticks() after that. */ -void cpu_disable_ticks(void) -{ - if (timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset = cpu_get_ticks(); - timers_state.cpu_clock_offset = cpu_get_clock(); - timers_state.cpu_ticks_enabled = 0; - } -} - -/***********************************************************/ -/* timers */ - -#define QEMU_CLOCK_REALTIME 0 -#define QEMU_CLOCK_VIRTUAL 1 -#define QEMU_CLOCK_HOST 2 - -struct QEMUClock { - int type; - /* XXX: add frequency */ -}; - -struct QEMUTimer { - QEMUClock *clock; - int64_t expire_time; - QEMUTimerCB *cb; - void *opaque; - struct QEMUTimer *next; -}; - -struct qemu_alarm_timer { - char const *name; - unsigned int flags; - - int (*start)(struct qemu_alarm_timer *t); - void (*stop)(struct qemu_alarm_timer *t); - void (*rearm)(struct qemu_alarm_timer *t); - void *priv; -}; - -#define ALARM_FLAG_DYNTICKS 0x1 -#define ALARM_FLAG_EXPIRED 0x2 - -static inline int alarm_has_dynticks(struct qemu_alarm_timer *t) -{ - return t && (t->flags & ALARM_FLAG_DYNTICKS); -} - -static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) -{ - if (!alarm_has_dynticks(t)) - return; - - t->rearm(t); -} - -/* TODO: MIN_TIMER_REARM_US should be optimized */ -#define MIN_TIMER_REARM_US 250 - -static struct qemu_alarm_timer *alarm_timer; - -#ifdef _WIN32 - -struct qemu_alarm_win32 { - MMRESULT timerId; - unsigned int period; -} alarm_win32_data = {0, -1}; - -static int win32_start_timer(struct qemu_alarm_timer *t); -static void win32_stop_timer(struct qemu_alarm_timer *t); -static void win32_rearm_timer(struct qemu_alarm_timer *t); - -#else - -static int unix_start_timer(struct qemu_alarm_timer *t); -static void unix_stop_timer(struct qemu_alarm_timer *t); - -#ifdef __linux__ - -static int dynticks_start_timer(struct qemu_alarm_timer *t); -static void dynticks_stop_timer(struct qemu_alarm_timer *t); -static void dynticks_rearm_timer(struct qemu_alarm_timer *t); - -static int hpet_start_timer(struct qemu_alarm_timer *t); -static void hpet_stop_timer(struct qemu_alarm_timer *t); - -static int rtc_start_timer(struct qemu_alarm_timer *t); -static void rtc_stop_timer(struct qemu_alarm_timer *t); - -#endif /* __linux__ */ - -#endif /* _WIN32 */ - -/* Correlation between real and virtual time is always going to be - fairly approximate, so ignore small variation. - When the guest is idle real and virtual time will be aligned in - the IO wait loop. */ -#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10) - -static void icount_adjust(void) -{ - int64_t cur_time; - int64_t cur_icount; - int64_t delta; - static int64_t last_delta; - /* If the VM is not running, then do nothing. */ - if (!vm_running) - return; - - cur_time = cpu_get_clock(); - cur_icount = qemu_get_clock(vm_clock); - delta = cur_icount - cur_time; - /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ - if (delta > 0 - && last_delta + ICOUNT_WOBBLE < delta * 2 - && icount_time_shift > 0) { - /* The guest is getting too far ahead. Slow time down. */ - icount_time_shift--; - } - if (delta < 0 - && last_delta - ICOUNT_WOBBLE > delta * 2 - && icount_time_shift < MAX_ICOUNT_SHIFT) { - /* The guest is getting too far behind. Speed time up. */ - icount_time_shift++; - } - last_delta = delta; - qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift); -} - -static void icount_adjust_rt(void * opaque) -{ - qemu_mod_timer(icount_rt_timer, - qemu_get_clock(rt_clock) + 1000); - icount_adjust(); -} - -static void icount_adjust_vm(void * opaque) -{ - qemu_mod_timer(icount_vm_timer, - qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10); - icount_adjust(); -} - -static void init_icount_adjust(void) -{ - /* Have both realtime and virtual time triggers for speed adjustment. - The realtime trigger catches emulated time passing too slowly, - the virtual time trigger catches emulated time passing too fast. - Realtime triggers occur even when idle, so use them less frequently - than VM triggers. */ - icount_rt_timer = qemu_new_timer(rt_clock, icount_adjust_rt, NULL); - qemu_mod_timer(icount_rt_timer, - qemu_get_clock(rt_clock) + 1000); - icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL); - qemu_mod_timer(icount_vm_timer, - qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10); -} - -static struct qemu_alarm_timer alarm_timers[] = { -#ifndef _WIN32 -#ifdef __linux__ - {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer, - dynticks_stop_timer, dynticks_rearm_timer, NULL}, - /* HPET - if available - is preferred */ - {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL}, - /* ...otherwise try RTC */ - {"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL}, -#endif - {"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL}, -#else - {"dynticks", ALARM_FLAG_DYNTICKS, win32_start_timer, - win32_stop_timer, win32_rearm_timer, &alarm_win32_data}, - {"win32", 0, win32_start_timer, - win32_stop_timer, NULL, &alarm_win32_data}, -#endif - {NULL, 0, NULL, NULL, NULL, NULL} -}; - -static void show_available_alarms(void) -{ - int i; - - printf("Available alarm timers, in order of precedence:\n"); - for (i = 0; alarm_timers[i].name; i++) - printf("%s\n", alarm_timers[i].name); -} - -static void configure_alarms(char const *opt) -{ - int i; - int cur = 0; - int count = ARRAY_SIZE(alarm_timers) - 1; - char *arg; - char *name; - struct qemu_alarm_timer tmp; - - if (!strcmp(opt, "?")) { - show_available_alarms(); - exit(0); - } - - arg = strdup(opt); - - /* Reorder the array */ - name = strtok(arg, ","); - while (name) { - for (i = 0; i < count && alarm_timers[i].name; i++) { - if (!strcmp(alarm_timers[i].name, name)) - break; - } - - if (i == count) { - fprintf(stderr, "Unknown clock %s\n", name); - goto next; - } - - if (i < cur) - /* Ignore */ - goto next; - - /* Swap */ - tmp = alarm_timers[i]; - alarm_timers[i] = alarm_timers[cur]; - alarm_timers[cur] = tmp; - - cur++; -next: - name = strtok(NULL, ","); - } - - qemu_free(arg); - - if (cur) { - /* Disable remaining timers */ - for (i = cur; i < count; i++) - alarm_timers[i].name = NULL; - } else { - show_available_alarms(); - exit(1); - } -} - -#define QEMU_NUM_CLOCKS 3 - -QEMUClock *rt_clock; -QEMUClock *vm_clock; -QEMUClock *host_clock; - -static QEMUTimer *active_timers[QEMU_NUM_CLOCKS]; - -static QEMUClock *qemu_new_clock(int type) -{ - QEMUClock *clock; - clock = qemu_mallocz(sizeof(QEMUClock)); - clock->type = type; - return clock; -} - -QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque) -{ - QEMUTimer *ts; - - ts = qemu_mallocz(sizeof(QEMUTimer)); - ts->clock = clock; - ts->cb = cb; - ts->opaque = opaque; - return ts; -} - -void qemu_free_timer(QEMUTimer *ts) -{ - qemu_free(ts); -} - -/* stop a timer, but do not dealloc it */ -void qemu_del_timer(QEMUTimer *ts) -{ - QEMUTimer **pt, *t; - - /* NOTE: this code must be signal safe because - qemu_timer_expired() can be called from a signal. */ - pt = &active_timers[ts->clock->type]; - for(;;) { - t = *pt; - if (!t) - break; - if (t == ts) { - *pt = t->next; - break; - } - pt = &t->next; - } -} - -/* modify the current timer so that it will be fired when current_time - >= expire_time. The corresponding callback will be called. */ -void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) -{ - QEMUTimer **pt, *t; - - qemu_del_timer(ts); - - /* add the timer in the sorted list */ - /* NOTE: this code must be signal safe because - qemu_timer_expired() can be called from a signal. */ - pt = &active_timers[ts->clock->type]; - for(;;) { - t = *pt; - if (!t) - break; - if (t->expire_time > expire_time) - break; - pt = &t->next; - } - ts->expire_time = expire_time; - ts->next = *pt; - *pt = ts; - - /* Rearm if necessary */ - if (pt == &active_timers[ts->clock->type]) { - if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0) { - qemu_rearm_alarm_timer(alarm_timer); - } - /* Interrupt execution to force deadline recalculation. */ - if (use_icount) - qemu_notify_event(); - } -} - -int qemu_timer_pending(QEMUTimer *ts) -{ - QEMUTimer *t; - for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) { - if (t == ts) - return 1; - } - return 0; -} - -int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) -{ - if (!timer_head) - return 0; - return (timer_head->expire_time <= current_time); -} - -static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) -{ - QEMUTimer *ts; - - for(;;) { - ts = *ptimer_head; - if (!ts || ts->expire_time > current_time) - break; - /* remove timer from the list before calling the callback */ - *ptimer_head = ts->next; - ts->next = NULL; - - /* run the callback (the timer list can be modified) */ - ts->cb(ts->opaque); - } -} - -int64_t qemu_get_clock(QEMUClock *clock) -{ - switch(clock->type) { - case QEMU_CLOCK_REALTIME: - return get_clock() / 1000000; - default: - case QEMU_CLOCK_VIRTUAL: - if (use_icount) { - return cpu_get_icount(); - } else { - return cpu_get_clock(); - } - case QEMU_CLOCK_HOST: - return get_clock_realtime(); - } -} - -int64_t qemu_get_clock_ns(QEMUClock *clock) -{ - switch(clock->type) { - case QEMU_CLOCK_REALTIME: - return get_clock(); - default: - case QEMU_CLOCK_VIRTUAL: - if (use_icount) { - return cpu_get_icount(); - } else { - return cpu_get_clock(); - } - case QEMU_CLOCK_HOST: - return get_clock_realtime(); - } -} - -static void init_clocks(void) -{ - init_get_clock(); - rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME); - vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL); - host_clock = qemu_new_clock(QEMU_CLOCK_HOST); - - rtc_clock = host_clock; -} - -/* save a timer */ -void qemu_put_timer(QEMUFile *f, QEMUTimer *ts) -{ - uint64_t expire_time; - - if (qemu_timer_pending(ts)) { - expire_time = ts->expire_time; - } else { - expire_time = -1; - } - qemu_put_be64(f, expire_time); -} - -void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) -{ - uint64_t expire_time; - - expire_time = qemu_get_be64(f); - if (expire_time != -1) { - qemu_mod_timer(ts, expire_time); - } else { - qemu_del_timer(ts); - } -} - -static void timer_save(QEMUFile *f, void *opaque) -{ - TimersState *s = opaque; - - if (s->cpu_ticks_enabled) { - hw_error("cannot save state if virtual timers are running"); - } - qemu_put_be64(f, s->cpu_ticks_offset); - qemu_put_be64(f, ticks_per_sec); - qemu_put_be64(f, s->cpu_clock_offset); -} - -static int timer_load(QEMUFile *f, void *opaque, int version_id) -{ - TimersState *s = opaque; - - if (version_id != 1 && version_id != 2) - return -EINVAL; - if (s->cpu_ticks_enabled) { - return -EINVAL; - } - s->cpu_ticks_offset = qemu_get_be64(f); - ticks_per_sec = qemu_get_be64(f); - if (version_id == 2) { - s->cpu_clock_offset = qemu_get_be64(f); - } - return 0; -} - -static void qemu_event_increment(void); - -#ifdef _WIN32 -static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, - DWORD_PTR dwUser, DWORD_PTR dw1, - DWORD_PTR dw2) -#else -static void host_alarm_handler(int host_signum) -#endif -{ -#if 0 -#define DISP_FREQ 1000 - { - static int64_t delta_min = INT64_MAX; - static int64_t delta_max, delta_cum, last_clock, delta, ti; - static int count; - ti = qemu_get_clock(vm_clock); - if (last_clock != 0) { - delta = ti - last_clock; - if (delta < delta_min) - delta_min = delta; - if (delta > delta_max) - delta_max = delta; - delta_cum += delta; - if (++count == DISP_FREQ) { - printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n", - muldiv64(delta_min, 1000000, get_ticks_per_sec()), - muldiv64(delta_max, 1000000, get_ticks_per_sec()), - muldiv64(delta_cum, 1000000 / DISP_FREQ, get_ticks_per_sec()), - (double)get_ticks_per_sec() / ((double)delta_cum / DISP_FREQ)); - count = 0; - delta_min = INT64_MAX; - delta_max = 0; - delta_cum = 0; - } - } - last_clock = ti; - } -#endif - if (alarm_has_dynticks(alarm_timer) || - (!use_icount && - qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL], - qemu_get_clock(vm_clock))) || - qemu_timer_expired(active_timers[QEMU_CLOCK_REALTIME], - qemu_get_clock(rt_clock)) || - qemu_timer_expired(active_timers[QEMU_CLOCK_HOST], - qemu_get_clock(host_clock))) { - qemu_event_increment(); - if (alarm_timer) alarm_timer->flags |= ALARM_FLAG_EXPIRED; - -#ifndef CONFIG_IOTHREAD - if (next_cpu) { - /* stop the currently executing cpu because a timer occured */ - cpu_exit(next_cpu); - } -#endif - timer_alarm_pending = 1; - qemu_notify_event(); - } -} - -static int64_t qemu_next_deadline(void) -{ - /* To avoid problems with overflow limit this to 2^32. */ - int64_t delta = INT32_MAX; - - if (active_timers[QEMU_CLOCK_VIRTUAL]) { - delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time - - qemu_get_clock(vm_clock); - } - if (active_timers[QEMU_CLOCK_HOST]) { - int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time - - qemu_get_clock(host_clock); - if (hdelta < delta) - delta = hdelta; - } - - if (delta < 0) - delta = 0; - - return delta; -} - -#if defined(__linux__) -static uint64_t qemu_next_deadline_dyntick(void) -{ - int64_t delta; - int64_t rtdelta; - - if (use_icount) - delta = INT32_MAX; - else - delta = (qemu_next_deadline() + 999) / 1000; - - if (active_timers[QEMU_CLOCK_REALTIME]) { - rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time - - qemu_get_clock(rt_clock))*1000; - if (rtdelta < delta) - delta = rtdelta; - } - - if (delta < MIN_TIMER_REARM_US) - delta = MIN_TIMER_REARM_US; - - return delta; -} -#endif - -#ifndef _WIN32 - -/* Sets a specific flag */ -static int fcntl_setfl(int fd, int flag) -{ - int flags; - - flags = fcntl(fd, F_GETFL); - if (flags == -1) - return -errno; - - if (fcntl(fd, F_SETFL, flags | flag) == -1) - return -errno; - - return 0; -} - -#if defined(__linux__) - -#define RTC_FREQ 1024 - -static void enable_sigio_timer(int fd) -{ - struct sigaction act; - - /* timer signal */ - sigfillset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = host_alarm_handler; - - sigaction(SIGIO, &act, NULL); - fcntl_setfl(fd, O_ASYNC); - fcntl(fd, F_SETOWN, getpid()); -} - -static int hpet_start_timer(struct qemu_alarm_timer *t) -{ - struct hpet_info info; - int r, fd; - - fd = open("/dev/hpet", O_RDONLY); - if (fd < 0) - return -1; - - /* Set frequency */ - r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ); - if (r < 0) { - fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n" - "error, but for better emulation accuracy type:\n" - "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n"); - goto fail; - } - - /* Check capabilities */ - r = ioctl(fd, HPET_INFO, &info); - if (r < 0) - goto fail; - - /* Enable periodic mode */ - r = ioctl(fd, HPET_EPI, 0); - if (info.hi_flags && (r < 0)) - goto fail; - - /* Enable interrupt */ - r = ioctl(fd, HPET_IE_ON, 0); - if (r < 0) - goto fail; - - enable_sigio_timer(fd); - t->priv = (void *)(long)fd; - - return 0; -fail: - close(fd); - return -1; -} - -static void hpet_stop_timer(struct qemu_alarm_timer *t) -{ - int fd = (long)t->priv; - - close(fd); -} - -static int rtc_start_timer(struct qemu_alarm_timer *t) -{ - int rtc_fd; - unsigned long current_rtc_freq = 0; - - TFR(rtc_fd = open("/dev/rtc", O_RDONLY)); - if (rtc_fd < 0) - return -1; - ioctl(rtc_fd, RTC_IRQP_READ, ¤t_rtc_freq); - if (current_rtc_freq != RTC_FREQ && - ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { - fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n" - "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n" - "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n"); - goto fail; - } - if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) { - fail: - close(rtc_fd); - return -1; - } - - enable_sigio_timer(rtc_fd); - - t->priv = (void *)(long)rtc_fd; - - return 0; -} - -static void rtc_stop_timer(struct qemu_alarm_timer *t) -{ - int rtc_fd = (long)t->priv; - - close(rtc_fd); -} - -static int dynticks_start_timer(struct qemu_alarm_timer *t) -{ - struct sigevent ev; - timer_t host_timer; - struct sigaction act; - - sigfillset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = host_alarm_handler; - - sigaction(SIGALRM, &act, NULL); - - /* - * Initialize ev struct to 0 to avoid valgrind complaining - * about uninitialized data in timer_create call - */ - memset(&ev, 0, sizeof(ev)); - ev.sigev_value.sival_int = 0; - ev.sigev_notify = SIGEV_SIGNAL; - ev.sigev_signo = SIGALRM; - - if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { - perror("timer_create"); - - /* disable dynticks */ - fprintf(stderr, "Dynamic Ticks disabled\n"); - - return -1; - } - - t->priv = (void *)(long)host_timer; - - return 0; -} - -static void dynticks_stop_timer(struct qemu_alarm_timer *t) -{ - timer_t host_timer = (timer_t)(long)t->priv; - - timer_delete(host_timer); -} - -static void dynticks_rearm_timer(struct qemu_alarm_timer *t) -{ - timer_t host_timer = (timer_t)(long)t->priv; - struct itimerspec timeout; - int64_t nearest_delta_us = INT64_MAX; - int64_t current_us; - - if (!active_timers[QEMU_CLOCK_REALTIME] && - !active_timers[QEMU_CLOCK_VIRTUAL] && - !active_timers[QEMU_CLOCK_HOST]) - return; - - nearest_delta_us = qemu_next_deadline_dyntick(); - - /* check whether a timer is already running */ - if (timer_gettime(host_timer, &timeout)) { - perror("gettime"); - fprintf(stderr, "Internal timer error: aborting\n"); - exit(1); - } - current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000; - if (current_us && current_us <= nearest_delta_us) - return; - - timeout.it_interval.tv_sec = 0; - timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ - timeout.it_value.tv_sec = nearest_delta_us / 1000000; - timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000; - if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) { - perror("settime"); - fprintf(stderr, "Internal timer error: aborting\n"); - exit(1); - } -} - -#endif /* defined(__linux__) */ - -static int unix_start_timer(struct qemu_alarm_timer *t) -{ - struct sigaction act; - struct itimerval itv; - int err; - - /* timer signal */ - sigfillset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = host_alarm_handler; - - sigaction(SIGALRM, &act, NULL); - - itv.it_interval.tv_sec = 0; - /* for i386 kernel 2.6 to get 1 ms */ - itv.it_interval.tv_usec = 999; - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 10 * 1000; - - err = setitimer(ITIMER_REAL, &itv, NULL); - if (err) - return -1; - - return 0; -} - -static void unix_stop_timer(struct qemu_alarm_timer *t) -{ - struct itimerval itv; - - memset(&itv, 0, sizeof(itv)); - setitimer(ITIMER_REAL, &itv, NULL); -} - -#endif /* !defined(_WIN32) */ - - -#ifdef _WIN32 - -static int win32_start_timer(struct qemu_alarm_timer *t) -{ - TIMECAPS tc; - struct qemu_alarm_win32 *data = t->priv; - UINT flags; - - memset(&tc, 0, sizeof(tc)); - timeGetDevCaps(&tc, sizeof(tc)); - - if (data->period < tc.wPeriodMin) - data->period = tc.wPeriodMin; - - timeBeginPeriod(data->period); - - flags = TIME_CALLBACK_FUNCTION; - if (alarm_has_dynticks(t)) - flags |= TIME_ONESHOT; - else - flags |= TIME_PERIODIC; - - data->timerId = timeSetEvent(1, // interval (ms) - data->period, // resolution - host_alarm_handler, // function - (DWORD)t, // parameter - flags); - - if (!data->timerId) { - fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n", - GetLastError()); - timeEndPeriod(data->period); - return -1; - } - - return 0; -} - -static void win32_stop_timer(struct qemu_alarm_timer *t) -{ - struct qemu_alarm_win32 *data = t->priv; - - timeKillEvent(data->timerId); - timeEndPeriod(data->period); -} - -static void win32_rearm_timer(struct qemu_alarm_timer *t) -{ - struct qemu_alarm_win32 *data = t->priv; - - if (!active_timers[QEMU_CLOCK_REALTIME] && - !active_timers[QEMU_CLOCK_VIRTUAL] && - !active_timers[QEMU_CLOCK_HOST]) - return; - - timeKillEvent(data->timerId); - - data->timerId = timeSetEvent(1, - data->period, - host_alarm_handler, - (DWORD)t, - TIME_ONESHOT | TIME_PERIODIC); - - if (!data->timerId) { - fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n", - GetLastError()); - - timeEndPeriod(data->period); - exit(1); - } -} - -#endif /* _WIN32 */ - -static int init_timer_alarm(void) -{ - struct qemu_alarm_timer *t = NULL; - int i, err = -1; - - for (i = 0; alarm_timers[i].name; i++) { - t = &alarm_timers[i]; - - err = t->start(t); - if (!err) - break; - } - - if (err) { - err = -ENOENT; - goto fail; - } - - alarm_timer = t; - - return 0; - -fail: - return err; -} - -static void quit_timers(void) -{ - alarm_timer->stop(alarm_timer); - alarm_timer = NULL; -} - /***********************************************************/ /* host time/date access */ void qemu_get_timedate(struct tm *tm, int offset) @@ -3314,7 +2255,7 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) } bytes_transferred_last = bytes_transferred; - bwidth = get_clock(); + bwidth = qemu_get_clock_ns(rt_clock); while (!qemu_file_rate_limit(f)) { int ret; @@ -3325,7 +2266,7 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) break; } - bwidth = get_clock() - bwidth; + bwidth = qemu_get_clock_ns(rt_clock) - bwidth; bwidth = (bytes_transferred - bytes_transferred_last) / bwidth; /* if we haven't transferred anything this round, force expected_time to a @@ -3645,7 +2586,7 @@ void vm_start(void) cpu_enable_ticks(); vm_running = 1; vm_state_notify(1, 0); - qemu_rearm_alarm_timer(alarm_timer); + //qemu_rearm_alarm_timer(alarm_timer); resume_all_vcpus(); } } @@ -4354,6 +3295,7 @@ void main_loop_wait(int timeout) #endif charpipe_poll(); +#if 0 /* rearm timer, if not periodic */ if (alarm_timer->flags & ALARM_FLAG_EXPIRED) { alarm_timer->flags &= ~ALARM_FLAG_EXPIRED; @@ -4373,6 +3315,8 @@ void main_loop_wait(int timeout) qemu_run_timers(&active_timers[QEMU_CLOCK_HOST], qemu_get_clock(host_clock)); +#endif + qemu_run_all_timers(); /* Check bottom-halves last in case any of the earlier events triggered them. */ @@ -4477,58 +3421,6 @@ static int tcg_has_work(void) return 0; } -static int qemu_calculate_timeout(void) -{ -#ifndef CONFIG_IOTHREAD - int timeout; - - if (!vm_running) - timeout = 5000; - else if (tcg_has_work()) - timeout = 0; - else if (!use_icount) - timeout = 5000; - else { - /* XXX: use timeout computed from timers */ - int64_t add; - int64_t delta; - /* Advance virtual time to the next event. */ - if (use_icount == 1) { - /* When not using an adaptive execution frequency - we tend to get badly out of sync with real time, - so just delay for a reasonable amount of time. */ - delta = 0; - } else { - delta = cpu_get_icount() - cpu_get_clock(); - } - if (delta > 0) { - /* If virtual time is ahead of real time then just - wait for IO. */ - timeout = (delta / 1000000) + 1; - } else { - /* Wait for either IO to occur or the next - timer event. */ - add = qemu_next_deadline(); - /* We advance the timer before checking for IO. - Limit the amount we advance so that early IO - activity won't get the guest too far ahead. */ - if (add > 10000000) - add = 10000000; - delta += add; - add = (add + (1 << icount_time_shift) - 1) - >> icount_time_shift; - qemu_icount += add; - timeout = delta / 1000000; - if (timeout < 0) - timeout = 0; - } - } - - return timeout; -#else /* CONFIG_IOTHREAD */ - return 1000; -#endif -} static int vm_can_run(void) { @@ -5067,6 +3959,7 @@ int main(int argc, char **argv, char **envp) uint32_t boot_devices_bitmap = 0; int i; int snapshot, linux_boot, net_boot; + const char *icount_option = NULL; const char *initrd_filename; const char *kernel_filename, *kernel_cmdline; const char *boot_devices = ""; @@ -5820,12 +4713,7 @@ int main(int argc, char **argv, char **envp) tb_size = 0; break; case QEMU_OPTION_icount: - use_icount = 1; - if (strcmp(optarg, "auto") == 0) { - icount_time_shift = -1; - } else { - icount_time_shift = strtol(optarg, NULL, 0); - } + icount_option = optarg; break; case QEMU_OPTION_incoming: incoming = optarg; @@ -6339,13 +5227,7 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "could not initialize alarm timer\n"); exit(1); } - if (use_icount && icount_time_shift < 0) { - use_icount = 2; - /* 125MIPS seems a reasonable initial guess at the guest speed. - It will be corrected fairly quickly anyway. */ - icount_time_shift = 3; - init_icount_adjust(); - } + configure_icount(icount_option); #ifdef _WIN32 socket_init(); @@ -6448,7 +5330,7 @@ int main(int argc, char **argv, char **envp) if (drive_init(&drives_opt[i], snapshot, machine) == -1) exit(1); - register_savevm("timer", 0, 2, timer_save, timer_load, &timers_state); + //register_savevm("timer", 0, 2, timer_save, timer_load, &timers_state); register_savevm_live("ram", 0, 3, ram_save_live, NULL, ram_load, NULL); #ifndef _WIN32 @@ -277,14 +277,6 @@ uint64_t node_cpumask[MAX_NODES]; static CPUState *cur_cpu; static CPUState *next_cpu; static int timer_alarm_pending = 1; -/* Conversion factor from emulated instructions to virtual clock ticks. */ -static int icount_time_shift; -/* Arbitrarily pick 1MIPS as the minimum allowable speed. */ -#define MAX_ICOUNT_SHIFT 10 -/* Compensate for varying guest execution speed. */ -static int64_t qemu_icount_bias; -static QEMUTimer *icount_rt_timer; -static QEMUTimer *icount_vm_timer; static QEMUTimer *nographic_timer; uint8_t qemu_uuid[16]; @@ -757,1039 +749,6 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) return res.ll; } -static int64_t get_clock_realtime(void) -{ - struct timeval tv; - - gettimeofday(&tv, NULL); - return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000); -} - -#ifdef WIN32 - -static int64_t clock_freq; - -static void init_get_clock(void) -{ - LARGE_INTEGER freq; - int ret; - ret = QueryPerformanceFrequency(&freq); - if (ret == 0) { - fprintf(stderr, "Could not calibrate ticks\n"); - exit(1); - } - clock_freq = freq.QuadPart; -} - -static int64_t get_clock(void) -{ - LARGE_INTEGER ti; - QueryPerformanceCounter(&ti); - return muldiv64(ti.QuadPart, get_ticks_per_sec(), clock_freq); -} - -#else - -static int use_rt_clock; - -static void init_get_clock(void) -{ - use_rt_clock = 0; -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \ - || defined(__DragonFly__) || defined(__FreeBSD_kernel__) - { - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { - use_rt_clock = 1; - } - } -#endif -} - -static int64_t get_clock(void) -{ -#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \ - || defined(__DragonFly__) || defined(__FreeBSD_kernel__) - if (use_rt_clock) { - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec * 1000000000LL + ts.tv_nsec; - } else -#endif - { - /* XXX: using gettimeofday leads to problems if the date - changes, so it should be avoided. */ - return get_clock_realtime(); - } -} -#endif - -/* Return the virtual CPU time, based on the instruction counter. */ -static int64_t cpu_get_icount(void) -{ - int64_t icount; - CPUState *env = cpu_single_env;; - icount = qemu_icount; - if (env) { - if (!can_do_io(env)) - fprintf(stderr, "Bad clock read\n"); - icount -= (env->icount_decr.u16.low + env->icount_extra); - } - return qemu_icount_bias + (icount << icount_time_shift); -} - -/***********************************************************/ -/* guest cycle counter */ - -typedef struct TimersState { - int64_t cpu_ticks_prev; - int64_t cpu_ticks_offset; - int64_t cpu_clock_offset; - int32_t cpu_ticks_enabled; - int64_t dummy; -} TimersState; - -TimersState timers_state; - -/* return the host CPU cycle counter and handle stop/restart */ -int64_t cpu_get_ticks(void) -{ - if (use_icount) { - return cpu_get_icount(); - } - if (!timers_state.cpu_ticks_enabled) { - return timers_state.cpu_ticks_offset; - } else { - int64_t ticks; - ticks = cpu_get_real_ticks(); - if (timers_state.cpu_ticks_prev > ticks) { - /* Note: non increasing ticks may happen if the host uses - software suspend */ - timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks; - } - timers_state.cpu_ticks_prev = ticks; - return ticks + timers_state.cpu_ticks_offset; - } -} - -/* return the host CPU monotonic timer and handle stop/restart */ -static int64_t cpu_get_clock(void) -{ - int64_t ti; - if (!timers_state.cpu_ticks_enabled) { - return timers_state.cpu_clock_offset; - } else { - ti = get_clock(); - return ti + timers_state.cpu_clock_offset; - } -} - -/* enable cpu_get_ticks() */ -void cpu_enable_ticks(void) -{ - if (!timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset -= cpu_get_real_ticks(); - timers_state.cpu_clock_offset -= get_clock(); - timers_state.cpu_ticks_enabled = 1; - } -} - -/* disable cpu_get_ticks() : the clock is stopped. You must not call - cpu_get_ticks() after that. */ -void cpu_disable_ticks(void) -{ - if (timers_state.cpu_ticks_enabled) { - timers_state.cpu_ticks_offset = cpu_get_ticks(); - timers_state.cpu_clock_offset = cpu_get_clock(); - timers_state.cpu_ticks_enabled = 0; - } -} - -/***********************************************************/ -/* timers */ - -#define QEMU_CLOCK_REALTIME 0 -#define QEMU_CLOCK_VIRTUAL 1 -#define QEMU_CLOCK_HOST 2 - -struct QEMUClock { - int type; - /* XXX: add frequency */ -}; - -struct QEMUTimer { - QEMUClock *clock; - int64_t expire_time; - QEMUTimerCB *cb; - void *opaque; - struct QEMUTimer *next; -}; - -struct qemu_alarm_timer { - char const *name; - unsigned int flags; - - int (*start)(struct qemu_alarm_timer *t); - void (*stop)(struct qemu_alarm_timer *t); - void (*rearm)(struct qemu_alarm_timer *t); - void *priv; -}; - -#define ALARM_FLAG_DYNTICKS 0x1 -#define ALARM_FLAG_EXPIRED 0x2 - -static inline int alarm_has_dynticks(struct qemu_alarm_timer *t) -{ - return t && (t->flags & ALARM_FLAG_DYNTICKS); -} - -static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t) -{ - if (!alarm_has_dynticks(t)) - return; - - t->rearm(t); -} - -/* TODO: MIN_TIMER_REARM_US should be optimized */ -#define MIN_TIMER_REARM_US 250 - -static struct qemu_alarm_timer *alarm_timer; - -#ifdef _WIN32 - -struct qemu_alarm_win32 { - MMRESULT timerId; - unsigned int period; -} alarm_win32_data = {0, -1}; - -static int win32_start_timer(struct qemu_alarm_timer *t); -static void win32_stop_timer(struct qemu_alarm_timer *t); -static void win32_rearm_timer(struct qemu_alarm_timer *t); - -#else - -static int unix_start_timer(struct qemu_alarm_timer *t); -static void unix_stop_timer(struct qemu_alarm_timer *t); - -#ifdef __linux__ - -static int dynticks_start_timer(struct qemu_alarm_timer *t); -static void dynticks_stop_timer(struct qemu_alarm_timer *t); -static void dynticks_rearm_timer(struct qemu_alarm_timer *t); - -static int hpet_start_timer(struct qemu_alarm_timer *t); -static void hpet_stop_timer(struct qemu_alarm_timer *t); - -static int rtc_start_timer(struct qemu_alarm_timer *t); -static void rtc_stop_timer(struct qemu_alarm_timer *t); - -#endif /* __linux__ */ - -#endif /* _WIN32 */ - -/* Correlation between real and virtual time is always going to be - fairly approximate, so ignore small variation. - When the guest is idle real and virtual time will be aligned in - the IO wait loop. */ -#define ICOUNT_WOBBLE (get_ticks_per_sec() / 10) - -static void icount_adjust(void) -{ - int64_t cur_time; - int64_t cur_icount; - int64_t delta; - static int64_t last_delta; - /* If the VM is not running, then do nothing. */ - if (!vm_running) - return; - - cur_time = cpu_get_clock(); - cur_icount = qemu_get_clock(vm_clock); - delta = cur_icount - cur_time; - /* FIXME: This is a very crude algorithm, somewhat prone to oscillation. */ - if (delta > 0 - && last_delta + ICOUNT_WOBBLE < delta * 2 - && icount_time_shift > 0) { - /* The guest is getting too far ahead. Slow time down. */ - icount_time_shift--; - } - if (delta < 0 - && last_delta - ICOUNT_WOBBLE > delta * 2 - && icount_time_shift < MAX_ICOUNT_SHIFT) { - /* The guest is getting too far behind. Speed time up. */ - icount_time_shift++; - } - last_delta = delta; - qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift); -} - -static void icount_adjust_rt(void * opaque) -{ - qemu_mod_timer(icount_rt_timer, - qemu_get_clock(rt_clock) + 1000); - icount_adjust(); -} - -static void icount_adjust_vm(void * opaque) -{ - qemu_mod_timer(icount_vm_timer, - qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10); - icount_adjust(); -} - -static void init_icount_adjust(void) -{ - /* Have both realtime and virtual time triggers for speed adjustment. - The realtime trigger catches emulated time passing too slowly, - the virtual time trigger catches emulated time passing too fast. - Realtime triggers occur even when idle, so use them less frequently - than VM triggers. */ - icount_rt_timer = qemu_new_timer(rt_clock, icount_adjust_rt, NULL); - qemu_mod_timer(icount_rt_timer, - qemu_get_clock(rt_clock) + 1000); - icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL); - qemu_mod_timer(icount_vm_timer, - qemu_get_clock(vm_clock) + get_ticks_per_sec() / 10); -} - -static struct qemu_alarm_timer alarm_timers[] = { -#ifndef _WIN32 -#ifdef __linux__ - {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer, - dynticks_stop_timer, dynticks_rearm_timer, NULL}, - /* HPET - if available - is preferred */ - {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL}, - /* ...otherwise try RTC */ - {"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL}, -#endif - {"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL}, -#else - {"dynticks", ALARM_FLAG_DYNTICKS, win32_start_timer, - win32_stop_timer, win32_rearm_timer, &alarm_win32_data}, - {"win32", 0, win32_start_timer, - win32_stop_timer, NULL, &alarm_win32_data}, -#endif - {NULL, } -}; - -static void show_available_alarms(void) -{ - int i; - - printf("Available alarm timers, in order of precedence:\n"); - for (i = 0; alarm_timers[i].name; i++) - printf("%s\n", alarm_timers[i].name); -} - -static void configure_alarms(char const *opt) -{ - int i; - int cur = 0; - int count = ARRAY_SIZE(alarm_timers) - 1; - char *arg; - char *name; - struct qemu_alarm_timer tmp; - - if (!strcmp(opt, "?")) { - show_available_alarms(); - exit(0); - } - - arg = qemu_strdup(opt); - - /* Reorder the array */ - name = strtok(arg, ","); - while (name) { - for (i = 0; i < count && alarm_timers[i].name; i++) { - if (!strcmp(alarm_timers[i].name, name)) - break; - } - - if (i == count) { - fprintf(stderr, "Unknown clock %s\n", name); - goto next; - } - - if (i < cur) - /* Ignore */ - goto next; - - /* Swap */ - tmp = alarm_timers[i]; - alarm_timers[i] = alarm_timers[cur]; - alarm_timers[cur] = tmp; - - cur++; -next: - name = strtok(NULL, ","); - } - - qemu_free(arg); - - if (cur) { - /* Disable remaining timers */ - for (i = cur; i < count; i++) - alarm_timers[i].name = NULL; - } else { - show_available_alarms(); - exit(1); - } -} - -#define QEMU_NUM_CLOCKS 3 - -QEMUClock *rt_clock; -QEMUClock *vm_clock; -QEMUClock *host_clock; - -static QEMUTimer *active_timers[QEMU_NUM_CLOCKS]; - -static QEMUClock *qemu_new_clock(int type) -{ - QEMUClock *clock; - clock = qemu_mallocz(sizeof(QEMUClock)); - clock->type = type; - return clock; -} - -QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque) -{ - QEMUTimer *ts; - - ts = qemu_mallocz(sizeof(QEMUTimer)); - ts->clock = clock; - ts->cb = cb; - ts->opaque = opaque; - return ts; -} - -void qemu_free_timer(QEMUTimer *ts) -{ - qemu_free(ts); -} - -/* stop a timer, but do not dealloc it */ -void qemu_del_timer(QEMUTimer *ts) -{ - QEMUTimer **pt, *t; - - /* NOTE: this code must be signal safe because - qemu_timer_expired() can be called from a signal. */ - pt = &active_timers[ts->clock->type]; - for(;;) { - t = *pt; - if (!t) - break; - if (t == ts) { - *pt = t->next; - break; - } - pt = &t->next; - } -} - -/* modify the current timer so that it will be fired when current_time - >= expire_time. The corresponding callback will be called. */ -void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) -{ - QEMUTimer **pt, *t; - - qemu_del_timer(ts); - - /* add the timer in the sorted list */ - /* NOTE: this code must be signal safe because - qemu_timer_expired() can be called from a signal. */ - pt = &active_timers[ts->clock->type]; - for(;;) { - t = *pt; - if (!t) - break; - if (t->expire_time > expire_time) - break; - pt = &t->next; - } - ts->expire_time = expire_time; - ts->next = *pt; - *pt = ts; - - /* Rearm if necessary */ - if (pt == &active_timers[ts->clock->type]) { - if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0) { - qemu_rearm_alarm_timer(alarm_timer); - } - /* Interrupt execution to force deadline recalculation. */ - if (use_icount) - qemu_notify_event(); - } -} - -int qemu_timer_pending(QEMUTimer *ts) -{ - QEMUTimer *t; - for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) { - if (t == ts) - return 1; - } - return 0; -} - -int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) -{ - if (!timer_head) - return 0; - return (timer_head->expire_time <= current_time); -} - -static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time) -{ - QEMUTimer *ts; - - for(;;) { - ts = *ptimer_head; - if (!ts || ts->expire_time > current_time) - break; - /* remove timer from the list before calling the callback */ - *ptimer_head = ts->next; - ts->next = NULL; - - /* run the callback (the timer list can be modified) */ - ts->cb(ts->opaque); - } -} - -int64_t qemu_get_clock(QEMUClock *clock) -{ - switch(clock->type) { - case QEMU_CLOCK_REALTIME: - return get_clock() / 1000000; - default: - case QEMU_CLOCK_VIRTUAL: - if (use_icount) { - return cpu_get_icount(); - } else { - return cpu_get_clock(); - } - case QEMU_CLOCK_HOST: - return get_clock_realtime(); - } -} - -int64_t qemu_get_clock_ns(QEMUClock *clock) -{ - switch(clock->type) { - case QEMU_CLOCK_REALTIME: - return get_clock(); - default: - case QEMU_CLOCK_VIRTUAL: - if (use_icount) { - return cpu_get_icount(); - } else { - return cpu_get_clock(); - } - case QEMU_CLOCK_HOST: - return get_clock_realtime(); - } -} - -static void init_clocks(void) -{ - init_get_clock(); - rt_clock = qemu_new_clock(QEMU_CLOCK_REALTIME); - vm_clock = qemu_new_clock(QEMU_CLOCK_VIRTUAL); - host_clock = qemu_new_clock(QEMU_CLOCK_HOST); - - rtc_clock = host_clock; -} - -/* save a timer */ -void qemu_put_timer(QEMUFile *f, QEMUTimer *ts) -{ - uint64_t expire_time; - - if (qemu_timer_pending(ts)) { - expire_time = ts->expire_time; - } else { - expire_time = -1; - } - qemu_put_be64(f, expire_time); -} - -void qemu_get_timer(QEMUFile *f, QEMUTimer *ts) -{ - uint64_t expire_time; - - expire_time = qemu_get_be64(f); - if (expire_time != -1) { - qemu_mod_timer(ts, expire_time); - } else { - qemu_del_timer(ts); - } -} - -static const VMStateDescription vmstate_timers = { - .name = "timer", - .version_id = 2, - .minimum_version_id = 1, - .minimum_version_id_old = 1, - .fields = (VMStateField []) { - VMSTATE_INT64(cpu_ticks_offset, TimersState), - VMSTATE_INT64(dummy, TimersState), - VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2), - VMSTATE_END_OF_LIST() - } -}; - -static void qemu_event_increment(void); - -#ifdef _WIN32 -static void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, - DWORD_PTR dwUser, DWORD_PTR dw1, - DWORD_PTR dw2) -#else -static void host_alarm_handler(int host_signum) -#endif -{ -#if 0 -#define DISP_FREQ 1000 - { - static int64_t delta_min = INT64_MAX; - static int64_t delta_max, delta_cum, last_clock, delta, ti; - static int count; - ti = qemu_get_clock(vm_clock); - if (last_clock != 0) { - delta = ti - last_clock; - if (delta < delta_min) - delta_min = delta; - if (delta > delta_max) - delta_max = delta; - delta_cum += delta; - if (++count == DISP_FREQ) { - printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n", - muldiv64(delta_min, 1000000, get_ticks_per_sec()), - muldiv64(delta_max, 1000000, get_ticks_per_sec()), - muldiv64(delta_cum, 1000000 / DISP_FREQ, get_ticks_per_sec()), - (double)get_ticks_per_sec() / ((double)delta_cum / DISP_FREQ)); - count = 0; - delta_min = INT64_MAX; - delta_max = 0; - delta_cum = 0; - } - } - last_clock = ti; - } -#endif - if (alarm_has_dynticks(alarm_timer) || - (!use_icount && - qemu_timer_expired(active_timers[QEMU_CLOCK_VIRTUAL], - qemu_get_clock(vm_clock))) || - qemu_timer_expired(active_timers[QEMU_CLOCK_REALTIME], - qemu_get_clock(rt_clock)) || - qemu_timer_expired(active_timers[QEMU_CLOCK_HOST], - qemu_get_clock(host_clock))) { - qemu_event_increment(); - if (alarm_timer) alarm_timer->flags |= ALARM_FLAG_EXPIRED; - -#ifndef CONFIG_IOTHREAD - if (next_cpu) { - /* stop the currently executing cpu because a timer occured */ - cpu_exit(next_cpu); - } -#endif - timer_alarm_pending = 1; - qemu_notify_event(); - } -} - -static int64_t qemu_next_deadline(void) -{ - /* To avoid problems with overflow limit this to 2^32. */ - int64_t delta = INT32_MAX; - - if (active_timers[QEMU_CLOCK_VIRTUAL]) { - delta = active_timers[QEMU_CLOCK_VIRTUAL]->expire_time - - qemu_get_clock(vm_clock); - } - if (active_timers[QEMU_CLOCK_HOST]) { - int64_t hdelta = active_timers[QEMU_CLOCK_HOST]->expire_time - - qemu_get_clock(host_clock); - if (hdelta < delta) - delta = hdelta; - } - - if (delta < 0) - delta = 0; - - return delta; -} - -#if defined(__linux__) -static uint64_t qemu_next_deadline_dyntick(void) -{ - int64_t delta; - int64_t rtdelta; - - if (use_icount) - delta = INT32_MAX; - else - delta = (qemu_next_deadline() + 999) / 1000; - - if (active_timers[QEMU_CLOCK_REALTIME]) { - rtdelta = (active_timers[QEMU_CLOCK_REALTIME]->expire_time - - qemu_get_clock(rt_clock))*1000; - if (rtdelta < delta) - delta = rtdelta; - } - - if (delta < MIN_TIMER_REARM_US) - delta = MIN_TIMER_REARM_US; - - return delta; -} -#endif - -#ifndef _WIN32 - -/* Sets a specific flag */ -static int fcntl_setfl(int fd, int flag) -{ - int flags; - - flags = fcntl(fd, F_GETFL); - if (flags == -1) - return -errno; - - if (fcntl(fd, F_SETFL, flags | flag) == -1) - return -errno; - - return 0; -} - -#if defined(__linux__) - -#define RTC_FREQ 1024 - -static void enable_sigio_timer(int fd) -{ - struct sigaction act; - - /* timer signal */ - sigfillset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = host_alarm_handler; - - sigaction(SIGIO, &act, NULL); - fcntl_setfl(fd, O_ASYNC); - fcntl(fd, F_SETOWN, getpid()); -} - -static int hpet_start_timer(struct qemu_alarm_timer *t) -{ - struct hpet_info info; - int r, fd; - - fd = qemu_open("/dev/hpet", O_RDONLY); - if (fd < 0) - return -1; - - /* Set frequency */ - r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ); - if (r < 0) { - fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n" - "error, but for better emulation accuracy type:\n" - "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n"); - goto fail; - } - - /* Check capabilities */ - r = ioctl(fd, HPET_INFO, &info); - if (r < 0) - goto fail; - - /* Enable periodic mode */ - r = ioctl(fd, HPET_EPI, 0); - if (info.hi_flags && (r < 0)) - goto fail; - - /* Enable interrupt */ - r = ioctl(fd, HPET_IE_ON, 0); - if (r < 0) - goto fail; - - enable_sigio_timer(fd); - t->priv = (void *)(long)fd; - - return 0; -fail: - close(fd); - return -1; -} - -static void hpet_stop_timer(struct qemu_alarm_timer *t) -{ - int fd = (long)t->priv; - - close(fd); -} - -static int rtc_start_timer(struct qemu_alarm_timer *t) -{ - int rtc_fd; - unsigned long current_rtc_freq = 0; - - TFR(rtc_fd = qemu_open("/dev/rtc", O_RDONLY)); - if (rtc_fd < 0) - return -1; - ioctl(rtc_fd, RTC_IRQP_READ, ¤t_rtc_freq); - if (current_rtc_freq != RTC_FREQ && - ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) { - fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n" - "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n" - "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n"); - goto fail; - } - if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) { - fail: - close(rtc_fd); - return -1; - } - - enable_sigio_timer(rtc_fd); - - t->priv = (void *)(long)rtc_fd; - - return 0; -} - -static void rtc_stop_timer(struct qemu_alarm_timer *t) -{ - int rtc_fd = (long)t->priv; - - close(rtc_fd); -} - -static int dynticks_start_timer(struct qemu_alarm_timer *t) -{ - struct sigevent ev; - timer_t host_timer; - struct sigaction act; - - sigfillset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = host_alarm_handler; - - sigaction(SIGALRM, &act, NULL); - - /* - * Initialize ev struct to 0 to avoid valgrind complaining - * about uninitialized data in timer_create call - */ - memset(&ev, 0, sizeof(ev)); - ev.sigev_value.sival_int = 0; - ev.sigev_notify = SIGEV_SIGNAL; - ev.sigev_signo = SIGALRM; - - if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) { - perror("timer_create"); - - /* disable dynticks */ - fprintf(stderr, "Dynamic Ticks disabled\n"); - - return -1; - } - - t->priv = (void *)(long)host_timer; - - return 0; -} - -static void dynticks_stop_timer(struct qemu_alarm_timer *t) -{ - timer_t host_timer = (timer_t)(long)t->priv; - - timer_delete(host_timer); -} - -static void dynticks_rearm_timer(struct qemu_alarm_timer *t) -{ - timer_t host_timer = (timer_t)(long)t->priv; - struct itimerspec timeout; - int64_t nearest_delta_us = INT64_MAX; - int64_t current_us; - - if (!active_timers[QEMU_CLOCK_REALTIME] && - !active_timers[QEMU_CLOCK_VIRTUAL] && - !active_timers[QEMU_CLOCK_HOST]) - return; - - nearest_delta_us = qemu_next_deadline_dyntick(); - - /* check whether a timer is already running */ - if (timer_gettime(host_timer, &timeout)) { - perror("gettime"); - fprintf(stderr, "Internal timer error: aborting\n"); - exit(1); - } - current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000; - if (current_us && current_us <= nearest_delta_us) - return; - - timeout.it_interval.tv_sec = 0; - timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */ - timeout.it_value.tv_sec = nearest_delta_us / 1000000; - timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000; - if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) { - perror("settime"); - fprintf(stderr, "Internal timer error: aborting\n"); - exit(1); - } -} - -#endif /* defined(__linux__) */ - -static int unix_start_timer(struct qemu_alarm_timer *t) -{ - struct sigaction act; - struct itimerval itv; - int err; - - /* timer signal */ - sigfillset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = host_alarm_handler; - - sigaction(SIGALRM, &act, NULL); - - itv.it_interval.tv_sec = 0; - /* for i386 kernel 2.6 to get 1 ms */ - itv.it_interval.tv_usec = 999; - itv.it_value.tv_sec = 0; - itv.it_value.tv_usec = 10 * 1000; - - err = setitimer(ITIMER_REAL, &itv, NULL); - if (err) - return -1; - - return 0; -} - -static void unix_stop_timer(struct qemu_alarm_timer *t) -{ - struct itimerval itv; - - memset(&itv, 0, sizeof(itv)); - setitimer(ITIMER_REAL, &itv, NULL); -} - -#endif /* !defined(_WIN32) */ - - -#ifdef _WIN32 - -static int win32_start_timer(struct qemu_alarm_timer *t) -{ - TIMECAPS tc; - struct qemu_alarm_win32 *data = t->priv; - UINT flags; - - memset(&tc, 0, sizeof(tc)); - timeGetDevCaps(&tc, sizeof(tc)); - - if (data->period < tc.wPeriodMin) - data->period = tc.wPeriodMin; - - timeBeginPeriod(data->period); - - flags = TIME_CALLBACK_FUNCTION; - if (alarm_has_dynticks(t)) - flags |= TIME_ONESHOT; - else - flags |= TIME_PERIODIC; - - data->timerId = timeSetEvent(1, // interval (ms) - data->period, // resolution - host_alarm_handler, // function - (DWORD)t, // parameter - flags); - - if (!data->timerId) { - fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n", - GetLastError()); - timeEndPeriod(data->period); - return -1; - } - - return 0; -} - -static void win32_stop_timer(struct qemu_alarm_timer *t) -{ - struct qemu_alarm_win32 *data = t->priv; - - timeKillEvent(data->timerId); - timeEndPeriod(data->period); -} - -static void win32_rearm_timer(struct qemu_alarm_timer *t) -{ - struct qemu_alarm_win32 *data = t->priv; - - if (!active_timers[QEMU_CLOCK_REALTIME] && - !active_timers[QEMU_CLOCK_VIRTUAL] && - !active_timers[QEMU_CLOCK_HOST]) - return; - - timeKillEvent(data->timerId); - - data->timerId = timeSetEvent(1, - data->period, - host_alarm_handler, - (DWORD)t, - TIME_ONESHOT | TIME_PERIODIC); - - if (!data->timerId) { - fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n", - GetLastError()); - - timeEndPeriod(data->period); - exit(1); - } -} - -#endif /* _WIN32 */ - -static int init_timer_alarm(void) -{ - struct qemu_alarm_timer *t = NULL; - int i, err = -1; - - for (i = 0; alarm_timers[i].name; i++) { - t = &alarm_timers[i]; - - err = t->start(t); - if (!err) - break; - } - - if (err) { - err = -ENOENT; - goto fail; - } - - alarm_timer = t; - - return 0; - -fail: - return err; -} - -static void quit_timers(void) -{ - alarm_timer->stop(alarm_timer); - alarm_timer = NULL; -} - /***********************************************************/ /* host time/date access */ void qemu_get_timedate(struct tm *tm, int offset) @@ -3612,7 +2571,7 @@ void vm_start(void) cpu_enable_ticks(); vm_running = 1; vm_state_notify(1, 0); - qemu_rearm_alarm_timer(alarm_timer); + //qemu_rearm_alarm_timer(alarm_timer); resume_all_vcpus(); } } @@ -4316,6 +3275,7 @@ void main_loop_wait(int timeout) } #endif +#if 0 /* rearm timer, if not periodic */ if (alarm_timer->flags & ALARM_FLAG_EXPIRED) { alarm_timer->flags &= ~ALARM_FLAG_EXPIRED; @@ -4335,6 +3295,8 @@ void main_loop_wait(int timeout) qemu_run_timers(&active_timers[QEMU_CLOCK_HOST], qemu_get_clock(host_clock)); +#endif + qemu_run_all_timers(); /* Check bottom-halves last in case any of the earlier events triggered them. */ @@ -4431,58 +3393,6 @@ static int tcg_has_work(void) return 0; } -static int qemu_calculate_timeout(void) -{ -#ifndef CONFIG_IOTHREAD - int timeout; - - if (!vm_running) - timeout = 5000; - else if (tcg_has_work()) - timeout = 0; - else if (!use_icount) - timeout = 5000; - else { - /* XXX: use timeout computed from timers */ - int64_t add; - int64_t delta; - /* Advance virtual time to the next event. */ - if (use_icount == 1) { - /* When not using an adaptive execution frequency - we tend to get badly out of sync with real time, - so just delay for a reasonable amount of time. */ - delta = 0; - } else { - delta = cpu_get_icount() - cpu_get_clock(); - } - if (delta > 0) { - /* If virtual time is ahead of real time then just - wait for IO. */ - timeout = (delta / 1000000) + 1; - } else { - /* Wait for either IO to occur or the next - timer event. */ - add = qemu_next_deadline(); - /* We advance the timer before checking for IO. - Limit the amount we advance so that early IO - activity won't get the guest too far ahead. */ - if (add > 10000000) - add = 10000000; - delta += add; - add = (add + (1 << icount_time_shift) - 1) - >> icount_time_shift; - qemu_icount += add; - timeout = delta / 1000000; - if (timeout < 0) - timeout = 0; - } - } - - return timeout; -#else /* CONFIG_IOTHREAD */ - return 1000; -#endif -} static int vm_can_run(void) { @@ -4980,6 +3890,7 @@ int main(int argc, char **argv, char **envp) uint32_t boot_devices_bitmap = 0; int i; int snapshot, linux_boot, net_boot; + const char *icount_option = NULL; const char *initrd_filename; const char *kernel_filename, *kernel_cmdline; const char *boot_devices = ""; @@ -5711,12 +4622,7 @@ int main(int argc, char **argv, char **envp) tb_size = 0; break; case QEMU_OPTION_icount: - use_icount = 1; - if (strcmp(optarg, "auto") == 0) { - icount_time_shift = -1; - } else { - icount_time_shift = strtol(optarg, NULL, 0); - } + icount_option = optarg; break; case QEMU_OPTION_incoming: incoming = optarg; @@ -5864,13 +4770,7 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "could not initialize alarm timer\n"); exit(1); } - if (use_icount && icount_time_shift < 0) { - use_icount = 2; - /* 125MIPS seems a reasonable initial guess at the guest speed. - It will be corrected fairly quickly anyway. */ - icount_time_shift = 3; - init_icount_adjust(); - } + configure_icount(icount_option); #ifdef _WIN32 socket_init(); @@ -5973,7 +4873,7 @@ int main(int argc, char **argv, char **envp) if (drive_init(&drives_opt[i], snapshot, machine) == -1) exit(1); - register_savevm("timer", 0, 2, timer_save, timer_load, NULL); + //register_savevm("timer", 0, 2, timer_save, timer_load, NULL); register_savevm_live("ram", 0, 3, ram_save_live, NULL, ram_load, NULL); #ifndef _WIN32 |