qemu-devel
[Top][All Lists]
Advanced

[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 */





reply via email to

[Prev in Thread] Current Thread [Next in Thread]