[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 0/32] New shot at accelerators
From: |
Glauber Costa |
Subject: |
[Qemu-devel] [PATCH 0/32] New shot at accelerators |
Date: |
Thu, 23 Oct 2008 12:18:44 -0200 |
Hi guys,
I'm sending here a new version of the accel patch. It comprises
the cleaned up version I've last sent, plus a few additions
You may want to pay special attention to the additions, since
they are newcomers to the series. To ease your job, they are:
0001-use-anonymous-memory-for-kqemu.patch
0002-protect-exec-all.h-frm-multiple-inclusion.patch
0003-change-definition-of-FILE-for-linux.patch
0005-use-more-meaningful-values-for-kqemu_cpu_exec.patch
0025-provide-accel-hook-for-cpu_exec.patch
0026-provide-two-accelerators-for-kqemu.patch
0027-arch-specific-hooks-for-accelerator.patch
0028-iret-arch-specific-accelerator.patch
0029-sysret-sysexit-arch-specific-accelerator.patch
0030-lcall-lret-arch-specific-accel-hooks.patch
0031-remove-kqemu_is_ok-tests.patch
0032-clean-up-kqemu-code.patch
git users can get a snapshot of it located at
git://git.kernel.org/pub/scm/virt/glommer/qemu-accel.git accel-v2
diffstat and OBP (One Big Patch ;-)) attached.
------
Makefile.target | 2 +-
accel.c | 51 +++++++++
accel.h | 171 ++++++++++++++++++++++++++++
cpu-all.h | 9 +-
cpu-exec.c | 47 +++-----
dyngen-exec.h | 6 +
exec-all.h | 34 +-----
exec.c | 115 ++++++++++----------
hw/pc.c | 13 +--
kqemu.c | 284 +++++++++++++++++++++++++++++++++++++++++++----
kqemu.h | 21 ++++
monitor.c | 70 +++++-------
osdep.c | 111 ------------------
softmmu_template.h | 10 +-
sysemu.h | 5 -
target-i386/accel86.h | 60 ++++++++++
target-i386/cpu.h | 13 --
target-i386/helper.c | 8 +-
target-i386/op_helper.c | 52 ++-------
vl.c | 93 ++++++----------
20 files changed, 736 insertions(+), 439 deletions(-)
diff --git a/Makefile.target b/Makefile.target
index e2edf9d..623ecd8 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -188,7 +188,7 @@ all: $(PROGS)
#########################################################
# cpu emulator library
LIBOBJS=exec.o kqemu.o translate-all.o cpu-exec.o\
- translate.o host-utils.o
+ translate.o host-utils.o accel.o
ifdef CONFIG_DYNGEN_OP
exec.o: dyngen-opc.h
LIBOBJS+=op.o
diff --git a/accel.c b/accel.c
new file mode 100644
index 0000000..8d635f0
--- /dev/null
+++ b/accel.c
@@ -0,0 +1,51 @@
+#include "hw/hw.h"
+#include "exec-all.h"
+#include "accel.h"
+
+QEMUAccel *current_accel;
+QEMUCont *head = NULL;
+
+int _accel_nop(void)
+{
+ return 0;
+}
+
+int noaccel_info(CPUState *env, char *buf)
+{
+ return snprintf(buf, MAX_INFO_BUF, "no accelerator present.\n");
+}
+
+CPUState *noaccel_get_env(void)
+{
+ return qemu_mallocz(sizeof(CPUState));
+}
+
+int noaccel_cpu_exec(CPUState *env)
+{
+ return EXEC_EXIT_SOFTMMU;
+}
+
+#define accel_nop ((void *)_accel_nop)
+
+/* Accelerator wrapper for the no-accel (raw qemu) case */
+QEMUAccel noaccel = {
+ .name = "none",
+ .cpu_interrupt = accel_nop,
+ .init_env = accel_nop,
+ .get_env = noaccel_get_env,
+ .start = accel_nop,
+ .flush_cache = accel_nop,
+ .flush_page = accel_nop,
+ .info = noaccel_info,
+ .profile = accel_nop,
+ .set_notdirty = accel_nop,
+ .modify_page = accel_nop,
+#ifndef CONFIG_USER_ONLY
+ .get_real_ticks = cpu_get_ticks,
+#endif
+ .register_physical_memory = accel_nop,
+ .trace_io = accel_nop,
+ .break_loop = accel_nop,
+ .cpu_exec = noaccel_cpu_exec,
+};
+
diff --git a/accel.h b/accel.h
new file mode 100644
index 0000000..00a495c
--- /dev/null
+++ b/accel.h
@@ -0,0 +1,171 @@
+#ifndef _ACCEL_H_
+#define _ACCEL_H_
+
+#define MAX_INFO_BUF 1024
+
+typedef struct QEMUAccel {
+ char *name;
+ void (*cpu_interrupt)(CPUState *env);
+ CPUState *(*get_env)(void);
+ void (*init_env)(CPUState *env);
+ int (*start)(int cpus);
+ void (*flush_cache)(CPUState *env, int global);
+ void (*flush_page)(CPUState *env, target_ulong addr);
+ int (*info)(CPUState *env, char *buf);
+ int (*profile)(CPUState *env, char *buf);
+ void (*set_notdirty)(ram_addr_t addr);
+ void (*modify_page)(ram_addr_t addr, int dirty_flags);
+#ifndef CONFIG_USER_ONLY
+ uint64_t (*get_real_ticks)(void);
+#endif
+ void (*register_physical_memory)(uint64_t start_addr,
+ ram_addr_t size, ram_addr_t phys_offset);
+ void (*trace_io)(CPUState *env);
+ int (*break_loop)(CPUState *env);
+ int (*cpu_exec)(CPUState *env);
+ void *arch; /* arch-specific accel functions */
+} QEMUAccel;
+
+typedef struct QEMUCont {
+ QEMUAccel *acc;
+ int active;
+ struct QEMUCont *next;
+} QEMUCont;
+
+extern QEMUAccel *current_accel;
+extern QEMUAccel noaccel;
+#ifdef USE_KQEMU
+extern QEMUAccel kqemu_accel;
+extern QEMUAccel kqemu_kernel_accel;
+#endif
+
+extern QEMUCont *head;
+void *qemu_mallocz(size_t size);
+extern CPUState *noaccel_get_env(void);
+
+static inline int register_qemu_accel(QEMUAccel *accel)
+{
+ QEMUCont *new, *tmp, *last = NULL;
+
+ for (tmp = head, last; tmp; tmp = tmp->next) {
+ /* we disallow registering the same accelerator twice */
+ if (tmp->acc == accel)
+ return -1;
+
+ if (!tmp->next)
+ last = tmp;
+ }
+
+ new = qemu_mallocz(sizeof(*head));
+
+ new->acc = accel;
+ new->active = 0;
+ new->next = NULL;
+
+ if (!head)
+ head = new;
+ else
+ last->next = new;
+
+ return 0;
+}
+
+static inline QEMUCont *get_accel_head(void)
+{
+ return head;
+}
+
+static inline void accel_cpu_interrupt(CPUState *env)
+{
+ current_accel->cpu_interrupt(env);
+}
+
+static inline int accel_start(int cpus)
+{
+ int status = -1;
+ /* The top accelerator in the list gets tried first, but if it fails,
+ * keep trying until one of them succeeds or we exhaust the list */
+ QEMUCont *tmp = head;
+ while (tmp) {
+ if (tmp->acc && tmp->acc->start && (!(tmp->acc->start(cpus))) ) {
+ tmp->active = 1;
+ current_accel = tmp->acc;
+ status = 0;
+ break;
+ }
+ tmp = tmp->next;
+ }
+ return status;
+}
+
+static inline CPUState *accel_get_env(void)
+{
+ return current_accel->get_env();
+}
+
+static inline void accel_init_env(CPUState *env)
+{
+ current_accel->init_env(env);
+}
+
+static inline void accel_flush_cache(CPUState *env, int global)
+{
+ current_accel->flush_cache(env, global);
+}
+
+static inline void accel_flush_page(CPUState *env, target_ulong addr)
+{
+ current_accel->flush_page(env, addr);
+}
+
+static inline int accel_info(CPUState *env, char *buf)
+{
+ return current_accel->info(env, buf);
+}
+
+static inline int accel_profile(CPUState *env, char *buf)
+{
+ return current_accel->profile(env, buf);
+}
+
+static inline void accel_set_notdirty(target_ulong addr)
+{
+ current_accel->set_notdirty(addr);
+}
+
+static inline void accel_modify_page(target_ulong addr, int dirty_flags)
+{
+ current_accel->modify_page(addr, dirty_flags);
+}
+
+int64_t cpu_get_ticks(void);
+
+#ifndef CONFIG_USER_ONLY
+static inline uint64_t accel_get_real_ticks(void)
+{
+ return current_accel->get_real_ticks();
+}
+#endif
+
+static inline void accel_register_phys_mem(uint64_t start_addr,
+ ram_addr_t size,
+ ram_addr_t phys_offset)
+{
+ current_accel->register_physical_memory(start_addr, size, phys_offset);
+}
+
+static inline void accel_trace_io(CPUState *env)
+{
+ current_accel->trace_io(env);
+}
+
+static inline int accel_break_loop(CPUState *env)
+{
+ return current_accel->break_loop(env);
+}
+
+static inline int accel_cpu_exec(CPUState *env)
+{
+ return current_accel->cpu_exec(env);
+}
+#endif
diff --git a/cpu-all.h b/cpu-all.h
index cdd79bc..edefb45 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -863,6 +863,10 @@ extern ram_addr_t ram_size;
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr,
uint32_t value);
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
+/* this is a private version, meant for internal use of accelerators */
+void __cpu_register_physical_memory(target_phys_addr_t start_addr,
+ ram_addr_t size,
+ ram_addr_t phys_offset);
void cpu_register_physical_memory(target_phys_addr_t start_addr,
ram_addr_t size,
ram_addr_t phys_offset);
@@ -1077,14 +1081,9 @@ static inline int64_t profile_getclock(void)
return cpu_get_real_ticks();
}
-extern int64_t kqemu_time, kqemu_time_start;
extern int64_t qemu_time, qemu_time_start;
extern int64_t tlb_flush_time;
-extern int64_t kqemu_exec_count;
extern int64_t dev_time;
-extern int64_t kqemu_ret_int_count;
-extern int64_t kqemu_ret_excp_count;
-extern int64_t kqemu_ret_intr_count;
#endif
#endif /* CPU_ALL_H */
diff --git a/cpu-exec.c b/cpu-exec.c
index 6d4dcdd..a0b6055 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -36,6 +36,7 @@
#include <signal.h>
#include <sys/ucontext.h>
#endif
+#include "accel.h"
#if defined(__sparc__) && !defined(HOST_SOLARIS)
// Work around ugly bugs in glibc that mangle global register contents
@@ -335,31 +336,23 @@ int cpu_exec(CPUState *env1)
}
env->exception_index = -1;
}
-#ifdef USE_KQEMU
- if (kqemu_is_ok(env) && env->interrupt_request == 0) {
- int ret;
- env->eflags = env->eflags | cc_table[CC_OP].compute_all() |
(DF & DF_MASK);
- ret = kqemu_cpu_exec(env);
- /* put eflags in CPU temporary format */
- CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P |
CC_C);
- DF = 1 - (2 * ((env->eflags >> 10) & 1));
- CC_OP = CC_OP_EFLAGS;
- env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P |
CC_C);
- if (ret == 1) {
- /* exception */
- longjmp(env->jmp_env, 1);
- } else if (ret == 2) {
- /* softmmu execution needed */
+
+ env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF &
DF_MASK);
+ ret = accel_cpu_exec(env);
+ env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P |
CC_C);
+ if (ret == EXEC_EXIT_INTR) {
+ /* exception */
+ longjmp(env->jmp_env, 1);
+ } else if (ret == EXEC_EXIT_SOFTMMU) {
+ /* softmmu execution needed */
+ } else {
+ if (env->interrupt_request != 0) {
+ /* hardware interrupt will be executed just after */
} else {
- if (env->interrupt_request != 0) {
- /* hardware interrupt will be executed just after */
- } else {
- /* otherwise, we restart */
- longjmp(env->jmp_env, 1);
- }
+ /* otherwise, we restart */
+ longjmp(env->jmp_env, 1);
}
}
-#endif
next_tb = 0; /* force lookup of first TB */
for(;;) {
@@ -605,7 +598,7 @@ int cpu_exec(CPUState *env1)
{
if (next_tb != 0 &&
#ifdef USE_KQEMU
- (env->kqemu_enabled != 2) &&
+ (!kqemu_kernel_enabled(env)) &&
#endif
tb->page_addr[1] == -1) {
tb_add_jump((TranslationBlock *)(next_tb & ~3), next_tb &
3, tb);
@@ -653,13 +646,7 @@ int cpu_exec(CPUState *env1)
}
/* reset soft MMU for next block (it can currently
only be set by a memory fault) */
-#if defined(USE_KQEMU)
-#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
- if (kqemu_is_ok(env) &&
- (cpu_get_time_fast() - env->last_io_time) >=
MIN_CYCLE_BEFORE_SWITCH) {
- cpu_loop_exit();
- }
-#endif
+ accel_break_loop(env);
} /* for(;;) */
} else {
env_to_regs();
diff --git a/dyngen-exec.h b/dyngen-exec.h
index 9260b6f..826ff46 100644
--- a/dyngen-exec.h
+++ b/dyngen-exec.h
@@ -27,6 +27,10 @@
#define _FILEDEFED
#endif
+#ifdef __linux__
+#define __FILE_defined
+#endif
+
/* NOTE: standard headers should be used with special care at this
point because host CPU registers are used as global variables. Some
host headers do not allow that. */
@@ -84,6 +88,8 @@ typedef void * host_reg_t;
#ifdef _BSD
typedef struct __sFILE FILE;
+#elif defined(__linux__)
+typedef struct _IO_FILE FILE;
#else
typedef struct FILE FILE;
#endif
diff --git a/exec-all.h b/exec-all.h
index 6609c9a..fa4a4eb 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -18,6 +18,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#ifndef _EXEC_ALL_H_
+#define _EXEC_ALL_H_
/* allow to see translation results - the slowdown should be negligible, so we
leave it */
#define DEBUG_DISAS
@@ -354,34 +356,8 @@ static inline int can_do_io(CPUState *env)
}
#endif
-#ifdef USE_KQEMU
-#define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
-
-#define MSR_QPI_COMMBASE 0xfabe0010
-
-int kqemu_init(CPUState *env);
-int kqemu_cpu_exec(CPUState *env);
-void kqemu_flush_page(CPUState *env, target_ulong addr);
-void kqemu_flush(CPUState *env, int global);
-void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr);
-void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr);
-void kqemu_set_phys_mem(uint64_t start_addr, ram_addr_t size,
- ram_addr_t phys_offset);
-void kqemu_cpu_interrupt(CPUState *env);
-void kqemu_record_dump(void);
-
-extern uint32_t kqemu_comm_base;
-
-static inline int kqemu_is_ok(CPUState *env)
-{
- return(env->kqemu_enabled &&
- (env->cr[0] & CR0_PE_MASK) &&
- !(env->hflags & HF_INHIBIT_IRQ_MASK) &&
- (env->eflags & IF_MASK) &&
- !(env->eflags & VM_MASK) &&
- (env->kqemu_enabled == 2 ||
- ((env->hflags & HF_CPL_MASK) == 3 &&
- (env->eflags & IOPL_MASK) != IOPL_MASK)));
-}
+#define EXEC_EXIT_DONE 0
+#define EXEC_EXIT_INTR 1
+#define EXEC_EXIT_SOFTMMU 2
#endif
diff --git a/exec.c b/exec.c
index f1fcec8..7fe7eeb 100644
--- a/exec.c
+++ b/exec.c
@@ -43,6 +43,8 @@
#include <qemu.h>
#endif
+#include "accel.h"
+
//#define DEBUG_TB_INVALIDATE
//#define DEBUG_FLUSH
//#define DEBUG_TLB
@@ -524,25 +526,31 @@ static int cpu_common_load(QEMUFile *f, void *opaque, int
version_id)
}
#endif
-void cpu_exec_init(CPUState *env)
+int next_cpu_index(void)
{
CPUState **penv;
- int cpu_index;
+ int cpu_index = 0;
- env->next_cpu = NULL;
penv = &first_cpu;
- cpu_index = 0;
+
while (*penv != NULL) {
penv = (CPUState **)&(*penv)->next_cpu;
cpu_index++;
}
- env->cpu_index = cpu_index;
+ return cpu_index;
+}
+
+void cpu_exec_init(CPUState *env)
+{
+ env->next_cpu = NULL;
+ env->cpu_index = next_cpu_index();
env->nb_watchpoints = 0;
- *penv = env;
+ if (env->cpu_index == 0)
+ first_cpu = env;
#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
- register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
+ register_savevm("cpu_common", env->cpu_index, CPU_COMMON_SAVE_VERSION,
cpu_common_save, cpu_common_load, env);
- register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
+ register_savevm("cpu", env->cpu_index, CPU_SAVE_VERSION,
cpu_save, cpu_load, env);
#endif
}
@@ -1427,6 +1435,7 @@ void cpu_single_step(CPUState *env, int enabled)
tb_flush(env);
}
#endif
+ accel_cpu_interrupt(env);
}
/* enable or disable low levels log */
@@ -1678,11 +1687,8 @@ void tlb_flush(CPUState *env, int flush_global)
memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
-#ifdef USE_KQEMU
- if (env->kqemu_enabled) {
- kqemu_flush(env, flush_global);
- }
-#endif
+ accel_flush_cache(env, flush_global);
+
tlb_flush_count++;
}
@@ -1724,11 +1730,7 @@ void tlb_flush_page(CPUState *env, target_ulong addr)
tlb_flush_jmp_cache(env, addr);
-#ifdef USE_KQEMU
- if (env->kqemu_enabled) {
- kqemu_flush_page(env, addr);
- }
-#endif
+ accel_flush_page(env, addr);
}
/* update the TLBs so that writes to code in the virtual page 'addr'
@@ -1775,18 +1777,14 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start,
ram_addr_t end,
if (length == 0)
return;
len = length >> TARGET_PAGE_BITS;
-#ifdef USE_KQEMU
- /* XXX: should not depend on cpu context */
- env = first_cpu;
- if (env->kqemu_enabled) {
- ram_addr_t addr;
- addr = start;
- for(i = 0; i < len; i++) {
- kqemu_set_notdirty(env, addr);
- addr += TARGET_PAGE_SIZE;
- }
+
+ ram_addr_t addr;
+ addr = start;
+ for(i = 0; i < len; i++) {
+ accel_set_notdirty(addr);
+ addr += TARGET_PAGE_SIZE;
}
-#endif
+
mask = ~dirty_flags;
p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
for(i = 0; i < len; i++)
@@ -2191,12 +2189,13 @@ static void *subpage_init (target_phys_addr_t base,
ram_addr_t *phys,
} \
} while (0)
-/* register physical memory. 'size' must be a multiple of the target
- page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
- io memory page */
-void cpu_register_physical_memory(target_phys_addr_t start_addr,
- ram_addr_t size,
- ram_addr_t phys_offset)
+/* Use this version of cpu registering physical memory in accel-specific code.
It exists
+ * to avoid chicken and egg problems with code that might need to register
memory in qemu,
+ * but not with the underlying accelerator
+ */
+void __cpu_register_physical_memory(target_phys_addr_t start_addr,
+ ram_addr_t size,
+ ram_addr_t phys_offset)
{
target_phys_addr_t addr, end_addr;
PhysPageDesc *p;
@@ -2204,13 +2203,6 @@ void cpu_register_physical_memory(target_phys_addr_t
start_addr,
ram_addr_t orig_size = size;
void *subpage;
-#ifdef USE_KQEMU
- /* XXX: should not depend on cpu context */
- env = first_cpu;
- if (env->kqemu_enabled) {
- kqemu_set_phys_mem(start_addr, size, phys_offset);
- }
-#endif
size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
end_addr = start_addr + (target_phys_addr_t)size;
for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
@@ -2268,6 +2260,18 @@ void cpu_register_physical_memory(target_phys_addr_t
start_addr,
}
}
+/* register physical memory. 'size' must be a multiple of the target
+ page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
+ io memory page */
+void cpu_register_physical_memory(target_phys_addr_t start_addr,
+ ram_addr_t size,
+ ram_addr_t phys_offset)
+{
+ accel_register_phys_mem(start_addr, size, phys_offset);
+
+ __cpu_register_physical_memory(start_addr, size, phys_offset);
+}
+
/* XXX: temporary until new memory mapping API */
ram_addr_t cpu_get_physical_page_desc(target_phys_addr_t addr)
{
@@ -2383,12 +2387,11 @@ static void notdirty_mem_writeb(void *opaque,
target_phys_addr_t ram_addr,
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
#endif
}
+
stb_p(phys_ram_base + ram_addr, val);
-#ifdef USE_KQEMU
- if (cpu_single_env->kqemu_enabled &&
- (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
- kqemu_modify_page(cpu_single_env, ram_addr);
-#endif
+
+ accel_modify_page(ram_addr, dirty_flags);
+
dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
/* we remove the notdirty callback only if the code has been
@@ -2408,12 +2411,11 @@ static void notdirty_mem_writew(void *opaque,
target_phys_addr_t ram_addr,
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
#endif
}
+
stw_p(phys_ram_base + ram_addr, val);
-#ifdef USE_KQEMU
- if (cpu_single_env->kqemu_enabled &&
- (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
- kqemu_modify_page(cpu_single_env, ram_addr);
-#endif
+
+ accel_modify_page(ram_addr, dirty_flags);
+
dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
/* we remove the notdirty callback only if the code has been
@@ -2433,12 +2435,11 @@ static void notdirty_mem_writel(void *opaque,
target_phys_addr_t ram_addr,
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
#endif
}
+
stl_p(phys_ram_base + ram_addr, val);
-#ifdef USE_KQEMU
- if (cpu_single_env->kqemu_enabled &&
- (dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
- kqemu_modify_page(cpu_single_env, ram_addr);
-#endif
+
+ accel_modify_page(ram_addr, dirty_flags);
+
dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
/* we remove the notdirty callback only if the code has been
diff --git a/hw/pc.c b/hw/pc.c
index 34683e7..2f56c1f 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -33,6 +33,7 @@
#include "boards.h"
#include "console.h"
#include "fw_cfg.h"
+#include "accel.h"
/* output Bochs bios info messages */
//#define DEBUG_BIOS
@@ -75,17 +76,7 @@ static void ioportF0_write(void *opaque, uint32_t addr,
uint32_t data)
/* TSC handling */
uint64_t cpu_get_tsc(CPUX86State *env)
{
- /* Note: when using kqemu, it is more logical to return the host TSC
- because kqemu does not trap the RDTSC instruction for
- performance reasons */
-#ifdef USE_KQEMU
- if (env->kqemu_enabled) {
- return cpu_get_real_ticks();
- } else
-#endif
- {
- return cpu_get_ticks();
- }
+ return accel_get_real_ticks();
}
/* SMM support */
diff --git a/kqemu.c b/kqemu.c
index 4783aa2..58a149b 100644
--- a/kqemu.c
+++ b/kqemu.c
@@ -30,6 +30,7 @@
#ifdef HOST_SOLARIS
#include <sys/ioccom.h>
#endif
+#include "exec.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
@@ -44,12 +45,21 @@
#ifdef USE_KQEMU
+#define KQEMU_USER 1
+#define KQEMU_KERNEL 2
+
+static int kqemu_state;
#define DEBUG
//#define PROFILE
#include <unistd.h>
#include <fcntl.h>
#include "kqemu.h"
+#include "accel86.h"
+
+#ifdef CONFIG_PROFILER
+#include "qemu-timer.h" /* for ticks_per_sec */
+#endif
#ifdef _WIN32
#define KQEMU_DEVICE "\\\\.\\kqemu"
@@ -69,11 +79,6 @@ int kqemu_fd = KQEMU_INVALID_FD;
#define kqemu_closefd(x) close(x)
#endif
-/* 0 = not allowed
- 1 = user kqemu
- 2 = kernel kqemu
-*/
-int kqemu_allowed = 1;
uint64_t *pages_to_flush;
unsigned int nb_pages_to_flush;
uint64_t *ram_pages_to_update;
@@ -84,6 +89,13 @@ uint8_t *modified_ram_pages_table;
int qpi_io_memory;
uint32_t kqemu_comm_base; /* physical address of the QPI communication page */
+static inline int cpu_get_time_fast(void)
+{
+ int low, high;
+ asm volatile("rdtsc" : "=a" (low), "=d" (high));
+ return low;
+}
+
#define cpuid(index, eax, ebx, ecx, edx) \
asm volatile ("cpuid" \
: "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
@@ -113,6 +125,19 @@ static int is_cpuid_supported(void)
}
#endif
+/* FIXME: Should not be needed, since ideally, QEMUAccel would avoid all kqemu
tests
+ * altogether
+ */
+int kqemu_is_enabled(CPUState *env)
+{
+ return kqemu_state == KQEMU_USER;
+}
+
+int kqemu_kernel_enabled(CPUState *env)
+{
+ return kqemu_state == KQEMU_KERNEL;
+}
+
static void kqemu_update_cpuid(CPUState *env)
{
int critical_features_mask, features, ext_features, ext_features_mask;
@@ -150,7 +175,9 @@ static void kqemu_update_cpuid(CPUState *env)
accelerated code */
}
-int kqemu_init(CPUState *env)
+QEMUAccel kqemu_accel;
+
+static int kqemu_do_start(int cpus)
{
struct kqemu_init kinit;
int ret, version;
@@ -158,7 +185,7 @@ int kqemu_init(CPUState *env)
DWORD temp;
#endif
- if (!kqemu_allowed)
+ if (cpus > 1)
return -1;
#ifdef _WIN32
@@ -230,8 +257,6 @@ int kqemu_init(CPUState *env)
kqemu_fd = KQEMU_INVALID_FD;
return -1;
}
- kqemu_update_cpuid(env);
- env->kqemu_enabled = kqemu_allowed;
nb_pages_to_flush = 0;
nb_ram_pages_to_update = 0;
@@ -239,7 +264,24 @@ int kqemu_init(CPUState *env)
return 0;
}
-void kqemu_flush_page(CPUState *env, target_ulong addr)
+static int kqemu_start(int cpus)
+{
+ kqemu_state = KQEMU_USER;
+ return kqemu_do_start(cpus);
+}
+
+static int kqemu_start_kernel(int cpus)
+{
+ kqemu_state = KQEMU_KERNEL;
+ return kqemu_do_start(cpus);
+}
+
+static void kqemu_init_env(CPUState *env)
+{
+ kqemu_update_cpuid(env);
+}
+
+static void kqemu_flush_page(CPUState *env, target_ulong addr)
{
#if defined(DEBUG)
if (loglevel & CPU_LOG_INT) {
@@ -252,7 +294,7 @@ void kqemu_flush_page(CPUState *env, target_ulong addr)
pages_to_flush[nb_pages_to_flush++] = addr;
}
-void kqemu_flush(CPUState *env, int global)
+static void kqemu_flush(CPUState *env, int global)
{
#ifdef DEBUG
if (loglevel & CPU_LOG_INT) {
@@ -262,7 +304,7 @@ void kqemu_flush(CPUState *env, int global)
nb_pages_to_flush = KQEMU_FLUSH_ALL;
}
-void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr)
+static void kqemu_set_notdirty(ram_addr_t ram_addr)
{
#ifdef DEBUG
if (loglevel & CPU_LOG_INT) {
@@ -291,7 +333,7 @@ static void kqemu_reset_modified_ram_pages(void)
nb_modified_ram_pages = 0;
}
-void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr)
+static void kqemu_modify_page(ram_addr_t ram_addr, int dirty_flags)
{
unsigned long page_index;
int ret;
@@ -299,6 +341,8 @@ void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr)
DWORD temp;
#endif
+ if ((dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
+ return;
page_index = ram_addr >> TARGET_PAGE_BITS;
if (!modified_ram_pages_table[page_index]) {
#if 0
@@ -689,7 +733,7 @@ static inline void kqemu_save_seg(SegmentCache *sc,
sc->base = ksc->base;
}
-int kqemu_cpu_exec(CPUState *env)
+static int kqemu_do_cpu_exec(CPUState *env)
{
struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;
int ret, cpl, i;
@@ -749,7 +793,7 @@ int kqemu_cpu_exec(CPUState *env)
cpl = (env->hflags & HF_CPL_MASK);
kenv->cpl = cpl;
kenv->nb_pages_to_flush = nb_pages_to_flush;
- kenv->user_only = (env->kqemu_enabled == 1);
+ kenv->user_only = kqemu_is_enabled(env);
kenv->nb_ram_pages_to_update = nb_ram_pages_to_update;
nb_ram_pages_to_update = 0;
kenv->nb_modified_ram_pages = nb_modified_ram_pages;
@@ -891,7 +935,7 @@ int kqemu_cpu_exec(CPUState *env)
cpu_dump_state(env, logfile, fprintf, 0);
}
#endif
- return 1;
+ return EXEC_EXIT_INTR;
} else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) {
env->exception_index = ret & 0xff;
env->error_code = kenv->error_code;
@@ -907,7 +951,7 @@ int kqemu_cpu_exec(CPUState *env)
cpu_dump_state(env, logfile, fprintf, 0);
}
#endif
- return 1;
+ return EXEC_EXIT_INTR;
} else if (ret == KQEMU_RET_INTR) {
#ifdef CONFIG_PROFILER
kqemu_ret_intr_count++;
@@ -917,7 +961,7 @@ int kqemu_cpu_exec(CPUState *env)
cpu_dump_state(env, logfile, fprintf, 0);
}
#endif
- return 0;
+ return EXEC_EXIT_DONE;
} else if (ret == KQEMU_RET_SOFTMMU) {
#ifdef CONFIG_PROFILER
{
@@ -930,16 +974,31 @@ int kqemu_cpu_exec(CPUState *env)
cpu_dump_state(env, logfile, fprintf, 0);
}
#endif
- return 2;
+ return EXEC_EXIT_SOFTMMU;
} else {
cpu_dump_state(env, stderr, fprintf, 0);
fprintf(stderr, "Unsupported return value: 0x%x\n", ret);
exit(1);
}
- return 0;
+ return EXEC_EXIT_DONE;
}
-void kqemu_cpu_interrupt(CPUState *env)
+static int kqemu_cpu_exec(CPUState *env)
+{
+
+ int ret = EXEC_EXIT_SOFTMMU;
+ if (kqemu_kernel_flags_ok(env) && env->interrupt_request == 0) {
+ ret = kqemu_do_cpu_exec(env);
+ /* put eflags in CPU temporary format */
+ CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((env->eflags >> 10) & 1));
+ CC_OP = CC_OP_EFLAGS;
+ }
+ return ret;
+}
+
+
+static void kqemu_cpu_interrupt(CPUState *env)
{
#if defined(_WIN32)
/* cancelling the I/O request causes KQEMU to finish executing the
@@ -1019,7 +1078,188 @@ static void qpi_init(void)
qpi_io_memory = cpu_register_io_memory(0,
qpi_mem_read,
qpi_mem_write, NULL);
- cpu_register_physical_memory(kqemu_comm_base & ~0xfff,
+ __cpu_register_physical_memory(kqemu_comm_base & ~0xfff,
0x1000, qpi_io_memory);
}
+
+static int kqemu_info(CPUState *env, char *buf)
+{
+ return snprintf(buf, MAX_INFO_BUF, "kqemu support: enabled for user
code\n");
+}
+
+static int kqemu_kernel_info(CPUState *env, char *buf)
+{
+ return snprintf(buf, MAX_INFO_BUF, "kqemu support: enabled for user and
kernel code\n");
+}
+
+int64_t kqemu_time;
+int64_t kqemu_exec_count;
+int64_t kqemu_ret_int_count;
+int64_t kqemu_ret_excp_count;
+int64_t kqemu_ret_intr_count;
+extern int64_t qemu_time;
+
+static int kqemu_profile(CPUState *env, char *buf)
+{
+ int len = 0;
+#ifdef CONFIG_PROFILER
+ len = sprintf(buf, "kqemu time %" PRId64 " (%0.3f %0.1f%%) count=%" PRId64
+ " int=%" PRId64 " excp=%" PRId64 " intr=%" PRId64 "\n",
+ kqemu_time, kqemu_time / (double)ticks_per_sec,
+ kqemu_time / qemu_time * 100.0,
+ kqemu_exec_count,
+ kqemu_ret_int_count,
+ kqemu_ret_excp_count,
+ kqemu_ret_intr_count);
+
+ kqemu_time = 0;
+ kqemu_exec_count = 0;
+ kqemu_ret_int_count = 0;
+ kqemu_ret_excp_count = 0;
+ kqemu_ret_intr_count = 0;
+ kqemu_record_dump();
+#endif
+ return len;
+}
+
+static void kqemu_trace_io(CPUState *env)
+{
+ if (env)
+ kqemu_cpu_field(env,last_io_time) = cpu_get_time_fast();
+}
+
+#define MIN_CYCLE_BEFORE_SWITCH (100 * 1000)
+
+static inline int kqemu_flags_ok(CPUState *env)
+{
+ return((env->cr[0] & CR0_PE_MASK) &&
+ !(env->hflags & HF_INHIBIT_IRQ_MASK) &&
+ (env->eflags & IF_MASK) &&
+ !(env->eflags & VM_MASK));
+}
+
+static inline int kqemu_kernel_flags_ok(CPUState *env)
+{
+ return (kqemu_flags_ok(env) && (kqemu_kernel_enabled(env) ||
+ ((env->hflags & HF_CPL_MASK) == 3 &&
+ (env->eflags & IOPL_MASK) != IOPL_MASK)));
+
+}
+
+static int kqemu_break_loop(CPUState *env)
+{
+ if (kqemu_kernel_flags_ok(env) &&
+ (cpu_get_time_fast() - kqemu_cpu_field(env,last_io_time)) >=
MIN_CYCLE_BEFORE_SWITCH) {
+ return 1;
+ }
+ return 0;
+}
+
+static CPUState *kqemu_get_env(void)
+{
+ KQEMUCPUState *kenv;
+ kenv = qemu_mallocz(sizeof(KQEMUCPUState));
+ return &kenv->env;
+}
+
+static int kqemu_get_msr(int msr, uint64_t *val)
+{
+ int ret = -1;
+ switch (msr) {
+ case MSR_QPI_COMMBASE:
+ val = kqemu_comm_base;
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int kqemu_set_msr(int msr, target_ulong val)
+{
+ return -1;
+}
+
+static void kqemu_interrupt_return(CPUState *env)
+{
+ if (kqemu_kernel_flags_ok(env)) {
+ CC_OP = CC_OP_EFLAGS;
+ env->exception_index = -1;
+ cpu_loop_exit();
+ }
+}
+
+static void kqemu_syscall_return(CPUState *env)
+{
+ if (kqemu_kernel_flags_ok(env)) {
+ if (env->hflags & HF_LMA_MASK)
+ CC_OP = CC_OP_EFLAGS;
+ env->exception_index = -1;
+ cpu_loop_exit();
+ }
+}
+
+static void kqemu_long_exit_loop(CPUState *env)
+{
+ if (kqemu_kernel_flags_ok(env)) {
+ env->exception_index = -1;
+ cpu_loop_exit();
+ }
+}
+
+QEMUAccel86 kqemu_accel86 = {
+ .get_msr = kqemu_get_msr,
+ .set_msr = kqemu_set_msr,
+ .interrupt_return = kqemu_interrupt_return,
+ .syscall_return = kqemu_syscall_return,
+ .long_call = kqemu_long_exit_loop,
+ .long_ret = kqemu_long_exit_loop,
+};
+
+QEMUAccel kqemu_accel = {
+ .name = "KQEMU",
+ .cpu_interrupt = kqemu_cpu_interrupt,
+ .init_env = kqemu_init_env,
+ .get_env = kqemu_get_env,
+ .start = kqemu_start,
+ .flush_cache = kqemu_flush,
+ .flush_page = kqemu_flush_page,
+ .info = kqemu_info,
+ .profile = kqemu_profile,
+ .set_notdirty = kqemu_set_notdirty,
+ .modify_page = kqemu_modify_page,
+#ifndef CONFIG_USER_ONLY
+ /* Note: when using kqemu, it is more logical to return the host TSC
+ because kqemu does not trap the RDTSC instruction for
+ performance reasons */
+ .get_real_ticks = cpu_get_real_ticks,
+#endif
+ .register_physical_memory = kqemu_set_phys_mem,
+ .trace_io = kqemu_trace_io,
+ .break_loop = kqemu_break_loop,
+ .cpu_exec = kqemu_cpu_exec,
+ .arch = &kqemu_accel86,
+};
+
+QEMUAccel kqemu_kernel_accel = {
+ .name = "kernel-KQEMU",
+ .cpu_interrupt = kqemu_cpu_interrupt,
+ .init_env = kqemu_init_env,
+ .get_env = kqemu_get_env,
+ .start = kqemu_start_kernel,
+ .flush_cache = kqemu_flush,
+ .flush_page = kqemu_flush_page,
+ .info = kqemu_kernel_info,
+ .profile = kqemu_profile,
+ .set_notdirty = kqemu_set_notdirty,
+ .modify_page = kqemu_modify_page,
+#ifndef CONFIG_USER_ONLY
+ .get_real_ticks = cpu_get_real_ticks,
+#endif
+ .register_physical_memory = kqemu_set_phys_mem,
+ .trace_io = kqemu_trace_io,
+ .break_loop = kqemu_break_loop,
+ .cpu_exec = kqemu_cpu_exec,
+ .arch = &kqemu_accel86,
+};
+
#endif
diff --git a/kqemu.h b/kqemu.h
index ed25c75..4152fbd 100644
--- a/kqemu.h
+++ b/kqemu.h
@@ -32,6 +32,12 @@
#define KQEMU_VERSION 0x010400
+extern int64_t kqemu_time, kqemu_time_start;
+extern int64_t kqemu_exec_count;
+extern int64_t kqemu_ret_int_count;
+extern int64_t kqemu_ret_excp_count;
+extern int64_t kqemu_ret_intr_count;
+
struct kqemu_segment_cache {
uint16_t selector;
uint16_t padding1;
@@ -151,4 +157,19 @@ struct kqemu_phys_mem {
#define KQEMU_SET_PHYS_MEM _IOW('q', 5, struct kqemu_phys_mem)
#endif
+int kqemu_is_enabled(CPUState *env);
+int kqemu_kernel_enabled(CPUState *env);
+
+typedef struct KQEMUCPUstate {
+ int last_io_time;
+ CPUState env;
+} KQEMUCPUState;
+
+#define kqemu_cpu_field(env, field) (*({ \
+ KQEMUCPUState *__c = container_of(env, KQEMUCPUState, env); \
+ &__c->field; }))
+
+#define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
+
+#define MSR_QPI_COMMBASE 0xfabe0010
#endif /* KQEMU_H */
diff --git a/monitor.c b/monitor.c
index f0a0bc3..fe915d8 100644
--- a/monitor.c
+++ b/monitor.c
@@ -34,6 +34,7 @@
#include "block.h"
#include "audio/audio.h"
#include "disas.h"
+#include "accel.h"
#include <dirent.h>
#include "qemu-timer.h"
#include "migration.h"
@@ -1233,49 +1234,42 @@ static void mem_info(void)
}
#endif
-static void do_info_kqemu(void)
+static int do_accel_do_list(void)
{
-#ifdef USE_KQEMU
+ QEMUCont *tmp;
+ for (tmp= get_accel_head(); tmp != NULL; tmp = tmp->next)
+ {
+ term_printf("%c %s\n", tmp->active ? '*' : ' ', tmp->acc->name);
+ }
+}
+
+static void do_info_accelerator(void)
+{
+ char buf[MAX_INFO_BUF];
CPUState *env;
- int val;
- val = 0;
+
env = mon_get_cpu();
+
if (!env) {
term_printf("No cpu initialized yet");
return;
}
- val = env->kqemu_enabled;
- term_printf("kqemu support: ");
- switch(val) {
- default:
- case 0:
- term_printf("disabled\n");
- break;
- case 1:
- term_printf("enabled for user code\n");
- break;
- case 2:
- term_printf("enabled for user and kernel code\n");
- break;
- }
-#else
- term_printf("kqemu support: not compiled\n");
-#endif
+
+ do_accel_do_list();
+ if (accel_info(env, buf))
+ term_printf(buf);
}
#ifdef CONFIG_PROFILER
-int64_t kqemu_time;
int64_t qemu_time;
-int64_t kqemu_exec_count;
int64_t dev_time;
-int64_t kqemu_ret_int_count;
-int64_t kqemu_ret_excp_count;
-int64_t kqemu_ret_intr_count;
-
static void do_info_profile(void)
{
int64_t total;
+ char buf[MAX_BUF];
+ CPUState *env = mon_get_cpu();
+
total = qemu_time;
if (total == 0)
total = 1;
@@ -1283,24 +1277,12 @@ static void do_info_profile(void)
dev_time, dev_time / (double)ticks_per_sec);
term_printf("qemu time %" PRId64 " (%0.3f)\n",
qemu_time, qemu_time / (double)ticks_per_sec);
- term_printf("kqemu time %" PRId64 " (%0.3f %0.1f%%) count=%" PRId64 "
int=%" PRId64 " excp=%" PRId64 " intr=%" PRId64 "\n",
- kqemu_time, kqemu_time / (double)ticks_per_sec,
- kqemu_time / (double)total * 100.0,
- kqemu_exec_count,
- kqemu_ret_int_count,
- kqemu_ret_excp_count,
- kqemu_ret_intr_count);
+ if (accel_profile(env, buf))
+ term_printf(buf);
qemu_time = 0;
- kqemu_time = 0;
- kqemu_exec_count = 0;
dev_time = 0;
- kqemu_ret_int_count = 0;
- kqemu_ret_excp_count = 0;
- kqemu_ret_intr_count = 0;
-#ifdef USE_KQEMU
- kqemu_record_dump();
-#endif
}
+
#else
static void do_info_profile(void)
{
@@ -1493,8 +1475,8 @@ static const term_cmd_t info_cmds[] = {
#endif
{ "jit", "", do_info_jit,
"", "show dynamic compiler info", },
- { "kqemu", "", do_info_kqemu,
- "", "show kqemu information", },
+ { "accelerator", "", do_info_accelerator,
+ "", "show accelerator information", },
{ "usb", "", usb_info,
"", "show guest USB devices", },
{ "usbhost", "", usb_host_info,
diff --git a/osdep.c b/osdep.c
index 683aad0..31c96e6 100644
--- a/osdep.c
+++ b/osdep.c
@@ -68,112 +68,9 @@ void qemu_vfree(void *ptr)
#else
-#if defined(USE_KQEMU)
-
-#ifdef __OpenBSD__
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/mount.h>
-#else
-#include <sys/vfs.h>
-#endif
-
#include <sys/mman.h>
#include <fcntl.h>
-static void *kqemu_vmalloc(size_t size)
-{
- static int phys_ram_fd = -1;
- static int phys_ram_size = 0;
- void *ptr;
-
-#ifdef __OpenBSD__ /* no need (?) for a dummy file on OpenBSD */
- int map_anon = MAP_ANON;
-#else
- int map_anon = 0;
- const char *tmpdir;
- char phys_ram_file[1024];
-#ifdef HOST_SOLARIS
- struct statvfs stfs;
-#else
- struct statfs stfs;
-#endif
-
- if (phys_ram_fd < 0) {
- tmpdir = getenv("QEMU_TMPDIR");
- if (!tmpdir)
-#ifdef HOST_SOLARIS
- tmpdir = "/tmp";
- if (statvfs(tmpdir, &stfs) == 0) {
-#else
- tmpdir = "/dev/shm";
- if (statfs(tmpdir, &stfs) == 0) {
-#endif
- int64_t free_space;
- int ram_mb;
-
- free_space = (int64_t)stfs.f_bavail * stfs.f_bsize;
- if ((ram_size + 8192 * 1024) >= free_space) {
- ram_mb = (ram_size / (1024 * 1024));
- fprintf(stderr,
- "You do not have enough space in '%s' for the %d MB of
QEMU virtual RAM.\n",
- tmpdir, ram_mb);
- if (strcmp(tmpdir, "/dev/shm") == 0) {
- fprintf(stderr, "To have more space available provided you
have enough RAM and swap, do as root:\n"
- "mount -o remount,size=%dm /dev/shm\n",
- ram_mb + 16);
- } else {
- fprintf(stderr,
- "Use the '-m' option of QEMU to diminish the
amount of virtual RAM or use the\n"
- "QEMU_TMPDIR environment variable to set another
directory where the QEMU\n"
- "temporary RAM file will be opened.\n");
- }
- fprintf(stderr, "Or disable the accelerator module with
-no-kqemu\n");
- exit(1);
- }
- }
- snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
- tmpdir);
- phys_ram_fd = mkstemp(phys_ram_file);
- if (phys_ram_fd < 0) {
- fprintf(stderr,
- "warning: could not create temporary file in '%s'.\n"
- "Use QEMU_TMPDIR to select a directory in a tmpfs
filesystem.\n"
- "Using '/tmp' as fallback.\n",
- tmpdir);
- snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
- "/tmp");
- phys_ram_fd = mkstemp(phys_ram_file);
- if (phys_ram_fd < 0) {
- fprintf(stderr, "Could not create temporary memory file
'%s'\n",
- phys_ram_file);
- exit(1);
- }
- }
- unlink(phys_ram_file);
- }
- size = (size + 4095) & ~4095;
- ftruncate(phys_ram_fd, phys_ram_size + size);
-#endif /* !__OpenBSD__ */
- ptr = mmap(NULL,
- size,
- PROT_WRITE | PROT_READ, map_anon | MAP_SHARED,
- phys_ram_fd, phys_ram_size);
- if (ptr == MAP_FAILED) {
- fprintf(stderr, "Could not map physical memory\n");
- exit(1);
- }
- phys_ram_size += size;
- return ptr;
-}
-
-static void kqemu_vfree(void *ptr)
-{
- /* may be useful some day, but currently we do not need to free */
-}
-
-#endif
-
void *qemu_memalign(size_t alignment, size_t size)
{
#if defined(_POSIX_C_SOURCE)
@@ -193,10 +90,6 @@ void *qemu_memalign(size_t alignment, size_t size)
/* alloc shared memory pages */
void *qemu_vmalloc(size_t size)
{
-#if defined(USE_KQEMU)
- if (kqemu_allowed)
- return kqemu_vmalloc(size);
-#endif
#ifdef _BSD
return valloc(size);
#else
@@ -206,10 +99,6 @@ void *qemu_vmalloc(size_t size)
void qemu_vfree(void *ptr)
{
-#if defined(USE_KQEMU)
- if (kqemu_allowed)
- kqemu_vfree(ptr);
-#endif
free(ptr);
}
diff --git a/softmmu_template.h b/softmmu_template.h
index 98dd378..4945352 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -47,6 +47,8 @@
#define ADDR_READ addr_read
#endif
+#include "accel.h"
+
static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
int mmu_idx,
void *retaddr);
@@ -75,9 +77,7 @@ static inline DATA_TYPE glue(io_read,
SUFFIX)(target_phys_addr_t physaddr,
res |= (uint64_t)io_mem_read[index][2](io_mem_opaque[index], physaddr + 4)
<< 32;
#endif
#endif /* SHIFT > 2 */
-#ifdef USE_KQEMU
- env->last_io_time = cpu_get_time_fast();
-#endif
+ accel_trace_io(env);
return res;
}
@@ -220,9 +220,7 @@ static inline void glue(io_write,
SUFFIX)(target_phys_addr_t physaddr,
io_mem_write[index][2](io_mem_opaque[index], physaddr + 4, val >> 32);
#endif
#endif /* SHIFT > 2 */
-#ifdef USE_KQEMU
- env->last_io_time = cpu_get_time_fast();
-#endif
+ accel_trace_io(env);
}
void REGPARM glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
diff --git a/sysemu.h b/sysemu.h
index 976fecc..5a19626 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -99,11 +99,6 @@ extern int semihosting_enabled;
extern int old_param;
extern const char *bootp_filename;
-
-#ifdef USE_KQEMU
-extern int kqemu_allowed;
-#endif
-
#define MAX_OPTION_ROMS 16
extern const char *option_rom[MAX_OPTION_ROMS];
extern int nb_option_roms;
diff --git a/target-i386/accel86.h b/target-i386/accel86.h
new file mode 100644
index 0000000..a7ba39b
--- /dev/null
+++ b/target-i386/accel86.h
@@ -0,0 +1,60 @@
+#ifndef _ACCEL_86_H_
+#define _ACCEL_86_H_
+
+#include "accel.h"
+
+typedef struct QEMUAccel86 {
+ int (*get_msr)(int msr, uint64_t *value);
+ int (*set_msr)(int msr, uint64_t value);
+ void (*interrupt_return)(CPUState *env);
+ void (*syscall_return)(CPUState *env);
+ void (*long_call)(CPUState *env);
+ void (*long_ret)(CPUState *env);
+} QEMUAccel86;
+
+#define accel86_call_func ((QEMUAccel86 *)(current_accel->arch))
+
+static inline int accel_get_msr(int msr, uint64_t *value)
+{
+ if (!current_accel->arch)
+ return -1;
+ return accel86_call_func->get_msr(msr, value);
+}
+
+static inline int accel_set_msr(int msr, uint64_t value)
+{
+ if (!current_accel->arch)
+ return -1;
+ return accel86_call_func->set_msr(msr, value);
+}
+
+static inline void accel_interrupt_return(CPUState *env)
+{
+ if (!current_accel->arch)
+ return;
+ accel86_call_func->interrupt_return(env);
+}
+
+static inline void accel_syscall_return(CPUState *env)
+{
+ if (!current_accel->arch)
+ return;
+ accel86_call_func->syscall_return(env);
+}
+
+static inline void accel_long_call(CPUState *env)
+{
+ if (!current_accel->arch)
+ return;
+ accel86_call_func->syscall_return(env);
+}
+
+static inline void accel_long_ret(CPUState *env)
+{
+ if (!current_accel->arch)
+ return;
+ accel86_call_func->syscall_return(env);
+}
+
+#endif
+
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 3c11e0f..e5e91cc 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -606,10 +606,6 @@ typedef struct CPUX86State {
uint32_t cpuid_ext3_features;
uint32_t cpuid_apic_id;
-#ifdef USE_KQEMU
- int kqemu_enabled;
- int last_io_time;
-#endif
/* in order to simplify APIC support, we leave this pointer to the
user */
struct APICState *apic_state;
@@ -727,15 +723,6 @@ void cpu_x86_update_cr0(CPUX86State *env, uint32_t
new_cr0);
#define X86_DUMP_FPU 0x0001 /* dump FPU state too */
#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
-#ifdef USE_KQEMU
-static inline int cpu_get_time_fast(void)
-{
- int low, high;
- asm volatile("rdtsc" : "=a" (low), "=d" (high));
- return low;
-}
-#endif
-
#define TARGET_PAGE_BITS 12
#define CPUState CPUX86State
diff --git a/target-i386/helper.c b/target-i386/helper.c
index c2e1a88..5ff051f 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -30,6 +30,8 @@
#include "svm.h"
#include "qemu-common.h"
+#include "accel.h"
+
//#define DEBUG_MMU
static int cpu_x86_register (CPUX86State *env, const char *cpu_model);
@@ -96,7 +98,7 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
CPUX86State *env;
static int inited;
- env = qemu_mallocz(sizeof(CPUX86State));
+ env = accel_get_env();
if (!env)
return NULL;
cpu_exec_init(env);
@@ -112,9 +114,7 @@ CPUX86State *cpu_x86_init(const char *cpu_model)
return NULL;
}
cpu_reset(env);
-#ifdef USE_KQEMU
- kqemu_init(env);
-#endif
+ accel_init_env(env);
return env;
}
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index ebb5824..addd42a 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -20,6 +20,7 @@
#define CPU_NO_GLOBAL_REGS
#include "exec.h"
#include "host-utils.h"
+#include "accel86.h"
//#define DEBUG_PCALL
@@ -1103,14 +1104,7 @@ void helper_sysret(int dflag)
env->eflags |= IF_MASK;
cpu_x86_set_cpl(env, 3);
}
-#ifdef USE_KQEMU
- if (kqemu_is_ok(env)) {
- if (env->hflags & HF_LMA_MASK)
- CC_OP = CC_OP_EFLAGS;
- env->exception_index = -1;
- cpu_loop_exit();
- }
-#endif
+ accel_syscall_return(env);
}
/* real mode interrupt */
@@ -2623,12 +2617,7 @@ void helper_lcall_protected(int new_cs, target_ulong
new_eip,
SET_ESP(sp, sp_mask);
EIP = offset;
}
-#ifdef USE_KQEMU
- if (kqemu_is_ok(env)) {
- env->exception_index = -1;
- cpu_loop_exit();
- }
-#endif
+ accel_long_call(env);
}
/* real and vm86 mode iret */
@@ -2917,24 +2906,14 @@ void helper_iret_protected(int shift, int next_eip)
helper_ret_protected(shift, 1, 0);
}
env->hflags2 &= ~HF2_NMI_MASK;
-#ifdef USE_KQEMU
- if (kqemu_is_ok(env)) {
- CC_OP = CC_OP_EFLAGS;
- env->exception_index = -1;
- cpu_loop_exit();
- }
-#endif
+
+ accel_interrupt_return(env);
}
void helper_lret_protected(int shift, int addend)
{
helper_ret_protected(shift, 0, addend);
-#ifdef USE_KQEMU
- if (kqemu_is_ok(env)) {
- env->exception_index = -1;
- cpu_loop_exit();
- }
-#endif
+ accel_long_ret(env);
}
void helper_sysenter(void)
@@ -3007,12 +2986,6 @@ void helper_sysexit(int dflag)
}
ESP = ECX;
EIP = EDX;
-#ifdef USE_KQEMU
- if (kqemu_is_ok(env)) {
- env->exception_index = -1;
- cpu_loop_exit();
- }
-#endif
}
#if defined(CONFIG_USER_ONLY)
@@ -3262,18 +3235,9 @@ void helper_rdmsr(void)
val = env->kernelgsbase;
break;
#endif
-#ifdef USE_KQEMU
- case MSR_QPI_COMMBASE:
- if (env->kqemu_enabled) {
- val = kqemu_comm_base;
- } else {
- val = 0;
- }
- break;
-#endif
default:
- /* XXX: exception ? */
- val = 0;
+ if (accel_get_msr((uint32_t)ECX, &val) < 0)
+ val = 0;
break;
}
EAX = (uint32_t)(val);
diff --git a/vl.c b/vl.c
index c0e43ac..42720e8 100644
--- a/vl.c
+++ b/vl.c
@@ -140,6 +140,7 @@
#include "disas.h"
#include "exec-all.h"
+#include "accel.h"
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
@@ -149,6 +150,8 @@
#define SMBD_COMMAND "/usr/sbin/smbd"
#endif
+#include "accel.h"
+
//#define DEBUG_UNUSED_IOPORT
//#define DEBUG_IOPORT
//#define DEBUG_NET
@@ -252,6 +255,14 @@ static QEMUTimer *icount_vm_timer;
uint8_t qemu_uuid[16];
+QEMUAccel *available_accels[] = {
+/* list of available accelerators */
+#ifdef USE_KQEMU
+ &kqemu_accel,
+ &kqemu_kernel_accel,
+#endif
+};
+
#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
/***********************************************************/
@@ -410,10 +421,7 @@ void cpu_outb(CPUState *env, int addr, int val)
fprintf(logfile, "outb: %04x %02x\n", addr, val);
#endif
ioport_write(0, addr, val);
-#ifdef USE_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
+ accel_trace_io(env);
}
void cpu_outw(CPUState *env, int addr, int val)
@@ -423,10 +431,7 @@ void cpu_outw(CPUState *env, int addr, int val)
fprintf(logfile, "outw: %04x %04x\n", addr, val);
#endif
ioport_write(1, addr, val);
-#ifdef USE_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
+ accel_trace_io(env);
}
void cpu_outl(CPUState *env, int addr, int val)
@@ -436,10 +441,7 @@ void cpu_outl(CPUState *env, int addr, int val)
fprintf(logfile, "outl: %04x %08x\n", addr, val);
#endif
ioport_write(2, addr, val);
-#ifdef USE_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
+ accel_trace_io(env);
}
int cpu_inb(CPUState *env, int addr)
@@ -450,10 +452,7 @@ int cpu_inb(CPUState *env, int addr)
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "inb : %04x %02x\n", addr, val);
#endif
-#ifdef USE_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
+ accel_trace_io(env);
return val;
}
@@ -465,10 +464,7 @@ int cpu_inw(CPUState *env, int addr)
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "inw : %04x %04x\n", addr, val);
#endif
-#ifdef USE_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
+ accel_trace_io(env);
return val;
}
@@ -480,10 +476,7 @@ int cpu_inl(CPUState *env, int addr)
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "inl : %04x %08x\n", addr, val);
#endif
-#ifdef USE_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
+ accel_trace_io(env);
return val;
}
@@ -1317,11 +1310,6 @@ static void host_alarm_handler(int host_signum)
if (env) {
/* stop the currently executing cpu because a timer occured */
cpu_interrupt(env, CPU_INTERRUPT_EXIT);
-#ifdef USE_KQEMU
- if (env->kqemu_enabled) {
- kqemu_cpu_interrupt(env);
- }
-#endif
}
event_pending = 1;
}
@@ -7560,14 +7548,8 @@ static int ram_load(QEMUFile *f, void *opaque, int
version_id)
void qemu_service_io(void)
{
CPUState *env = cpu_single_env;
- if (env) {
+ if (env)
cpu_interrupt(env, CPU_INTERRUPT_EXIT);
-#ifdef USE_KQEMU
- if (env->kqemu_enabled) {
- kqemu_cpu_interrupt(env);
- }
-#endif
- }
}
/***********************************************************/
@@ -8255,10 +8237,6 @@ static void help(int exitcode)
"-hdachs c,h,s[,t] force hard disk 0 physical geometry and the
optional BIOS\n"
" translation (t=none or lba) (usually qemu can
guess them)\n"
"-L path set the directory for the BIOS, VGA BIOS and
keymaps\n"
-#ifdef USE_KQEMU
- "-kernel-kqemu enable KQEMU full virtualization (default is user
mode only)\n"
- "-no-kqemu disable KQEMU kernel module usage\n"
-#endif
#ifdef TARGET_I386
"-no-acpi disable ACPI\n"
#endif
@@ -8362,8 +8340,7 @@ enum {
QEMU_OPTION_alt_grab,
QEMU_OPTION_no_quit,
QEMU_OPTION_pidfile,
- QEMU_OPTION_no_kqemu,
- QEMU_OPTION_kernel_kqemu,
+ QEMU_OPTION_accel,
QEMU_OPTION_win2k_hack,
QEMU_OPTION_usb,
QEMU_OPTION_usbdevice,
@@ -8446,10 +8423,7 @@ static const QEMUOption qemu_options[] = {
{ "hdachs", HAS_ARG, QEMU_OPTION_hdachs },
{ "L", HAS_ARG, QEMU_OPTION_L },
{ "bios", HAS_ARG, QEMU_OPTION_bios },
-#ifdef USE_KQEMU
- { "no-kqemu", 0, QEMU_OPTION_no_kqemu },
- { "kernel-kqemu", 0, QEMU_OPTION_kernel_kqemu },
-#endif
+ { "accel", HAS_ARG, QEMU_OPTION_accel},
#if defined(TARGET_PPC) || defined(TARGET_SPARC)
{ "g", 1, QEMU_OPTION_g },
#endif
@@ -9264,14 +9238,15 @@ int main(int argc, char **argv)
win2k_install_hack = 1;
break;
#endif
-#ifdef USE_KQEMU
- case QEMU_OPTION_no_kqemu:
- kqemu_allowed = 0;
- break;
- case QEMU_OPTION_kernel_kqemu:
- kqemu_allowed = 2;
+ case QEMU_OPTION_accel:
+ {
+ int i;
+ for (i = 0; i < ARRAY_SIZE(available_accels); i++) {
+ if (!strcasecmp(optarg, available_accels[i]->name))
+ register_qemu_accel(available_accels[i]);
+ }
+ }
break;
-#endif
case QEMU_OPTION_usb:
usb_enabled = 1;
break;
@@ -9413,6 +9388,9 @@ int main(int argc, char **argv)
exit(1);
}
+ /* Basic handler for the noaccel case */
+ register_qemu_accel(&noaccel);
+
if (nographic) {
if (serial_device_index == 0)
serial_devices[0] = "stdio";
@@ -9476,10 +9454,6 @@ int main(int argc, char **argv)
exit(1);
}
-#ifdef USE_KQEMU
- if (smp_cpus > 1)
- kqemu_allowed = 0;
-#endif
linux_boot = (kernel_filename != NULL);
net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
@@ -9600,6 +9574,11 @@ int main(int argc, char **argv)
/* init the dynamic translator */
cpu_exec_init_all(tb_size * 1024 * 1024);
+ if (accel_start(smp_cpus)) {
+ fprintf(stderr, "qemu: error, no suitable accelerator found\n");
+ exit(1);
+ }
+
bdrv_init();
/* we always create the cdrom drive, even if no disk is there */
- [Qemu-devel] [PATCH 0/32] New shot at accelerators,
Glauber Costa <=
- [Qemu-devel] [PATCH 01/32] use anonymous memory for kqemu., Glauber Costa, 2008/10/23
- [Qemu-devel] Re: [PATCH 01/32] use anonymous memory for kqemu., Jan Kiszka, 2008/10/23
- [Qemu-devel] Re: [PATCH 01/32] use anonymous memory for kqemu., Anthony Liguori, 2008/10/23
- [Qemu-devel] Re: [PATCH 01/32] use anonymous memory for kqemu., Jan Kiszka, 2008/10/23
- [Qemu-devel] Re: [PATCH 01/32] use anonymous memory for kqemu., Anthony Liguori, 2008/10/23
- Re: [Qemu-devel] Re: [PATCH 01/32] use anonymous memory for kqemu., Leonardo Reiter, 2008/10/23
- Re: [Qemu-devel] Re: [PATCH 01/32] use anonymous memory for kqemu., Leonardo Reiter, 2008/10/23
- Re: [Qemu-devel] Re: [PATCH 01/32] use anonymous memory for kqemu., Andreas Färber, 2008/10/24
- Re: [Qemu-devel] Re: [PATCH 01/32] use anonymous memory for kqemu., Ben Taylor, 2008/10/24
- [Qemu-devel] QEMU on Solaris 10 (was: [PATCH 01/32] use anonymous memory for kqemu.), Andreas Färber, 2008/10/25