Compile qemu-timer only once

Arrange various declarations so that also non-CPU code can access
them, adjust users.

Move CPU specific code to cpus.c.

Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
Blue Swirl 2010-03-29 19:24:00 +00:00
parent 5c4532ee78
commit 29e922b61f
13 changed files with 197 additions and 185 deletions

View file

@ -105,6 +105,7 @@ common-obj-$(CONFIG_VNC_SASL) += vnc-auth-sasl.o
common-obj-$(CONFIG_COCOA) += cocoa.o common-obj-$(CONFIG_COCOA) += cocoa.o
common-obj-$(CONFIG_IOTHREAD) += qemu-thread.o common-obj-$(CONFIG_IOTHREAD) += qemu-thread.o
common-obj-y += notify.o common-obj-y += notify.o
common-obj-y += qemu-timer.o
slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o slirp-obj-y = cksum.o if.o ip_icmp.o ip_input.o ip_output.o
slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o slirp-obj-y += slirp.o mbuf.o misc.o sbuf.o socket.o tcp_input.o tcp_output.o

View file

@ -162,7 +162,6 @@ endif #CONFIG_BSD_USER
ifdef CONFIG_SOFTMMU ifdef CONFIG_SOFTMMU
obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o
obj-y += qemu-timer.o
# virtio has to be here due to weird dependency between PCI and virtio-net. # virtio has to be here due to weird dependency between PCI and virtio-net.
# need to fix this properly # need to fix this properly
obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o

147
cpu-all.h
View file

@ -771,10 +771,6 @@ void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...)
extern CPUState *first_cpu; extern CPUState *first_cpu;
extern CPUState *cpu_single_env; extern CPUState *cpu_single_env;
int64_t qemu_icount_round(int64_t count);
extern int64_t qemu_icount;
extern int use_icount;
#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ #define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */
#define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */ #define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */
#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */ #define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */
@ -921,149 +917,6 @@ void dump_exec_info(FILE *f,
int cpu_memory_rw_debug(CPUState *env, target_ulong addr, int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
uint8_t *buf, int len, int is_write); uint8_t *buf, int len, int is_write);
/*******************************************/
/* 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 */ /* profiling */
#ifdef CONFIG_PROFILER #ifdef CONFIG_PROFILER
static inline int64_t profile_getclock(void) static inline int64_t profile_getclock(void)

16
cpus.c
View file

@ -771,3 +771,19 @@ void set_cpu_log(const char *optarg)
} }
cpu_set_log(mask); cpu_set_log(mask);
} }
/* 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);
}

View file

@ -337,20 +337,6 @@ static inline tb_page_addr_t get_page_addr_code(CPUState *env1, target_ulong add
+ env1->tlb_table[mmu_idx][page_index].addend; + env1->tlb_table[mmu_idx][page_index].addend;
return qemu_ram_addr_from_host(p); return qemu_ram_addr_from_host(p);
} }
/* 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 #endif
typedef void (CPUDebugExcpHandler)(CPUState *env); typedef void (CPUDebugExcpHandler)(CPUState *env);

1
exec.c
View file

@ -38,6 +38,7 @@
#include "hw/hw.h" #include "hw/hw.h"
#include "osdep.h" #include "osdep.h"
#include "kvm.h" #include "kvm.h"
#include "qemu-timer.h"
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
#include <qemu.h> #include <qemu.h>
#include <signal.h> #include <signal.h>

View file

@ -1,3 +1,5 @@
#include "qemu-timer.h"
/* Helpers for instruction counting code generation. */ /* Helpers for instruction counting code generation. */
static TCGArg *icount_arg; static TCGArg *icount_arg;

View file

@ -32,7 +32,7 @@
/* For tb_lock */ /* For tb_lock */
#include "exec-all.h" #include "exec-all.h"
#include "qemu-timer.h"
#include "envlist.h" #include "envlist.h"
#define DEBUG_LOGFILE "/tmp/qemu.log" #define DEBUG_LOGFILE "/tmp/qemu.log"

View file

@ -13,6 +13,10 @@
#define QEMU_BUILD_BUG_ON(x) typedef char __build_bug_on__##__LINE__[(x)?-1:1]; #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;
/* Hack around the mess dyngen-exec.h causes: We need QEMU_NORETURN in files that /* 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 cannot include the following headers without conflicts. This condition has
to be removed once dyngen is gone. */ to be removed once dyngen is gone. */
@ -96,8 +100,6 @@ static inline char *realpath(const char *path, char *resolved_path)
#endif /* !defined(NEED_CPU_H) */ #endif /* !defined(NEED_CPU_H) */
/* bottom halves */ /* bottom halves */
typedef struct QEMUBH QEMUBH;
typedef void QEMUBHFunc(void *opaque); typedef void QEMUBHFunc(void *opaque);
void async_context_push(void); void async_context_push(void);
@ -211,11 +213,9 @@ typedef struct CharDriverState CharDriverState;
typedef struct MACAddr MACAddr; typedef struct MACAddr MACAddr;
typedef struct VLANState VLANState; typedef struct VLANState VLANState;
typedef struct VLANClientState VLANClientState; typedef struct VLANClientState VLANClientState;
typedef struct QEMUFile QEMUFile;
typedef struct i2c_bus i2c_bus; typedef struct i2c_bus i2c_bus;
typedef struct i2c_slave i2c_slave; typedef struct i2c_slave i2c_slave;
typedef struct SMBusDevice SMBusDevice; typedef struct SMBusDevice SMBusDevice;
typedef struct QEMUTimer QEMUTimer;
typedef struct PCIHostState PCIHostState; typedef struct PCIHostState PCIHostState;
typedef struct PCIExpressHost PCIExpressHost; typedef struct PCIExpressHost PCIExpressHost;
typedef struct PCIBus PCIBus; typedef struct PCIBus PCIBus;

View file

@ -53,16 +53,14 @@
#include <mmsystem.h> #include <mmsystem.h>
#endif #endif
#include "cpu-defs.h"
#include "qemu-timer.h" #include "qemu-timer.h"
#include "exec-all.h"
/* Conversion factor from emulated instructions to virtual clock ticks. */ /* Conversion factor from emulated instructions to virtual clock ticks. */
static int icount_time_shift; int icount_time_shift;
/* Arbitrarily pick 1MIPS as the minimum allowable speed. */ /* Arbitrarily pick 1MIPS as the minimum allowable speed. */
#define MAX_ICOUNT_SHIFT 10 #define MAX_ICOUNT_SHIFT 10
/* Compensate for varying guest execution speed. */ /* Compensate for varying guest execution speed. */
static int64_t qemu_icount_bias; int64_t qemu_icount_bias;
static QEMUTimer *icount_rt_timer; static QEMUTimer *icount_rt_timer;
static QEMUTimer *icount_vm_timer; static QEMUTimer *icount_vm_timer;
@ -138,20 +136,6 @@ static int64_t get_clock(void)
} }
#endif #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 */ /* guest cycle counter */

View file

@ -1,6 +1,8 @@
#ifndef QEMU_TIMER_H #ifndef QEMU_TIMER_H
#define QEMU_TIMER_H #define QEMU_TIMER_H
#include "qemu-common.h"
/* timers */ /* timers */
typedef struct QEMUClock QEMUClock; typedef struct QEMUClock QEMUClock;
@ -69,4 +71,169 @@ void ptimer_stop(ptimer_state *s);
void qemu_put_ptimer(QEMUFile *f, ptimer_state *s); void qemu_put_ptimer(QEMUFile *f, ptimer_state *s);
void qemu_get_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__ ("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
#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
#endif #endif

View file

@ -16,6 +16,8 @@
* You should have received a copy of the GNU Lesser General Public * 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/>. * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/ */
#include "qemu-timer.h"
#define DATA_SIZE (1 << SHIFT) #define DATA_SIZE (1 << SHIFT)
#if DATA_SIZE == 8 #if DATA_SIZE == 8

View file

@ -29,6 +29,7 @@
#include "exec-all.h" #include "exec-all.h"
#include "disas.h" #include "disas.h"
#include "tcg.h" #include "tcg.h"
#include "qemu-timer.h"
/* code generation context */ /* code generation context */
TCGContext tcg_ctx; TCGContext tcg_ctx;