]> git.proxmox.com Git - qemu.git/blobdiff - target-i386/op_helper.c
iothread: replace fair_mutex with a condition variable
[qemu.git] / target-i386 / op_helper.c
index bb7661877a9e0f6eef94ba8093886f659e4739ed..315e18b9a4c3f1e2e6962f433e754810574b9867 100644 (file)
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  */
-#define CPU_NO_GLOBAL_REGS
+
+#include <math.h>
 #include "exec.h"
 #include "host-utils.h"
+#include "ioport.h"
 
 //#define DEBUG_PCALL
 
+
+#ifdef DEBUG_PCALL
+#  define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
+#  define LOG_PCALL_STATE(env) \
+          log_cpu_state_mask(CPU_LOG_PCALL, (env), X86_DUMP_CCOP)
+#else
+#  define LOG_PCALL(...) do { } while (0)
+#  define LOG_PCALL_STATE(env) do { } while (0)
+#endif
+
+
 #if 0
 #define raise_exception_err(a, b)\
 do {\
-    if (logfile)\
-        fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
+    qemu_log("raise_exception line=%d\n", __LINE__);\
     (raise_exception_err)(a, b);\
 } while (0)
 #endif
 
-const uint8_t parity_table[256] = {
+static const uint8_t parity_table[256] = {
     CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
     0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
     0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
@@ -68,7 +79,7 @@ const uint8_t parity_table[256] = {
 };
 
 /* modulo 17 table */
-const uint8_t rclw_table[32] = {
+static const uint8_t rclw_table[32] = {
     0, 1, 2, 3, 4, 5, 6, 7,
     8, 9,10,11,12,13,14,15,
    16, 0, 1, 2, 3, 4, 5, 6,
@@ -76,27 +87,20 @@ const uint8_t rclw_table[32] = {
 };
 
 /* modulo 9 table */
-const uint8_t rclb_table[32] = {
+static const uint8_t rclb_table[32] = {
     0, 1, 2, 3, 4, 5, 6, 7,
     8, 0, 1, 2, 3, 4, 5, 6,
     7, 8, 0, 1, 2, 3, 4, 5,
     6, 7, 8, 0, 1, 2, 3, 4,
 };
 
-const CPU86_LDouble f15rk[7] =
-{
-    0.00000000000000000000L,
-    1.00000000000000000000L,
-    3.14159265358979323851L,  /*pi*/
-    0.30102999566398119523L,  /*lg2*/
-    0.69314718055994530943L,  /*ln2*/
-    1.44269504088896340739L,  /*l2e*/
-    3.32192809488736234781L,  /*l2t*/
-};
+#define floatx80_lg2 make_floatx80( 0x3ffd, 0x9a209a84fbcff799LL )
+#define floatx80_l2e make_floatx80( 0x3fff, 0xb8aa3b295c17f0bcLL )
+#define floatx80_l2t make_floatx80( 0x4000, 0xd49a784bcd1b8afeLL )
 
 /* broken thread support */
 
-spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
 
 void helper_lock(void)
 {
@@ -116,7 +120,7 @@ void helper_write_eflags(target_ulong t0, uint32_t update_mask)
 target_ulong helper_read_eflags(void)
 {
     uint32_t eflags;
-    eflags = cc_table[CC_OP].compute_all();
+    eflags = helper_cc_compute_all(CC_OP);
     eflags |= (DF & DF_MASK);
     eflags |= env->eflags & ~(VM_MASK | RF_MASK);
     return eflags;
@@ -276,10 +280,7 @@ static void switch_tss(int tss_selector,
     target_ulong ptr;
 
     type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
-#ifdef DEBUG_PCALL
-    if (loglevel & CPU_LOG_PCALL)
-        fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
-#endif
+    LOG_PCALL("switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
 
     /* if task gate, we read the TSS segment and we load it */
     if (type == 5) {
@@ -341,6 +342,10 @@ static void switch_tss(int tss_selector,
         new_segs[R_GS] = 0;
         new_trap = 0;
     }
+    /* XXX: avoid a compiler warning, see
+     http://support.amd.com/us/Processor_TechDocs/24593.pdf
+     chapters 12.2.5 and 13.2.4 on how to implement TSS Trap bit */
+    (void)new_trap;
 
     /* NOTE: we must avoid memory exceptions during the task switch,
        so we make dummy accesses before */
@@ -496,6 +501,17 @@ static void switch_tss(int tss_selector,
         /* XXX: different exception if CALL ? */
         raise_exception_err(EXCP0D_GPF, 0);
     }
+
+#ifndef CONFIG_USER_ONLY
+    /* reset local breakpoints */
+    if (env->dr[7] & 0x55) {
+        for (i = 0; i < 4; i++) {
+            if (hw_breakpoint_enabled(env->dr[7], i) == 0x1)
+                hw_breakpoint_remove(env, i);
+        }
+        env->dr[7] &= ~0x55;
+    }
+#endif
 }
 
 /* check if Port I/O is allowed in TSS */
@@ -540,32 +556,32 @@ void helper_check_iol(uint32_t t0)
 
 void helper_outb(uint32_t port, uint32_t data)
 {
-    cpu_outb(env, port, data & 0xff);
+    cpu_outb(port, data & 0xff);
 }
 
 target_ulong helper_inb(uint32_t port)
 {
-    return cpu_inb(env, port);
+    return cpu_inb(port);
 }
 
 void helper_outw(uint32_t port, uint32_t data)
 {
-    cpu_outw(env, port, data & 0xffff);
+    cpu_outw(port, data & 0xffff);
 }
 
 target_ulong helper_inw(uint32_t port)
 {
-    return cpu_inw(env, port);
+    return cpu_inw(port);
 }
 
 void helper_outl(uint32_t port, uint32_t data)
 {
-    cpu_outl(env, port, data);
+    cpu_outl(port, data);
 }
 
 target_ulong helper_inl(uint32_t port)
 {
-    return cpu_inl(env, port);
+    return cpu_inl(port);
 }
 
 static inline unsigned int get_sp_mask(unsigned int e2)
@@ -576,6 +592,21 @@ static inline unsigned int get_sp_mask(unsigned int e2)
         return 0xffff;
 }
 
+static int exeption_has_error_code(int intno)
+{
+        switch(intno) {
+        case 8:
+        case 10:
+        case 11:
+        case 12:
+        case 13:
+        case 14:
+        case 17:
+            return 1;
+        }
+       return 0;
+}
+
 #ifdef TARGET_X86_64
 #define SET_ESP(val, sp_mask)\
 do {\
@@ -590,6 +621,10 @@ do {\
 #define SET_ESP(val, sp_mask) ESP = (ESP & ~(sp_mask)) | ((val) & (sp_mask))
 #endif
 
+/* in 64-bit machines, this can overflow. So this segment addition macro
+ * can be used to trim the value to 32-bit whenever needed */
+#define SEG_ADDL(ssp, sp, sp_mask) ((uint32_t)((ssp) + (sp & (sp_mask))))
+
 /* XXX: add a is_user flag to have proper security support */
 #define PUSHW(ssp, sp, sp_mask, val)\
 {\
@@ -600,7 +635,7 @@ do {\
 #define PUSHL(ssp, sp, sp_mask, val)\
 {\
     sp -= 4;\
-    stl_kernel((ssp) + (sp & (sp_mask)), (val));\
+    stl_kernel(SEG_ADDL(ssp, sp, sp_mask), (uint32_t)(val));\
 }
 
 #define POPW(ssp, sp, sp_mask, val)\
@@ -611,7 +646,7 @@ do {\
 
 #define POPL(ssp, sp, sp_mask, val)\
 {\
-    val = (uint32_t)ldl_kernel((ssp) + (sp & (sp_mask)));\
+    val = (uint32_t)ldl_kernel(SEG_ADDL(ssp, sp, sp_mask));\
     sp += 4;\
 }
 
@@ -623,23 +658,12 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
     target_ulong ptr, ssp;
     int type, dpl, selector, ss_dpl, cpl;
     int has_error_code, new_stack, shift;
-    uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
+    uint32_t e1, e2, offset, ss = 0, esp, ss_e1 = 0, ss_e2 = 0;
     uint32_t old_eip, sp_mask;
 
     has_error_code = 0;
-    if (!is_int && !is_hw) {
-        switch(intno) {
-        case 8:
-        case 10:
-        case 11:
-        case 12:
-        case 13:
-        case 14:
-        case 17:
-            has_error_code = 1;
-            break;
-        }
-    }
+    if (!is_int && !is_hw)
+        has_error_code = exeption_has_error_code(intno);
     if (is_int)
         old_eip = next_eip;
     else
@@ -689,7 +713,7 @@ static void do_interrupt_protected(int intno, int is_int, int error_code,
     }
     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
     cpl = env->hflags & HF_CPL_MASK;
-    /* check privledge if software int */
+    /* check privilege if software int */
     if (is_int && dpl < cpl)
         raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
     /* check valid bit */
@@ -863,19 +887,8 @@ static void do_interrupt64(int intno, int is_int, int error_code,
     target_ulong old_eip, esp, offset;
 
     has_error_code = 0;
-    if (!is_int && !is_hw) {
-        switch(intno) {
-        case 8:
-        case 10:
-        case 11:
-        case 12:
-        case 13:
-        case 14:
-        case 17:
-            has_error_code = 1;
-            break;
-        }
-    }
+    if (!is_int && !is_hw)
+        has_error_code = exeption_has_error_code(intno);
     if (is_int)
         old_eip = next_eip;
     else
@@ -900,7 +913,7 @@ static void do_interrupt64(int intno, int is_int, int error_code,
     }
     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
     cpl = env->hflags & HF_CPL_MASK;
-    /* check privledge if software int */
+    /* check privilege if software int */
     if (is_int && dpl < cpl)
         raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
     /* check valid bit */
@@ -980,12 +993,13 @@ static void do_interrupt64(int intno, int is_int, int error_code,
 }
 #endif
 
+#ifdef TARGET_X86_64
 #if defined(CONFIG_USER_ONLY)
 void helper_syscall(int next_eip_addend)
 {
     env->exception_index = EXCP_SYSCALL;
     env->exception_next_eip = env->eip + next_eip_addend;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 #else
 void helper_syscall(int next_eip_addend)
@@ -996,7 +1010,6 @@ void helper_syscall(int next_eip_addend)
         raise_exception_err(EXCP06_ILLOP, 0);
     }
     selector = (env->star >> 32) & 0xffff;
-#ifdef TARGET_X86_64
     if (env->hflags & HF_LMA_MASK) {
         int code64;
 
@@ -1022,9 +1035,7 @@ void helper_syscall(int next_eip_addend)
             env->eip = env->lstar;
         else
             env->eip = env->cstar;
-    } else
-#endif
-    {
+    } else {
         ECX = (uint32_t)(env->eip + next_eip_addend);
 
         cpu_x86_set_cpl(env, 0);
@@ -1043,7 +1054,9 @@ void helper_syscall(int next_eip_addend)
     }
 }
 #endif
+#endif
 
+#ifdef TARGET_X86_64
 void helper_sysret(int dflag)
 {
     int cpl, selector;
@@ -1056,7 +1069,6 @@ void helper_sysret(int dflag)
         raise_exception_err(EXCP0D_GPF, 0);
     }
     selector = (env->star >> 48) & 0xffff;
-#ifdef TARGET_X86_64
     if (env->hflags & HF_LMA_MASK) {
         if (dflag == 2) {
             cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
@@ -1082,9 +1094,7 @@ void helper_sysret(int dflag)
         load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
                     IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
         cpu_x86_set_cpl(env, 3);
-    } else
-#endif
-    {
+    } else {
         cpu_x86_load_seg_cache(env, R_CS, selector | 3,
                                0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
@@ -1099,15 +1109,8 @@ 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
 }
+#endif
 
 /* real mode interrupt */
 static void do_interrupt_real(int intno, int is_int, int error_code,
@@ -1146,9 +1149,10 @@ static void do_interrupt_real(int intno, int is_int, int error_code,
     env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
 }
 
+#if defined(CONFIG_USER_ONLY)
 /* fake user mode interrupt */
-void do_interrupt_user(int intno, int is_int, int error_code,
-                       target_ulong next_eip)
+static void do_interrupt_user(int intno, int is_int, int error_code,
+                              target_ulong next_eip)
 {
     SegmentCache *dt;
     target_ulong ptr;
@@ -1166,7 +1170,7 @@ void do_interrupt_user(int intno, int is_int, int error_code,
 
     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
     cpl = env->hflags & HF_CPL_MASK;
-    /* check privledge if software int */
+    /* check privilege if software int */
     if (is_int && dpl < cpl)
         raise_exception_err(EXCP0D_GPF, (intno << shift) + 2);
 
@@ -1177,47 +1181,73 @@ void do_interrupt_user(int intno, int is_int, int error_code,
         EIP = next_eip;
 }
 
+#else
+
+static void handle_even_inj(int intno, int is_int, int error_code,
+               int is_hw, int rm)
+{
+    uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
+    if (!(event_inj & SVM_EVTINJ_VALID)) {
+           int type;
+           if (is_int)
+                   type = SVM_EVTINJ_TYPE_SOFT;
+           else
+                   type = SVM_EVTINJ_TYPE_EXEPT;
+           event_inj = intno | type | SVM_EVTINJ_VALID;
+           if (!rm && exeption_has_error_code(intno)) {
+                   event_inj |= SVM_EVTINJ_VALID_ERR;
+                   stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err), error_code);
+           }
+           stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj);
+    }
+}
+#endif
+
 /*
  * Begin execution of an interruption. is_int is TRUE if coming from
  * the int instruction. next_eip is the EIP value AFTER the interrupt
  * instruction. It is only relevant if is_int is TRUE.
  */
-void do_interrupt(int intno, int is_int, int error_code,
-                  target_ulong next_eip, int is_hw)
+static void do_interrupt_all(int intno, int is_int, int error_code,
+                             target_ulong next_eip, int is_hw)
 {
-    if (loglevel & CPU_LOG_INT) {
+    if (qemu_loglevel_mask(CPU_LOG_INT)) {
         if ((env->cr[0] & CR0_PE_MASK)) {
             static int count;
-            fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
+            qemu_log("%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
                     count, intno, error_code, is_int,
                     env->hflags & HF_CPL_MASK,
                     env->segs[R_CS].selector, EIP,
                     (int)env->segs[R_CS].base + EIP,
                     env->segs[R_SS].selector, ESP);
             if (intno == 0x0e) {
-                fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]);
+                qemu_log(" CR2=" TARGET_FMT_lx, env->cr[2]);
             } else {
-                fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX);
+                qemu_log(" EAX=" TARGET_FMT_lx, EAX);
             }
-            fprintf(logfile, "\n");
-            cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
+            qemu_log("\n");
+            log_cpu_state(env, X86_DUMP_CCOP);
 #if 0
             {
                 int i;
-                uint8_t *ptr;
-                fprintf(logfile, "       code=");
+                target_ulong ptr;
+                qemu_log("       code=");
                 ptr = env->segs[R_CS].base + env->eip;
                 for(i = 0; i < 16; i++) {
-                    fprintf(logfile, " %02x", ldub(ptr + i));
+                    qemu_log(" %02x", ldub(ptr + i));
                 }
-                fprintf(logfile, "\n");
+                qemu_log("\n");
             }
 #endif
             count++;
         }
     }
     if (env->cr[0] & CR0_PE_MASK) {
-#if TARGET_X86_64
+#if !defined(CONFIG_USER_ONLY)
+        if (env->hflags & HF_SVMI_MASK)
+            handle_even_inj(intno, is_int, error_code, is_hw, 0);
+#endif
+#ifdef TARGET_X86_64
         if (env->hflags & HF_LMA_MASK) {
             do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
         } else
@@ -1226,10 +1256,64 @@ void do_interrupt(int intno, int is_int, int error_code,
             do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
         }
     } else {
+#if !defined(CONFIG_USER_ONLY)
+        if (env->hflags & HF_SVMI_MASK)
+            handle_even_inj(intno, is_int, error_code, is_hw, 1);
+#endif
         do_interrupt_real(intno, is_int, error_code, next_eip);
     }
+
+#if !defined(CONFIG_USER_ONLY)
+    if (env->hflags & HF_SVMI_MASK) {
+           uint32_t event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
+           stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
+    }
+#endif
+}
+
+void do_interrupt(CPUState *env1)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+#if defined(CONFIG_USER_ONLY)
+    /* if user mode only, we simulate a fake exception
+       which will be handled outside the cpu execution
+       loop */
+    do_interrupt_user(env->exception_index,
+                      env->exception_is_int,
+                      env->error_code,
+                      env->exception_next_eip);
+    /* successfully delivered */
+    env->old_exception = -1;
+#else
+    /* simulate a real cpu exception. On i386, it can
+       trigger new exceptions, but we do not handle
+       double or triple faults yet. */
+    do_interrupt_all(env->exception_index,
+                     env->exception_is_int,
+                     env->error_code,
+                     env->exception_next_eip, 0);
+    /* successfully delivered */
+    env->old_exception = -1;
+#endif
+    env = saved_env;
 }
 
+void do_interrupt_x86_hardirq(CPUState *env1, int intno, int is_hw)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    do_interrupt_all(intno, 0, 0, 0, is_hw);
+    env = saved_env;
+}
+
+/* This should come from sysemu.h - if we could include it here... */
+void qemu_system_reset_request(void);
+
 /*
  * Check nested exceptions and change to double or triple fault if
  * needed. It should only be called, if this is not an interrupt.
@@ -1243,12 +1327,20 @@ static int check_exception(int intno, int *error_code)
     int second_contributory = intno == 0 ||
                                (intno >= 10 && intno <= 13);
 
-    if (loglevel & CPU_LOG_INT)
-        fprintf(logfile, "check_exception old: 0x%x new 0x%x\n",
+    qemu_log_mask(CPU_LOG_INT, "check_exception old: 0x%x new 0x%x\n",
                 env->old_exception, intno);
 
-    if (env->old_exception == EXCP08_DBLE)
-        cpu_abort(env, "triple fault");
+#if !defined(CONFIG_USER_ONLY)
+    if (env->old_exception == EXCP08_DBLE) {
+        if (env->hflags & HF_SVMI_MASK)
+            helper_vmexit(SVM_EXIT_SHUTDOWN, 0); /* does not return */
+
+        qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
+
+        qemu_system_reset_request();
+        return EXCP_HLT;
+    }
+#endif
 
     if ((first_contributory && second_contributory)
         || (env->old_exception == EXCP0E_PAGE &&
@@ -1270,8 +1362,8 @@ static int check_exception(int intno, int *error_code)
  * EIP value AFTER the interrupt instruction. It is only relevant if
  * is_int is TRUE.
  */
-void raise_interrupt(int intno, int is_int, int error_code,
-                     int next_eip_addend)
+static void QEMU_NORETURN raise_interrupt(int intno, int is_int, int error_code,
+                                          int next_eip_addend)
 {
     if (!is_int) {
         helper_svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
@@ -1284,12 +1376,12 @@ void raise_interrupt(int intno, int is_int, int error_code,
     env->error_code = error_code;
     env->exception_is_int = is_int;
     env->exception_next_eip = env->eip + next_eip_addend;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 /* shortcuts to generate exceptions */
 
-void (raise_exception_err)(int exception_index, int error_code)
+void raise_exception_err(int exception_index, int error_code)
 {
     raise_interrupt(exception_index, 0, error_code, 0);
 }
@@ -1299,11 +1391,16 @@ void raise_exception(int exception_index)
     raise_interrupt(exception_index, 0, 0, 0);
 }
 
+void raise_exception_env(int exception_index, CPUState *nenv)
+{
+    env = nenv;
+    raise_exception(exception_index);
+}
 /* SMM support */
 
 #if defined(CONFIG_USER_ONLY)
 
-void do_smm_enter(void)
+void do_smm_enter(CPUState *env1)
 {
 }
 
@@ -1319,16 +1416,18 @@ void helper_rsm(void)
 #define SMM_REVISION_ID 0x00020000
 #endif
 
-void do_smm_enter(void)
+void do_smm_enter(CPUState *env1)
 {
     target_ulong sm_state;
     SegmentCache *dt;
     int i, offset;
+    CPUState *saved_env;
 
-    if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "SMM: enter\n");
-        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
-    }
+    saved_env = env;
+    env = env1;
+
+    qemu_log_mask(CPU_LOG_INT, "SMM: enter\n");
+    log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
 
     env->hflags |= HF_SMM_MASK;
     cpu_smm_update(env);
@@ -1435,8 +1534,7 @@ void do_smm_enter(void)
     /* init SMM cpu state */
 
 #ifdef TARGET_X86_64
-    env->efer = 0;
-    env->hflags &= ~HF_LMA_MASK;
+    cpu_load_efer(env, 0);
 #endif
     load_eflags(0, ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
     env->eip = 0x00008000;
@@ -1453,6 +1551,7 @@ void do_smm_enter(void)
     cpu_x86_update_cr4(env, 0);
     env->dr[7] = 0x00000400;
     CC_OP = CC_OP_EFLAGS;
+    env = saved_env;
 }
 
 void helper_rsm(void)
@@ -1463,11 +1562,7 @@ void helper_rsm(void)
 
     sm_state = env->smbase + 0x8000;
 #ifdef TARGET_X86_64
-    env->efer = ldq_phys(sm_state + 0x7ed0);
-    if (env->efer & MSR_EFER_LMA)
-        env->hflags |= HF_LMA_MASK;
-    else
-        env->hflags &= ~HF_LMA_MASK;
+    cpu_load_efer(env, ldq_phys(sm_state + 0x7ed0));
 
     for(i = 0; i < 6; i++) {
         offset = 0x7e00 + i * 16;
@@ -1573,10 +1668,8 @@ void helper_rsm(void)
     env->hflags &= ~HF_SMM_MASK;
     cpu_smm_update(env);
 
-    if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "SMM: after RSM\n");
-        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
-    }
+    qemu_log_mask(CPU_LOG_INT, "SMM: after RSM\n");
+    log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
 }
 
 #endif /* !CONFIG_USER_ONLY */
@@ -1719,7 +1812,7 @@ void helper_aaa(void)
     int al, ah, af;
     int eflags;
 
-    eflags = cc_table[CC_OP].compute_all();
+    eflags = helper_cc_compute_all(CC_OP);
     af = eflags & CC_A;
     al = EAX & 0xff;
     ah = (EAX >> 8) & 0xff;
@@ -1735,7 +1828,6 @@ void helper_aaa(void)
     }
     EAX = (EAX & ~0xffff) | al | (ah << 8);
     CC_SRC = eflags;
-    FORCE_RET();
 }
 
 void helper_aas(void)
@@ -1744,7 +1836,7 @@ void helper_aas(void)
     int al, ah, af;
     int eflags;
 
-    eflags = cc_table[CC_OP].compute_all();
+    eflags = helper_cc_compute_all(CC_OP);
     af = eflags & CC_A;
     al = EAX & 0xff;
     ah = (EAX >> 8) & 0xff;
@@ -1760,7 +1852,6 @@ void helper_aas(void)
     }
     EAX = (EAX & ~0xffff) | al | (ah << 8);
     CC_SRC = eflags;
-    FORCE_RET();
 }
 
 void helper_daa(void)
@@ -1768,7 +1859,7 @@ void helper_daa(void)
     int al, af, cf;
     int eflags;
 
-    eflags = cc_table[CC_OP].compute_all();
+    eflags = helper_cc_compute_all(CC_OP);
     cf = eflags & CC_C;
     af = eflags & CC_A;
     al = EAX & 0xff;
@@ -1788,7 +1879,6 @@ void helper_daa(void)
     eflags |= parity_table[al]; /* pf */
     eflags |= (al & 0x80); /* sf */
     CC_SRC = eflags;
-    FORCE_RET();
 }
 
 void helper_das(void)
@@ -1796,7 +1886,7 @@ void helper_das(void)
     int al, al1, af, cf;
     int eflags;
 
-    eflags = cc_table[CC_OP].compute_all();
+    eflags = helper_cc_compute_all(CC_OP);
     cf = eflags & CC_C;
     af = eflags & CC_A;
     al = EAX & 0xff;
@@ -1819,13 +1909,12 @@ void helper_das(void)
     eflags |= parity_table[al]; /* pf */
     eflags |= (al & 0x80); /* sf */
     CC_SRC = eflags;
-    FORCE_RET();
 }
 
 void helper_into(int next_eip_addend)
 {
     int eflags;
-    eflags = cc_table[CC_OP].compute_all();
+    eflags = helper_cc_compute_all(CC_OP);
     if (eflags & CC_O) {
         raise_interrupt(EXCP04_INTO, 1, 0, next_eip_addend);
     }
@@ -1836,12 +1925,14 @@ void helper_cmpxchg8b(target_ulong a0)
     uint64_t d;
     int eflags;
 
-    eflags = cc_table[CC_OP].compute_all();
+    eflags = helper_cc_compute_all(CC_OP);
     d = ldq(a0);
     if (d == (((uint64_t)EDX << 32) | (uint32_t)EAX)) {
         stq(a0, ((uint64_t)ECX << 32) | (uint32_t)EBX);
         eflags |= CC_Z;
     } else {
+        /* always do the store */
+        stq(a0, d); 
         EDX = (uint32_t)(d >> 32);
         EAX = (uint32_t)d;
         eflags &= ~CC_Z;
@@ -1855,7 +1946,9 @@ void helper_cmpxchg16b(target_ulong a0)
     uint64_t d0, d1;
     int eflags;
 
-    eflags = cc_table[CC_OP].compute_all();
+    if ((a0 & 0xf) != 0)
+        raise_exception(EXCP0D_GPF);
+    eflags = helper_cc_compute_all(CC_OP);
     d0 = ldq(a0);
     d1 = ldq(a0 + 8);
     if (d0 == EAX && d1 == EDX) {
@@ -1863,6 +1956,9 @@ void helper_cmpxchg16b(target_ulong a0)
         stq(a0 + 8, ECX);
         eflags |= CC_Z;
     } else {
+        /* always do the store */
+        stq(a0, d0); 
+        stq(a0 + 8, d1); 
         EDX = d1;
         EAX = d0;
         eflags &= ~CC_Z;
@@ -1873,115 +1969,24 @@ void helper_cmpxchg16b(target_ulong a0)
 
 void helper_single_step(void)
 {
-    env->dr[6] |= 0x4000;
-    raise_exception(EXCP01_SSTP);
+#ifndef CONFIG_USER_ONLY
+    check_hw_breakpoints(env, 1);
+    env->dr[6] |= DR6_BS;
+#endif
+    raise_exception(EXCP01_DB);
 }
 
 void helper_cpuid(void)
 {
-    uint32_t index;
+    uint32_t eax, ebx, ecx, edx;
 
     helper_svm_check_intercept_param(SVM_EXIT_CPUID, 0);
-    
-    index = (uint32_t)EAX;
-    /* test if maximum index reached */
-    if (index & 0x80000000) {
-        if (index > env->cpuid_xlevel)
-            index = env->cpuid_level;
-    } else {
-        if (index > env->cpuid_level)
-            index = env->cpuid_level;
-    }
 
-    switch(index) {
-    case 0:
-        EAX = env->cpuid_level;
-        EBX = env->cpuid_vendor1;
-        EDX = env->cpuid_vendor2;
-        ECX = env->cpuid_vendor3;
-        break;
-    case 1:
-        EAX = env->cpuid_version;
-        EBX = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
-        ECX = env->cpuid_ext_features;
-        EDX = env->cpuid_features;
-        break;
-    case 2:
-        /* cache info: needed for Pentium Pro compatibility */
-        EAX = 1;
-        EBX = 0;
-        ECX = 0;
-        EDX = 0x2c307d;
-        break;
-    case 0x80000000:
-        EAX = env->cpuid_xlevel;
-        EBX = env->cpuid_vendor1;
-        EDX = env->cpuid_vendor2;
-        ECX = env->cpuid_vendor3;
-        break;
-    case 0x80000001:
-        EAX = env->cpuid_features;
-        EBX = 0;
-        ECX = env->cpuid_ext3_features;
-        EDX = env->cpuid_ext2_features;
-        break;
-    case 0x80000002:
-    case 0x80000003:
-    case 0x80000004:
-        EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0];
-        EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1];
-        ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2];
-        EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3];
-        break;
-    case 0x80000005:
-        /* cache info (L1 cache) */
-        EAX = 0x01ff01ff;
-        EBX = 0x01ff01ff;
-        ECX = 0x40020140;
-        EDX = 0x40020140;
-        break;
-    case 0x80000006:
-        /* cache info (L2 cache) */
-        EAX = 0;
-        EBX = 0x42004200;
-        ECX = 0x02008140;
-        EDX = 0;
-        break;
-    case 0x80000008:
-        /* virtual & phys address size in low 2 bytes. */
-/* XXX: This value must match the one used in the MMU code. */ 
-#if defined(TARGET_X86_64)
-#  if defined(USE_KQEMU)
-        EAX = 0x00003020;      /* 48 bits virtual, 32 bits physical */
-#  else
-/* XXX: The physical address space is limited to 42 bits in exec.c. */
-        EAX = 0x00003028;      /* 48 bits virtual, 40 bits physical */
-#  endif
-#else
-# if defined(USE_KQEMU)
-        EAX = 0x00000020;      /* 32 bits physical */
-#  else
-        EAX = 0x00000024;      /* 36 bits physical */
-#  endif
-#endif
-        EBX = 0;
-        ECX = 0;
-        EDX = 0;
-        break;
-    case 0x8000000A:
-        EAX = 0x00000001;
-        EBX = 0;
-        ECX = 0;
-        EDX = 0;
-        break;
-    default:
-        /* reserved values: zero */
-        EAX = 0;
-        EBX = 0;
-        ECX = 0;
-        EDX = 0;
-        break;
-    }
+    cpu_x86_cpuid(env, (uint32_t)EAX, (uint32_t)ECX, &eax, &ebx, &ecx, &edx);
+    EAX = eax;
+    EBX = ebx;
+    ECX = ecx;
+    EDX = edx;
 }
 
 void helper_enter_level(int level, int data32, target_ulong t1)
@@ -2222,7 +2227,7 @@ void helper_load_seg(int seg_reg, int selector)
                        get_seg_limit(e1, e2),
                        e2);
 #if 0
-        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
+        qemu_log("load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
                 selector, (unsigned long)sc->base, sc->limit, sc->flags);
 #endif
     }
@@ -2350,28 +2355,19 @@ void helper_lcall_protected(int new_cs, target_ulong new_eip,
 {
     int new_stack, i;
     uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
-    uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
+    uint32_t ss = 0, ss_e1 = 0, ss_e2 = 0, sp, type, ss_dpl, sp_mask;
     uint32_t val, limit, old_sp_mask;
     target_ulong ssp, old_ssp, next_eip;
 
     next_eip = env->eip + next_eip_addend;
-#ifdef DEBUG_PCALL
-    if (loglevel & CPU_LOG_PCALL) {
-        fprintf(logfile, "lcall %04x:%08x s=%d\n",
-                new_cs, (uint32_t)new_eip, shift);
-        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
-    }
-#endif
+    LOG_PCALL("lcall %04x:%08x s=%d\n", new_cs, (uint32_t)new_eip, shift);
+    LOG_PCALL_STATE(env);
     if ((new_cs & 0xfffc) == 0)
         raise_exception_err(EXCP0D_GPF, 0);
     if (load_segment(&e1, &e2, new_cs) != 0)
         raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
     cpl = env->hflags & HF_CPL_MASK;
-#ifdef DEBUG_PCALL
-    if (loglevel & CPU_LOG_PCALL) {
-        fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
-    }
-#endif
+    LOG_PCALL("desc=%08x:%08x\n", e1, e2);
     if (e2 & DESC_S_MASK) {
         if (!(e2 & DESC_CS_MASK))
             raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
@@ -2475,11 +2471,8 @@ void helper_lcall_protected(int new_cs, target_ulong new_eip,
         if (!(e2 & DESC_C_MASK) && dpl < cpl) {
             /* to inner privilege */
             get_ss_esp_from_tss(&ss, &sp, dpl);
-#ifdef DEBUG_PCALL
-            if (loglevel & CPU_LOG_PCALL)
-                fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
+            LOG_PCALL("new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
                         ss, sp, param_count, ESP);
-#endif
             if ((ss & 0xfffc) == 0)
                 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
             if ((ss & 3) != dpl)
@@ -2555,12 +2548,6 @@ 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
 }
 
 /* real and vm86 mode iret */
@@ -2586,7 +2573,8 @@ void helper_iret_real(int shift)
         POPW(ssp, sp, sp_mask, new_eflags);
     }
     ESP = (ESP & ~sp_mask) | (sp & sp_mask);
-    load_seg_vm(R_CS, new_cs);
+    env->segs[R_CS].selector = new_cs;
+    env->segs[R_CS].base = (new_cs << 4);
     env->eip = new_eip;
     if (env->eflags & VM_MASK)
         eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
@@ -2595,7 +2583,7 @@ void helper_iret_real(int shift)
     if (shift == 0)
         eflags_mask &= 0xffff;
     load_eflags(new_eflags, eflags_mask);
-    env->hflags &= ~HF_NMI_MASK;
+    env->hflags2 &= ~HF2_NMI_MASK;
 }
 
 static inline void validate_seg(int seg_reg, int cpl)
@@ -2665,13 +2653,9 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
         if (is_iret)
             POPW(ssp, sp, sp_mask, new_eflags);
     }
-#ifdef DEBUG_PCALL
-    if (loglevel & CPU_LOG_PCALL) {
-        fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
-                new_cs, new_eip, shift, addend);
-        cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
-    }
-#endif
+    LOG_PCALL("lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
+              new_cs, new_eip, shift, addend);
+    LOG_PCALL_STATE(env);
     if ((new_cs & 0xfffc) == 0)
         raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
     if (load_segment(&e1, &e2, new_cs) != 0)
@@ -2697,7 +2681,7 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
     sp += addend;
     if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
                        ((env->hflags & HF_CS64_MASK) && !is_iret))) {
-        /* return to same priledge level */
+        /* return to same privilege level */
         cpu_x86_load_seg_cache(env, R_CS, new_cs,
                        get_seg_base(e1, e2),
                        get_seg_limit(e1, e2),
@@ -2721,12 +2705,8 @@ static inline void helper_ret_protected(int shift, int is_iret, int addend)
             POPW(ssp, sp, sp_mask, new_esp);
             POPW(ssp, sp, sp_mask, new_ss);
         }
-#ifdef DEBUG_PCALL
-        if (loglevel & CPU_LOG_PCALL) {
-            fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
+        LOG_PCALL("new ss:esp=%04x:" TARGET_FMT_lx "\n",
                     new_ss, new_esp);
-        }
-#endif
         if ((new_ss & 0xfffc) == 0) {
 #ifdef TARGET_X86_64
             /* NULL ss is allowed in long mode if cpl != 3*/
@@ -2847,25 +2827,12 @@ void helper_iret_protected(int shift, int next_eip)
     } else {
         helper_ret_protected(shift, 1, 0);
     }
-    env->hflags &= ~HF_NMI_MASK;
-#ifdef USE_KQEMU
-    if (kqemu_is_ok(env)) {
-        CC_OP = CC_OP_EFLAGS;
-        env->exception_index = -1;
-        cpu_loop_exit();
-    }
-#endif
+    env->hflags2 &= ~HF2_NMI_MASK;
 }
 
 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
 }
 
 void helper_sysenter(void)
@@ -2875,11 +2842,23 @@ void helper_sysenter(void)
     }
     env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
     cpu_x86_set_cpl(env, 0);
-    cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
-                           0, 0xffffffff,
-                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
-                           DESC_S_MASK |
-                           DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+
+#ifdef TARGET_X86_64
+    if (env->hflags & HF_LMA_MASK) {
+        cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
+    } else
+#endif
+    {
+        cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+    }
     cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
                            0, 0xffffffff,
                            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
@@ -2889,7 +2868,7 @@ void helper_sysenter(void)
     EIP = env->sysenter_eip;
 }
 
-void helper_sysexit(void)
+void helper_sysexit(int dflag)
 {
     int cpl;
 
@@ -2898,24 +2877,34 @@ void helper_sysexit(void)
         raise_exception_err(EXCP0D_GPF, 0);
     }
     cpu_x86_set_cpl(env, 3);
-    cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
-                           0, 0xffffffff,
-                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
-                           DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
-                           DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
-    cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
-                           0, 0xffffffff,
-                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
-                           DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
-                           DESC_W_MASK | DESC_A_MASK);
+#ifdef TARGET_X86_64
+    if (dflag == 2) {
+        cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
+        cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_W_MASK | DESC_A_MASK);
+    } else
+#endif
+    {
+        cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+        cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_W_MASK | DESC_A_MASK);
+    }
     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)
@@ -2927,6 +2916,10 @@ target_ulong helper_read_crN(int reg)
 void helper_write_crN(int reg, target_ulong t0)
 {
 }
+
+void helper_movl_drN_T0(int reg, target_ulong t0)
+{
+}
 #else
 target_ulong helper_read_crN(int reg)
 {
@@ -2938,7 +2931,11 @@ target_ulong helper_read_crN(int reg)
         val = env->cr[reg];
         break;
     case 8:
-        val = cpu_get_apic_tpr(env);
+        if (!(env->hflags2 & HF2_VINTR_MASK)) {
+            val = cpu_get_apic_tpr(env->apic_state);
+        } else {
+            val = env->v_tpr;
+        }
         break;
     }
     return val;
@@ -2958,14 +2955,34 @@ void helper_write_crN(int reg, target_ulong t0)
         cpu_x86_update_cr4(env, t0);
         break;
     case 8:
-        cpu_set_apic_tpr(env, t0);
-        env->cr[8] = t0;
+        if (!(env->hflags2 & HF2_VINTR_MASK)) {
+            cpu_set_apic_tpr(env->apic_state, t0);
+        }
+        env->v_tpr = t0 & 0x0f;
         break;
     default:
         env->cr[reg] = t0;
         break;
     }
 }
+
+void helper_movl_drN_T0(int reg, target_ulong t0)
+{
+    int i;
+
+    if (reg < 4) {
+        hw_breakpoint_remove(env, reg);
+        env->dr[reg] = t0;
+        hw_breakpoint_insert(env, reg);
+    } else if (reg == 7) {
+        for (i = 0; i < 4; i++)
+            hw_breakpoint_remove(env, i);
+        env->dr[7] = t0;
+        for (i = 0; i < 4; i++)
+            hw_breakpoint_insert(env, i);
+    } else
+        env->dr[reg] = t0;
+}
 #endif
 
 void helper_lmsw(target_ulong t0)
@@ -2982,23 +2999,10 @@ void helper_clts(void)
     env->hflags &= ~HF_TS_MASK;
 }
 
-#if !defined(CONFIG_USER_ONLY)
-target_ulong helper_movtl_T0_cr8(void)
-{
-    return cpu_get_apic_tpr(env);
-}
-#endif
-
-/* XXX: do more */
-void helper_movl_drN_T0(int reg, target_ulong t0)
-{
-    env->dr[reg] = t0;
-}
-
 void helper_invlpg(target_ulong addr)
 {
     helper_svm_check_intercept_param(SVM_EXIT_INVLPG, 0);
-    cpu_x86_flush_tlb(env, addr);
+    tlb_flush_page(env, addr);
 }
 
 void helper_rdtsc(void)
@@ -3010,11 +3014,17 @@ void helper_rdtsc(void)
     }
     helper_svm_check_intercept_param(SVM_EXIT_RDTSC, 0);
 
-    val = cpu_get_tsc(env);
+    val = cpu_get_tsc(env) + env->tsc_offset;
     EAX = (uint32_t)(val);
     EDX = (uint32_t)(val >> 32);
 }
 
+void helper_rdtscp(void)
+{
+    helper_rdtsc();
+    ECX = (uint32_t)(env->tsc_aux);
+}
+
 void helper_rdpmc(void)
 {
     if ((env->cr[4] & CR4_PCE_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
@@ -3054,7 +3064,7 @@ void helper_wrmsr(void)
         env->sysenter_eip = val;
         break;
     case MSR_IA32_APICBASE:
-        cpu_set_apic_base(env, val);
+        cpu_set_apic_base(env->apic_state, val);
         break;
     case MSR_EFER:
         {
@@ -3068,8 +3078,12 @@ void helper_wrmsr(void)
                 update_mask |= MSR_EFER_FFXSR;
             if (env->cpuid_ext2_features & CPUID_EXT2_NX)
                 update_mask |= MSR_EFER_NXE;
-            env->efer = (env->efer & ~update_mask) |
-            (val & update_mask);
+            if (env->cpuid_ext3_features & CPUID_EXT3_SVM)
+                update_mask |= MSR_EFER_SVME;
+            if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
+                update_mask |= MSR_EFER_FFXSR;
+            cpu_load_efer(env, (env->efer & ~update_mask) |
+                          (val & update_mask));
         }
         break;
     case MSR_STAR:
@@ -3101,7 +3115,66 @@ void helper_wrmsr(void)
         env->kernelgsbase = val;
         break;
 #endif
+    case MSR_MTRRphysBase(0):
+    case MSR_MTRRphysBase(1):
+    case MSR_MTRRphysBase(2):
+    case MSR_MTRRphysBase(3):
+    case MSR_MTRRphysBase(4):
+    case MSR_MTRRphysBase(5):
+    case MSR_MTRRphysBase(6):
+    case MSR_MTRRphysBase(7):
+        env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base = val;
+        break;
+    case MSR_MTRRphysMask(0):
+    case MSR_MTRRphysMask(1):
+    case MSR_MTRRphysMask(2):
+    case MSR_MTRRphysMask(3):
+    case MSR_MTRRphysMask(4):
+    case MSR_MTRRphysMask(5):
+    case MSR_MTRRphysMask(6):
+    case MSR_MTRRphysMask(7):
+        env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask = val;
+        break;
+    case MSR_MTRRfix64K_00000:
+        env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix64K_00000] = val;
+        break;
+    case MSR_MTRRfix16K_80000:
+    case MSR_MTRRfix16K_A0000:
+        env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1] = val;
+        break;
+    case MSR_MTRRfix4K_C0000:
+    case MSR_MTRRfix4K_C8000:
+    case MSR_MTRRfix4K_D0000:
+    case MSR_MTRRfix4K_D8000:
+    case MSR_MTRRfix4K_E0000:
+    case MSR_MTRRfix4K_E8000:
+    case MSR_MTRRfix4K_F0000:
+    case MSR_MTRRfix4K_F8000:
+        env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3] = val;
+        break;
+    case MSR_MTRRdefType:
+        env->mtrr_deftype = val;
+        break;
+    case MSR_MCG_STATUS:
+        env->mcg_status = val;
+        break;
+    case MSR_MCG_CTL:
+        if ((env->mcg_cap & MCG_CTL_P)
+            && (val == 0 || val == ~(uint64_t)0))
+            env->mcg_ctl = val;
+        break;
+    case MSR_TSC_AUX:
+        env->tsc_aux = val;
+        break;
     default:
+        if ((uint32_t)ECX >= MSR_MC0_CTL
+            && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
+            uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
+            if ((offset & 0x3) != 0
+                || (val == 0 || val == ~(uint64_t)0))
+                env->mce_banks[offset] = val;
+            break;
+        }
         /* XXX: exception ? */
         break;
     }
@@ -3124,7 +3197,7 @@ void helper_rdmsr(void)
         val = env->sysenter_eip;
         break;
     case MSR_IA32_APICBASE:
-        val = cpu_get_apic_base(env);
+        val = cpu_get_apic_base(env->apic_state);
         break;
     case MSR_EFER:
         val = env->efer;
@@ -3138,6 +3211,12 @@ void helper_rdmsr(void)
     case MSR_VM_HSAVE_PA:
         val = env->vm_hsave;
         break;
+    case MSR_IA32_PERF_STATUS:
+        /* tsc_increment_by_tick */
+        val = 1000ULL;
+        /* CPU multiplier */
+        val |= (((uint64_t)4ULL) << 40);
+        break;
 #ifdef TARGET_X86_64
     case MSR_LSTAR:
         val = env->lstar;
@@ -3157,8 +3236,76 @@ void helper_rdmsr(void)
     case MSR_KERNELGSBASE:
         val = env->kernelgsbase;
         break;
+    case MSR_TSC_AUX:
+        val = env->tsc_aux;
+        break;
 #endif
+    case MSR_MTRRphysBase(0):
+    case MSR_MTRRphysBase(1):
+    case MSR_MTRRphysBase(2):
+    case MSR_MTRRphysBase(3):
+    case MSR_MTRRphysBase(4):
+    case MSR_MTRRphysBase(5):
+    case MSR_MTRRphysBase(6):
+    case MSR_MTRRphysBase(7):
+        val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysBase(0)) / 2].base;
+        break;
+    case MSR_MTRRphysMask(0):
+    case MSR_MTRRphysMask(1):
+    case MSR_MTRRphysMask(2):
+    case MSR_MTRRphysMask(3):
+    case MSR_MTRRphysMask(4):
+    case MSR_MTRRphysMask(5):
+    case MSR_MTRRphysMask(6):
+    case MSR_MTRRphysMask(7):
+        val = env->mtrr_var[((uint32_t)ECX - MSR_MTRRphysMask(0)) / 2].mask;
+        break;
+    case MSR_MTRRfix64K_00000:
+        val = env->mtrr_fixed[0];
+        break;
+    case MSR_MTRRfix16K_80000:
+    case MSR_MTRRfix16K_A0000:
+        val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix16K_80000 + 1];
+        break;
+    case MSR_MTRRfix4K_C0000:
+    case MSR_MTRRfix4K_C8000:
+    case MSR_MTRRfix4K_D0000:
+    case MSR_MTRRfix4K_D8000:
+    case MSR_MTRRfix4K_E0000:
+    case MSR_MTRRfix4K_E8000:
+    case MSR_MTRRfix4K_F0000:
+    case MSR_MTRRfix4K_F8000:
+        val = env->mtrr_fixed[(uint32_t)ECX - MSR_MTRRfix4K_C0000 + 3];
+        break;
+    case MSR_MTRRdefType:
+        val = env->mtrr_deftype;
+        break;
+    case MSR_MTRRcap:
+        if (env->cpuid_features & CPUID_MTRR)
+            val = MSR_MTRRcap_VCNT | MSR_MTRRcap_FIXRANGE_SUPPORT | MSR_MTRRcap_WC_SUPPORTED;
+        else
+            /* XXX: exception ? */
+            val = 0;
+        break;
+    case MSR_MCG_CAP:
+        val = env->mcg_cap;
+        break;
+    case MSR_MCG_CTL:
+        if (env->mcg_cap & MCG_CTL_P)
+            val = env->mcg_ctl;
+        else
+            val = 0;
+        break;
+    case MSR_MCG_STATUS:
+        val = env->mcg_status;
+        break;
     default:
+        if ((uint32_t)ECX >= MSR_MC0_CTL
+            && (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
+            uint32_t offset = (uint32_t)ECX - MSR_MC0_CTL;
+            val = env->mce_banks[offset];
+            break;
+        }
         /* XXX: exception ? */
         val = 0;
         break;
@@ -3175,7 +3322,9 @@ target_ulong helper_lsl(target_ulong selector1)
     int rpl, dpl, cpl, type;
 
     selector = selector1 & 0xffff;
-    eflags = cc_table[CC_OP].compute_all();
+    eflags = helper_cc_compute_all(CC_OP);
+    if ((selector & 0xfffc) == 0)
+        goto fail;
     if (load_segment(&e1, &e2, selector) != 0)
         goto fail;
     rpl = selector & 3;
@@ -3217,7 +3366,7 @@ target_ulong helper_lar(target_ulong selector1)
     int rpl, dpl, cpl, type;
 
     selector = selector1 & 0xffff;
-    eflags = cc_table[CC_OP].compute_all();
+    eflags = helper_cc_compute_all(CC_OP);
     if ((selector & 0xfffc) == 0)
         goto fail;
     if (load_segment(&e1, &e2, selector) != 0)
@@ -3263,7 +3412,7 @@ void helper_verr(target_ulong selector1)
     int rpl, dpl, cpl;
 
     selector = selector1 & 0xffff;
-    eflags = cc_table[CC_OP].compute_all();
+    eflags = helper_cc_compute_all(CC_OP);
     if ((selector & 0xfffc) == 0)
         goto fail;
     if (load_segment(&e1, &e2, selector) != 0)
@@ -3296,7 +3445,7 @@ void helper_verw(target_ulong selector1)
     int rpl, dpl, cpl;
 
     selector = selector1 & 0xffff;
-    eflags = cc_table[CC_OP].compute_all();
+    eflags = helper_cc_compute_all(CC_OP);
     if ((selector & 0xfffc) == 0)
         goto fail;
     if (load_segment(&e1, &e2, selector) != 0)
@@ -3322,6 +3471,28 @@ void helper_verw(target_ulong selector1)
 
 /* x87 FPU helpers */
 
+static inline double floatx80_to_double(floatx80 a)
+{
+    union {
+        float64 f64;
+        double d;
+    } u;
+
+    u.f64 = floatx80_to_float64(a, &env->fp_status);
+    return u.d;
+}
+
+static inline floatx80 double_to_floatx80(double a)
+{
+    union {
+        float64 f64;
+        double d;
+    } u;
+
+    u.d = a;
+    return float64_to_floatx80(u.f64, &env->fp_status);
+}
+
 static void fpu_set_exception(int mask)
 {
     env->fpus |= mask;
@@ -3329,14 +3500,15 @@ static void fpu_set_exception(int mask)
         env->fpus |= FPUS_SE | FPUS_B;
 }
 
-static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
+static inline floatx80 helper_fdiv(floatx80 a, floatx80 b)
 {
-    if (b == 0.0)
+    if (floatx80_is_zero(b)) {
         fpu_set_exception(FPUS_ZE);
-    return a / b;
+    }
+    return floatx80_div(a, b, &env->fp_status);
 }
 
-void fpu_raise_exception(void)
+static void fpu_raise_exception(void)
 {
     if (env->cr[0] & CR0_NE_MASK) {
         raise_exception(EXCP10_COPR);
@@ -3355,7 +3527,7 @@ void helper_flds_FT0(uint32_t val)
         uint32_t i;
     } u;
     u.i = val;
-    FT0 = float32_to_floatx(u.f, &env->fp_status);
+    FT0 = float32_to_floatx80(u.f, &env->fp_status);
 }
 
 void helper_fldl_FT0(uint64_t val)
@@ -3365,12 +3537,12 @@ void helper_fldl_FT0(uint64_t val)
         uint64_t i;
     } u;
     u.i = val;
-    FT0 = float64_to_floatx(u.f, &env->fp_status);
+    FT0 = float64_to_floatx80(u.f, &env->fp_status);
 }
 
 void helper_fildl_FT0(int32_t val)
 {
-    FT0 = int32_to_floatx(val, &env->fp_status);
+    FT0 = int32_to_floatx80(val, &env->fp_status);
 }
 
 void helper_flds_ST0(uint32_t val)
@@ -3382,7 +3554,7 @@ void helper_flds_ST0(uint32_t val)
     } u;
     new_fpstt = (env->fpstt - 1) & 7;
     u.i = val;
-    env->fpregs[new_fpstt].d = float32_to_floatx(u.f, &env->fp_status);
+    env->fpregs[new_fpstt].d = float32_to_floatx80(u.f, &env->fp_status);
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
 }
@@ -3396,7 +3568,7 @@ void helper_fldl_ST0(uint64_t val)
     } u;
     new_fpstt = (env->fpstt - 1) & 7;
     u.i = val;
-    env->fpregs[new_fpstt].d = float64_to_floatx(u.f, &env->fp_status);
+    env->fpregs[new_fpstt].d = float64_to_floatx80(u.f, &env->fp_status);
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
 }
@@ -3405,7 +3577,7 @@ void helper_fildl_ST0(int32_t val)
 {
     int new_fpstt;
     new_fpstt = (env->fpstt - 1) & 7;
-    env->fpregs[new_fpstt].d = int32_to_floatx(val, &env->fp_status);
+    env->fpregs[new_fpstt].d = int32_to_floatx80(val, &env->fp_status);
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
 }
@@ -3414,7 +3586,7 @@ void helper_fildll_ST0(int64_t val)
 {
     int new_fpstt;
     new_fpstt = (env->fpstt - 1) & 7;
-    env->fpregs[new_fpstt].d = int64_to_floatx(val, &env->fp_status);
+    env->fpregs[new_fpstt].d = int64_to_floatx80(val, &env->fp_status);
     env->fpstt = new_fpstt;
     env->fptags[new_fpstt] = 0; /* validate stack entry */
 }
@@ -3425,7 +3597,7 @@ uint32_t helper_fsts_ST0(void)
         float32 f;
         uint32_t i;
     } u;
-    u.f = floatx_to_float32(ST0, &env->fp_status);
+    u.f = floatx80_to_float32(ST0, &env->fp_status);
     return u.i;
 }
 
@@ -3435,14 +3607,14 @@ uint64_t helper_fstl_ST0(void)
         float64 f;
         uint64_t i;
     } u;
-    u.f = floatx_to_float64(ST0, &env->fp_status);
+    u.f = floatx80_to_float64(ST0, &env->fp_status);
     return u.i;
 }
 
 int32_t helper_fist_ST0(void)
 {
     int32_t val;
-    val = floatx_to_int32(ST0, &env->fp_status);
+    val = floatx80_to_int32(ST0, &env->fp_status);
     if (val != (int16_t)val)
         val = -32768;
     return val;
@@ -3451,21 +3623,21 @@ int32_t helper_fist_ST0(void)
 int32_t helper_fistl_ST0(void)
 {
     int32_t val;
-    val = floatx_to_int32(ST0, &env->fp_status);
+    val = floatx80_to_int32(ST0, &env->fp_status);
     return val;
 }
 
 int64_t helper_fistll_ST0(void)
 {
     int64_t val;
-    val = floatx_to_int64(ST0, &env->fp_status);
+    val = floatx80_to_int64(ST0, &env->fp_status);
     return val;
 }
 
 int32_t helper_fistt_ST0(void)
 {
     int32_t val;
-    val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
+    val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
     if (val != (int16_t)val)
         val = -32768;
     return val;
@@ -3474,14 +3646,14 @@ int32_t helper_fistt_ST0(void)
 int32_t helper_fisttl_ST0(void)
 {
     int32_t val;
-    val = floatx_to_int32_round_to_zero(ST0, &env->fp_status);
+    val = floatx80_to_int32_round_to_zero(ST0, &env->fp_status);
     return val;
 }
 
 int64_t helper_fisttll_ST0(void)
 {
     int64_t val;
-    val = floatx_to_int64_round_to_zero(ST0, &env->fp_status);
+    val = floatx80_to_int64_round_to_zero(ST0, &env->fp_status);
     return val;
 }
 
@@ -3550,7 +3722,7 @@ void helper_fmov_STN_ST0(int st_index)
 
 void helper_fxchg_ST0_STN(int st_index)
 {
-    CPU86_LDouble tmp;
+    floatx80 tmp;
     tmp = ST(st_index);
     ST(st_index) = ST0;
     ST0 = tmp;
@@ -3564,18 +3736,16 @@ void helper_fcom_ST0_FT0(void)
 {
     int ret;
 
-    ret = floatx_compare(ST0, FT0, &env->fp_status);
+    ret = floatx80_compare(ST0, FT0, &env->fp_status);
     env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
-    FORCE_RET();
 }
 
 void helper_fucom_ST0_FT0(void)
 {
     int ret;
 
-    ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
+    ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
     env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1];
-    FORCE_RET();
 }
 
 static const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
@@ -3585,11 +3755,10 @@ void helper_fcomi_ST0_FT0(void)
     int eflags;
     int ret;
 
-    ret = floatx_compare(ST0, FT0, &env->fp_status);
-    eflags = cc_table[CC_OP].compute_all();
+    ret = floatx80_compare(ST0, FT0, &env->fp_status);
+    eflags = helper_cc_compute_all(CC_OP);
     eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
     CC_SRC = eflags;
-    FORCE_RET();
 }
 
 void helper_fucomi_ST0_FT0(void)
@@ -3597,31 +3766,30 @@ void helper_fucomi_ST0_FT0(void)
     int eflags;
     int ret;
 
-    ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
-    eflags = cc_table[CC_OP].compute_all();
+    ret = floatx80_compare_quiet(ST0, FT0, &env->fp_status);
+    eflags = helper_cc_compute_all(CC_OP);
     eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
     CC_SRC = eflags;
-    FORCE_RET();
 }
 
 void helper_fadd_ST0_FT0(void)
 {
-    ST0 += FT0;
+    ST0 = floatx80_add(ST0, FT0, &env->fp_status);
 }
 
 void helper_fmul_ST0_FT0(void)
 {
-    ST0 *= FT0;
+    ST0 = floatx80_mul(ST0, FT0, &env->fp_status);
 }
 
 void helper_fsub_ST0_FT0(void)
 {
-    ST0 -= FT0;
+    ST0 = floatx80_sub(ST0, FT0, &env->fp_status);
 }
 
 void helper_fsubr_ST0_FT0(void)
 {
-    ST0 = FT0 - ST0;
+    ST0 = floatx80_sub(FT0, ST0, &env->fp_status);
 }
 
 void helper_fdiv_ST0_FT0(void)
@@ -3638,36 +3806,34 @@ void helper_fdivr_ST0_FT0(void)
 
 void helper_fadd_STN_ST0(int st_index)
 {
-    ST(st_index) += ST0;
+    ST(st_index) = floatx80_add(ST(st_index), ST0, &env->fp_status);
 }
 
 void helper_fmul_STN_ST0(int st_index)
 {
-    ST(st_index) *= ST0;
+    ST(st_index) = floatx80_mul(ST(st_index), ST0, &env->fp_status);
 }
 
 void helper_fsub_STN_ST0(int st_index)
 {
-    ST(st_index) -= ST0;
+    ST(st_index) = floatx80_sub(ST(st_index), ST0, &env->fp_status);
 }
 
 void helper_fsubr_STN_ST0(int st_index)
 {
-    CPU86_LDouble *p;
-    p = &ST(st_index);
-    *p = ST0 - *p;
+    ST(st_index) = floatx80_sub(ST0, ST(st_index), &env->fp_status);
 }
 
 void helper_fdiv_STN_ST0(int st_index)
 {
-    CPU86_LDouble *p;
+    floatx80 *p;
     p = &ST(st_index);
     *p = helper_fdiv(*p, ST0);
 }
 
 void helper_fdivr_STN_ST0(int st_index)
 {
-    CPU86_LDouble *p;
+    floatx80 *p;
     p = &ST(st_index);
     *p = helper_fdiv(ST0, *p);
 }
@@ -3675,52 +3841,52 @@ void helper_fdivr_STN_ST0(int st_index)
 /* misc FPU operations */
 void helper_fchs_ST0(void)
 {
-    ST0 = floatx_chs(ST0);
+    ST0 = floatx80_chs(ST0);
 }
 
 void helper_fabs_ST0(void)
 {
-    ST0 = floatx_abs(ST0);
+    ST0 = floatx80_abs(ST0);
 }
 
 void helper_fld1_ST0(void)
 {
-    ST0 = f15rk[1];
+    ST0 = floatx80_one;
 }
 
 void helper_fldl2t_ST0(void)
 {
-    ST0 = f15rk[6];
+    ST0 = floatx80_l2t;
 }
 
 void helper_fldl2e_ST0(void)
 {
-    ST0 = f15rk[5];
+    ST0 = floatx80_l2e;
 }
 
 void helper_fldpi_ST0(void)
 {
-    ST0 = f15rk[2];
+    ST0 = floatx80_pi;
 }
 
 void helper_fldlg2_ST0(void)
 {
-    ST0 = f15rk[3];
+    ST0 = floatx80_lg2;
 }
 
 void helper_fldln2_ST0(void)
 {
-    ST0 = f15rk[4];
+    ST0 = floatx80_ln2;
 }
 
 void helper_fldz_ST0(void)
 {
-    ST0 = f15rk[0];
+    ST0 = floatx80_zero;
 }
 
 void helper_fldz_FT0(void)
 {
-    FT0 = f15rk[0];
+    FT0 = floatx80_zero;
 }
 
 uint32_t helper_fnstsw(void)
@@ -3754,7 +3920,6 @@ static void update_fp_status(void)
         break;
     }
     set_float_rounding_mode(rnd_type, &env->fp_status);
-#ifdef FLOATX80
     switch((env->fpuc >> 8) & 3) {
     case 0:
         rnd_type = 32;
@@ -3768,7 +3933,6 @@ static void update_fp_status(void)
         break;
     }
     set_floatx80_rounding_precision(rnd_type, &env->fp_status);
-#endif
 }
 
 void helper_fldcw(uint32_t val)
@@ -3786,7 +3950,6 @@ void helper_fwait(void)
 {
     if (env->fpus & FPUS_SE)
         fpu_raise_exception();
-    FORCE_RET();
 }
 
 void helper_fninit(void)
@@ -3808,7 +3971,7 @@ void helper_fninit(void)
 
 void helper_fbld_ST0(target_ulong ptr)
 {
-    CPU86_LDouble tmp;
+    floatx80 tmp;
     uint64_t val;
     unsigned int v;
     int i;
@@ -3818,9 +3981,10 @@ void helper_fbld_ST0(target_ulong ptr)
         v = ldub(ptr + i);
         val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
     }
-    tmp = val;
-    if (ldub(ptr + 9) & 0x80)
-        tmp = -tmp;
+    tmp = int64_to_floatx80(val, &env->fp_status);
+    if (ldub(ptr + 9) & 0x80) {
+        floatx80_chs(tmp);
+    }
     fpush();
     ST0 = tmp;
 }
@@ -3831,7 +3995,7 @@ void helper_fbst_ST0(target_ulong ptr)
     target_ulong mem_ref, mem_end;
     int64_t val;
 
-    val = floatx_to_int64(ST0, &env->fp_status);
+    val = floatx80_to_int64(ST0, &env->fp_status);
     mem_ref = ptr;
     mem_end = mem_ref + 9;
     if (val < 0) {
@@ -3855,17 +4019,19 @@ void helper_fbst_ST0(target_ulong ptr)
 
 void helper_f2xm1(void)
 {
-    ST0 = pow(2.0,ST0) - 1.0;
+    double val = floatx80_to_double(ST0);
+    val = pow(2.0, val) - 1.0;
+    ST0 = double_to_floatx80(val);
 }
 
 void helper_fyl2x(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = floatx80_to_double(ST0);
 
-    fptemp = ST0;
     if (fptemp>0.0){
-        fptemp = log(fptemp)/log(2.0);  /* log2(ST) */
-        ST1 *= fptemp;
+        fptemp = log(fptemp)/log(2.0);    /* log2(ST) */
+        fptemp *= floatx80_to_double(ST1);
+        ST1 = double_to_floatx80(fptemp);
         fpop();
     } else {
         env->fpus &= (~0x4700);
@@ -3875,15 +4041,15 @@ void helper_fyl2x(void)
 
 void helper_fptan(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = floatx80_to_double(ST0);
 
-    fptemp = ST0;
     if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
         env->fpus |= 0x400;
     } else {
-        ST0 = tan(fptemp);
+        fptemp = tan(fptemp);
+        ST0 = double_to_floatx80(fptemp);
         fpush();
-        ST0 = 1.0;
+        ST0 = floatx80_one;
         env->fpus &= (~0x400);  /* C2 <-- 0 */
         /* the above code is for  |arg| < 2**52 only */
     }
@@ -3891,45 +4057,57 @@ void helper_fptan(void)
 
 void helper_fpatan(void)
 {
-    CPU86_LDouble fptemp, fpsrcop;
+    double fptemp, fpsrcop;
 
-    fpsrcop = ST1;
-    fptemp = ST0;
-    ST1 = atan2(fpsrcop,fptemp);
+    fpsrcop = floatx80_to_double(ST1);
+    fptemp = floatx80_to_double(ST0);
+    ST1 = double_to_floatx80(atan2(fpsrcop, fptemp));
     fpop();
 }
 
 void helper_fxtract(void)
 {
-    CPU86_LDoubleU temp;
-    unsigned int expdif;
+    CPU_LDoubleU temp;
 
     temp.d = ST0;
-    expdif = EXPD(temp) - EXPBIAS;
-    /*DP exponent bias*/
-    ST0 = expdif;
-    fpush();
-    BIASEXPONENT(temp);
-    ST0 = temp.d;
+
+    if (floatx80_is_zero(ST0)) {
+        /* Easy way to generate -inf and raising division by 0 exception */
+        ST0 = floatx80_div(floatx80_chs(floatx80_one), floatx80_zero, &env->fp_status);
+        fpush();
+        ST0 = temp.d;
+    } else {
+        int expdif;
+
+        expdif = EXPD(temp) - EXPBIAS;
+        /*DP exponent bias*/
+        ST0 = int32_to_floatx80(expdif, &env->fp_status);
+        fpush();
+        BIASEXPONENT(temp);
+        ST0 = temp.d;
+    }
 }
 
 void helper_fprem1(void)
 {
-    CPU86_LDouble dblq, fpsrcop, fptemp;
-    CPU86_LDoubleU fpsrcop1, fptemp1;
+    double st0, st1, dblq, fpsrcop, fptemp;
+    CPU_LDoubleU fpsrcop1, fptemp1;
     int expdif;
     signed long long int q;
 
-    if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
-        ST0 = 0.0 / 0.0; /* NaN */
+    st0 = floatx80_to_double(ST0);
+    st1 = floatx80_to_double(ST1);
+
+    if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
+        ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
         env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
         return;
     }
 
-    fpsrcop = ST0;
-    fptemp = ST1;
-    fpsrcop1.d = fpsrcop;
-    fptemp1.d = fptemp;
+    fpsrcop = st0;
+    fptemp = st1;
+    fpsrcop1.d = ST0;
+    fptemp1.d = ST1;
     expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
 
     if (expdif < 0) {
@@ -3943,7 +4121,7 @@ void helper_fprem1(void)
         dblq = fpsrcop / fptemp;
         /* round dblq towards nearest integer */
         dblq = rint(dblq);
-        ST0 = fpsrcop - fptemp * dblq;
+        st0 = fpsrcop - fptemp * dblq;
 
         /* convert dblq to q by truncating towards zero */
         if (dblq < 0.0)
@@ -3959,31 +4137,35 @@ void helper_fprem1(void)
     } else {
         env->fpus |= 0x400;  /* C2 <-- 1 */
         fptemp = pow(2.0, expdif - 50);
-        fpsrcop = (ST0 / ST1) / fptemp;
+        fpsrcop = (st0 / st1) / fptemp;
         /* fpsrcop = integer obtained by chopping */
         fpsrcop = (fpsrcop < 0.0) ?
                   -(floor(fabs(fpsrcop))) : floor(fpsrcop);
-        ST0 -= (ST1 * fpsrcop * fptemp);
+        st0 -= (st1 * fpsrcop * fptemp);
     }
+    ST0 = double_to_floatx80(st0);
 }
 
 void helper_fprem(void)
 {
-    CPU86_LDouble dblq, fpsrcop, fptemp;
-    CPU86_LDoubleU fpsrcop1, fptemp1;
+    double st0, st1, dblq, fpsrcop, fptemp;
+    CPU_LDoubleU fpsrcop1, fptemp1;
     int expdif;
     signed long long int q;
 
-    if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
-       ST0 = 0.0 / 0.0; /* NaN */
+    st0 = floatx80_to_double(ST0);
+    st1 = floatx80_to_double(ST1);
+
+    if (isinf(st0) || isnan(st0) || isnan(st1) || (st1 == 0.0)) {
+       ST0 = double_to_floatx80(0.0 / 0.0); /* NaN */
        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
        return;
     }
 
-    fpsrcop = (CPU86_LDouble)ST0;
-    fptemp = (CPU86_LDouble)ST1;
-    fpsrcop1.d = fpsrcop;
-    fptemp1.d = fptemp;
+    fpsrcop = st0;
+    fptemp = st1;
+    fpsrcop1.d = ST0;
+    fptemp1.d = ST1;
     expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
 
     if (expdif < 0) {
@@ -3997,7 +4179,7 @@ void helper_fprem(void)
         dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
         /* round dblq towards zero */
         dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
-        ST0 = fpsrcop/*ST0*/ - fptemp * dblq;
+        st0 = fpsrcop/*ST0*/ - fptemp * dblq;
 
         /* convert dblq to q by truncating towards zero */
         if (dblq < 0.0)
@@ -4014,22 +4196,23 @@ void helper_fprem(void)
         int N = 32 + (expdif % 32); /* as per AMD docs */
         env->fpus |= 0x400;  /* C2 <-- 1 */
         fptemp = pow(2.0, (double)(expdif - N));
-        fpsrcop = (ST0 / ST1) / fptemp;
+        fpsrcop = (st0 / st1) / fptemp;
         /* fpsrcop = integer obtained by chopping */
         fpsrcop = (fpsrcop < 0.0) ?
                   -(floor(fabs(fpsrcop))) : floor(fpsrcop);
-        ST0 -= (ST1 * fpsrcop * fptemp);
+        st0 -= (st1 * fpsrcop * fptemp);
     }
+    ST0 = double_to_floatx80(st0);
 }
 
 void helper_fyl2xp1(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = floatx80_to_double(ST0);
 
-    fptemp = ST0;
     if ((fptemp+1.0)>0.0) {
         fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
-        ST1 *= fptemp;
+        fptemp *= floatx80_to_double(ST1);
+        ST1 = double_to_floatx80(fptemp);
         fpop();
     } else {
         env->fpus &= (~0x4700);
@@ -4039,27 +4222,23 @@ void helper_fyl2xp1(void)
 
 void helper_fsqrt(void)
 {
-    CPU86_LDouble fptemp;
-
-    fptemp = ST0;
-    if (fptemp<0.0) {
+    if (floatx80_is_neg(ST0)) {
         env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
         env->fpus |= 0x400;
     }
-    ST0 = sqrt(fptemp);
+    ST0 = floatx80_sqrt(ST0, &env->fp_status);
 }
 
 void helper_fsincos(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = floatx80_to_double(ST0);
 
-    fptemp = ST0;
     if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
         env->fpus |= 0x400;
     } else {
-        ST0 = sin(fptemp);
+        ST0 = double_to_floatx80(sin(fptemp));
         fpush();
-        ST0 = cos(fptemp);
+        ST0 = double_to_floatx80(cos(fptemp));
         env->fpus &= (~0x400);  /* C2 <-- 0 */
         /* the above code is for  |arg| < 2**63 only */
     }
@@ -4067,23 +4246,27 @@ void helper_fsincos(void)
 
 void helper_frndint(void)
 {
-    ST0 = floatx_round_to_int(ST0, &env->fp_status);
+    ST0 = floatx80_round_to_int(ST0, &env->fp_status);
 }
 
 void helper_fscale(void)
 {
-    ST0 = ldexp (ST0, (int)(ST1));
+    if (floatx80_is_any_nan(ST1)) {
+        ST0 = ST1;
+    } else {
+        int n = floatx80_to_int32_round_to_zero(ST1, &env->fp_status);
+        ST0 = floatx80_scalbn(ST0, n, &env->fp_status);
+    }
 }
 
 void helper_fsin(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = floatx80_to_double(ST0);
 
-    fptemp = ST0;
     if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
         env->fpus |= 0x400;
     } else {
-        ST0 = sin(fptemp);
+        ST0 = double_to_floatx80(sin(fptemp));
         env->fpus &= (~0x400);  /* C2 <-- 0 */
         /* the above code is for  |arg| < 2**53 only */
     }
@@ -4091,13 +4274,12 @@ void helper_fsin(void)
 
 void helper_fcos(void)
 {
-    CPU86_LDouble fptemp;
+    double fptemp = floatx80_to_double(ST0);
 
-    fptemp = ST0;
     if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
         env->fpus |= 0x400;
     } else {
-        ST0 = cos(fptemp);
+        ST0 = double_to_floatx80(cos(fptemp));
         env->fpus &= (~0x400);  /* C2 <-- 0 */
         /* the above code is for  |arg5 < 2**63 only */
     }
@@ -4105,7 +4287,7 @@ void helper_fcos(void)
 
 void helper_fxam_ST0(void)
 {
-    CPU86_LDoubleU temp;
+    CPU_LDoubleU temp;
     int expdif;
 
     temp.d = ST0;
@@ -4117,11 +4299,7 @@ void helper_fxam_ST0(void)
     /* XXX: test fptags too */
     expdif = EXPD(temp);
     if (expdif == MAXEXPD) {
-#ifdef USE_X86LDOUBLE
         if (MANTD(temp) == 0x8000000000000000ULL)
-#else
-        if (MANTD(temp) == 0)
-#endif
             env->fpus |=  0x500 /*Infinity*/;
         else
             env->fpus |=  0x100 /*NaN*/;
@@ -4139,7 +4317,7 @@ void helper_fstenv(target_ulong ptr, int data32)
 {
     int fpus, fptag, exp, i;
     uint64_t mant;
-    CPU86_LDoubleU tmp;
+    CPU_LDoubleU tmp;
 
     fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
     fptag = 0;
@@ -4155,9 +4333,7 @@ void helper_fstenv(target_ulong ptr, int data32)
                 /* zero */
                fptag |= 1;
            } else if (exp == 0 || exp == MAXEXPD
-#ifdef USE_X86LDOUBLE
                        || (mant & (1LL << 63)) == 0
-#endif
                        ) {
                 /* NaNs, infinity, denormal */
                 fptag |= 2;
@@ -4209,7 +4385,7 @@ void helper_fldenv(target_ulong ptr, int data32)
 
 void helper_fsave(target_ulong ptr, int data32)
 {
-    CPU86_LDouble tmp;
+    floatx80 tmp;
     int i;
 
     helper_fstenv(ptr, data32);
@@ -4237,7 +4413,7 @@ void helper_fsave(target_ulong ptr, int data32)
 
 void helper_frstor(target_ulong ptr, int data32)
 {
-    CPU86_LDouble tmp;
+    floatx80 tmp;
     int i;
 
     helper_fldenv(ptr, data32);
@@ -4253,9 +4429,14 @@ void helper_frstor(target_ulong ptr, int data32)
 void helper_fxsave(target_ulong ptr, int data64)
 {
     int fpus, fptag, i, nb_xmm_regs;
-    CPU86_LDouble tmp;
+    floatx80 tmp;
     target_ulong addr;
 
+    /* The operand must be 16 byte aligned */
+    if (ptr & 0xf) {
+        raise_exception(EXCP0D_GPF);
+    }
+
     fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
     fptag = 0;
     for(i = 0; i < 8; i++) {
@@ -4293,10 +4474,15 @@ void helper_fxsave(target_ulong ptr, int data64)
         else
             nb_xmm_regs = 8;
         addr = ptr + 0xa0;
-        for(i = 0; i < nb_xmm_regs; i++) {
-            stq(addr, env->xmm_regs[i].XMM_Q(0));
-            stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
-            addr += 16;
+        /* Fast FXSAVE leaves out the XMM registers */
+        if (!(env->efer & MSR_EFER_FFXSR)
+          || (env->hflags & HF_CPL_MASK)
+          || !(env->hflags & HF_LMA_MASK)) {
+            for(i = 0; i < nb_xmm_regs; i++) {
+                stq(addr, env->xmm_regs[i].XMM_Q(0));
+                stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
+                addr += 16;
+            }
         }
     }
 }
@@ -4304,9 +4490,14 @@ void helper_fxsave(target_ulong ptr, int data64)
 void helper_fxrstor(target_ulong ptr, int data64)
 {
     int i, fpus, fptag, nb_xmm_regs;
-    CPU86_LDouble tmp;
+    floatx80 tmp;
     target_ulong addr;
 
+    /* The operand must be 16 byte aligned */
+    if (ptr & 0xf) {
+        raise_exception(EXCP0D_GPF);
+    }
+
     env->fpuc = lduw(ptr);
     fpus = lduw(ptr + 2);
     fptag = lduw(ptr + 4);
@@ -4333,69 +4524,36 @@ void helper_fxrstor(target_ulong ptr, int data64)
         else
             nb_xmm_regs = 8;
         addr = ptr + 0xa0;
-        for(i = 0; i < nb_xmm_regs; i++) {
-            env->xmm_regs[i].XMM_Q(0) = ldq(addr);
-            env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
-            addr += 16;
+        /* Fast FXRESTORE leaves out the XMM registers */
+        if (!(env->efer & MSR_EFER_FFXSR)
+          || (env->hflags & HF_CPL_MASK)
+          || !(env->hflags & HF_LMA_MASK)) {
+            for(i = 0; i < nb_xmm_regs; i++) {
+                env->xmm_regs[i].XMM_Q(0) = ldq(addr);
+                env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
+                addr += 16;
+            }
         }
     }
 }
 
-#ifndef USE_X86LDOUBLE
-
-void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
-{
-    CPU86_LDoubleU temp;
-    int e;
-
-    temp.d = f;
-    /* mantissa */
-    *pmant = (MANTD(temp) << 11) | (1LL << 63);
-    /* exponent + sign */
-    e = EXPD(temp) - EXPBIAS + 16383;
-    e |= SIGND(temp) >> 16;
-    *pexp = e;
-}
-
-CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
-{
-    CPU86_LDoubleU temp;
-    int e;
-    uint64_t ll;
-
-    /* XXX: handle overflow ? */
-    e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
-    e |= (upper >> 4) & 0x800; /* sign */
-    ll = (mant >> 11) & ((1LL << 52) - 1);
-#ifdef __arm__
-    temp.l.upper = (e << 20) | (ll >> 32);
-    temp.l.lower = ll;
-#else
-    temp.ll = ll | ((uint64_t)e << 52);
-#endif
-    return temp.d;
-}
-
-#else
-
-void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
+void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f)
 {
-    CPU86_LDoubleU temp;
+    CPU_LDoubleU temp;
 
     temp.d = f;
     *pmant = temp.l.lower;
     *pexp = temp.l.upper;
 }
 
-CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
+floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper)
 {
-    CPU86_LDoubleU temp;
+    CPU_LDoubleU temp;
 
     temp.l.upper = upper;
     temp.l.lower = mant;
     return temp.d;
 }
-#endif
 
 #ifdef TARGET_X86_64
 
@@ -4541,14 +4699,20 @@ void helper_idivq_EAX(target_ulong t0)
 }
 #endif
 
-void helper_hlt(void)
+static void do_hlt(void)
 {
-    helper_svm_check_intercept_param(SVM_EXIT_HLT, 0);
-    
     env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
     env->halted = 1;
     env->exception_index = EXCP_HLT;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
+}
+
+void helper_hlt(int next_eip_addend)
+{
+    helper_svm_check_intercept_param(SVM_EXIT_HLT, 0);
+    EIP += next_eip_addend;
+    
+    do_hlt();
 }
 
 void helper_monitor(target_ulong ptr)
@@ -4559,24 +4723,31 @@ void helper_monitor(target_ulong ptr)
     helper_svm_check_intercept_param(SVM_EXIT_MONITOR, 0);
 }
 
-void helper_mwait(void)
+void helper_mwait(int next_eip_addend)
 {
     if ((uint32_t)ECX != 0)
         raise_exception(EXCP0D_GPF);
     helper_svm_check_intercept_param(SVM_EXIT_MWAIT, 0);
+    EIP += next_eip_addend;
+
     /* XXX: not complete but not completely erroneous */
     if (env->cpu_index != 0 || env->next_cpu != NULL) {
         /* more than one CPU: do not sleep because another CPU may
            wake this one */
     } else {
-        helper_hlt();
+        do_hlt();
     }
 }
 
 void helper_debug(void)
 {
     env->exception_index = EXCP_DEBUG;
-    cpu_loop_exit();
+    cpu_loop_exit(env);
+}
+
+void helper_reset_rf(void)
+{
+    env->eflags &= ~RF_MASK;
 }
 
 void helper_raise_interrupt(int intno, int next_eip_addend)
@@ -4634,7 +4805,6 @@ void helper_boundw(target_ulong a0, int v)
     if (v < low || v > high) {
         raise_exception(EXCP05_BOUND);
     }
-    FORCE_RET();
 }
 
 void helper_boundl(target_ulong a0, int v)
@@ -4645,17 +4815,6 @@ void helper_boundl(target_ulong a0, int v)
     if (v < low || v > high) {
         raise_exception(EXCP05_BOUND);
     }
-    FORCE_RET();
-}
-
-static float approx_rsqrt(float a)
-{
-    return 1.0 / sqrt(a);
-}
-
-static float approx_rcp(float a)
-{
-    return 1.0 / a;
 }
 
 #if !defined(CONFIG_USER_ONLY)
@@ -4676,6 +4835,7 @@ static float approx_rcp(float a)
 
 #endif
 
+#if !defined(CONFIG_USER_ONLY)
 /* try to fill the TLB and return an exception if error. If retaddr is
    NULL, it means that the function was called in C code (i.e. not
    from generated code or from helper.c) */
@@ -4701,29 +4861,29 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
             if (tb) {
                 /* the PC is inside the translated code. It means that we have
                    a virtual CPU fault */
-                cpu_restore_state(tb, env, pc, NULL);
+                cpu_restore_state(tb, env, pc);
             }
         }
         raise_exception_err(env->exception_index, env->error_code);
     }
     env = saved_env;
 }
-
+#endif
 
 /* Secure Virtual Machine helpers */
 
 #if defined(CONFIG_USER_ONLY)
 
-void helper_vmrun(void) 
+void helper_vmrun(int aflag, int next_eip_addend)
 { 
 }
 void helper_vmmcall(void) 
 { 
 }
-void helper_vmload(void) 
+void helper_vmload(int aflag)
 { 
 }
-void helper_vmsave(void) 
+void helper_vmsave(int aflag)
 { 
 }
 void helper_stgi(void)
@@ -4735,7 +4895,7 @@ void helper_clgi(void)
 void helper_skinit(void) 
 { 
 }
-void helper_invlpga(void) 
+void helper_invlpga(int aflag)
 { 
 }
 void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1) 
@@ -4745,6 +4905,10 @@ void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
 {
 }
 
+void svm_check_intercept(CPUState *env1, uint32_t type)
+{
+}
+
 void helper_svm_check_io(uint32_t port, uint32_t param, 
                          uint32_t next_eip_addend)
 {
@@ -4761,7 +4925,7 @@ static inline void svm_save_seg(target_phys_addr_t addr,
     stl_phys(addr + offsetof(struct vmcb_seg, limit), 
              sc->limit);
     stw_phys(addr + offsetof(struct vmcb_seg, attrib), 
-             (sc->flags >> 8) | ((sc->flags >> 12) & 0x0f00));
+             ((sc->flags >> 8) & 0xff) | ((sc->flags >> 12) & 0x0f00));
 }
                                 
 static inline void svm_load_seg(target_phys_addr_t addr, SegmentCache *sc)
@@ -4784,7 +4948,7 @@ static inline void svm_load_seg_cache(target_phys_addr_t addr,
                            sc->base, sc->limit, sc->flags);
 }
 
-void helper_vmrun(void)
+void helper_vmrun(int aflag, int next_eip_addend)
 {
     target_ulong addr;
     uint32_t event_inj;
@@ -4792,9 +4956,12 @@ void helper_vmrun(void)
 
     helper_svm_check_intercept_param(SVM_EXIT_VMRUN, 0);
 
-    addr = EAX;
-    if (loglevel & CPU_LOG_TB_IN_ASM)
-        fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr);
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmrun! " TARGET_FMT_lx "\n", addr);
 
     env->vm_vmcb = addr;
 
@@ -4809,7 +4976,6 @@ void helper_vmrun(void)
     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
-    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8), env->cr[8]);
     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
 
@@ -4825,7 +4991,8 @@ void helper_vmrun(void)
     svm_save_seg(env->vm_hsave + offsetof(struct vmcb, save.ds), 
                  &env->segs[R_DS]);
 
-    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip), EIP);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip),
+             EIP + next_eip_addend);
     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
     stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
 
@@ -4841,6 +5008,8 @@ void helper_vmrun(void)
     /* enable intercepts */
     env->hflags |= HF_SVMI_MASK;
 
+    env->tsc_offset = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.tsc_offset));
+
     env->gdt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
     env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
 
@@ -4855,19 +5024,16 @@ void helper_vmrun(void)
     cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
     env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
     int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
+    env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
     if (int_ctl & V_INTR_MASKING_MASK) {
-        env->cr[8] = int_ctl & V_TPR_MASK;
-        cpu_set_apic_tpr(env, env->cr[8]);
+        env->v_tpr = int_ctl & V_TPR_MASK;
+        env->hflags2 |= HF2_VINTR_MASK;
         if (env->eflags & IF_MASK)
-            env->hflags |= HF_HIF_MASK;
+            env->hflags2 |= HF2_HIF_MASK;
     }
 
-#ifdef TARGET_X86_64
-    env->efer = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer));
-    env->hflags &= ~HF_LMA_MASK;
-    if (env->efer & MSR_EFER_LMA)
-       env->hflags |= HF_LMA_MASK;
-#endif
+    cpu_load_efer(env, 
+                  ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
     env->eflags = 0;
     load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
                 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
@@ -4901,7 +5067,11 @@ void helper_vmrun(void)
         break;
     }
 
-    helper_stgi();
+    env->hflags2 |= HF2_GIF_MASK;
+
+    if (int_ctl & V_IRQ_MASK) {
+        env->interrupt_request |= CPU_INTERRUPT_VIRQ;
+    }
 
     /* maybe we need to inject an event */
     event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
@@ -4909,10 +5079,8 @@ void helper_vmrun(void)
         uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
         uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
         uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
-        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
 
-        if (loglevel & CPU_LOG_TB_IN_ASM)
-            fprintf(logfile, "Injecting(%#hx): ", valid_err);
+        qemu_log_mask(CPU_LOG_TB_IN_ASM, "Injecting(%#hx): ", valid_err);
         /* FIXME: need to implement valid_err */
         switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
         case SVM_EVTINJ_TYPE_INTR:
@@ -4920,43 +5088,37 @@ void helper_vmrun(void)
                 env->error_code = event_inj_err;
                 env->exception_is_int = 0;
                 env->exception_next_eip = -1;
-                if (loglevel & CPU_LOG_TB_IN_ASM)
-                    fprintf(logfile, "INTR");
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
+                /* XXX: is it always correct ? */
+                do_interrupt_all(vector, 0, 0, 0, 1);
                 break;
         case SVM_EVTINJ_TYPE_NMI:
-                env->exception_index = vector;
+                env->exception_index = EXCP02_NMI;
                 env->error_code = event_inj_err;
                 env->exception_is_int = 0;
                 env->exception_next_eip = EIP;
-                if (loglevel & CPU_LOG_TB_IN_ASM)
-                    fprintf(logfile, "NMI");
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
+                cpu_loop_exit(env);
                 break;
         case SVM_EVTINJ_TYPE_EXEPT:
                 env->exception_index = vector;
                 env->error_code = event_inj_err;
                 env->exception_is_int = 0;
                 env->exception_next_eip = -1;
-                if (loglevel & CPU_LOG_TB_IN_ASM)
-                    fprintf(logfile, "EXEPT");
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
+                cpu_loop_exit(env);
                 break;
         case SVM_EVTINJ_TYPE_SOFT:
                 env->exception_index = vector;
                 env->error_code = event_inj_err;
                 env->exception_is_int = 1;
                 env->exception_next_eip = EIP;
-                if (loglevel & CPU_LOG_TB_IN_ASM)
-                    fprintf(logfile, "SOFT");
+                qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
+                cpu_loop_exit(env);
                 break;
         }
-        if (loglevel & CPU_LOG_TB_IN_ASM)
-            fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code);
+        qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code);
     }
-    if ((int_ctl & V_IRQ_MASK) || 
-        (env->intercept & (1ULL << (SVM_EXIT_INTR - SVM_EXIT_INTR)))) {
-        env->interrupt_request |= CPU_INTERRUPT_VIRQ;
-    }
-
-    cpu_loop_exit();
 }
 
 void helper_vmmcall(void)
@@ -4965,15 +5127,17 @@ void helper_vmmcall(void)
     raise_exception(EXCP06_ILLOP);
 }
 
-void helper_vmload(void)
+void helper_vmload(int aflag)
 {
     target_ulong addr;
     helper_svm_check_intercept_param(SVM_EXIT_VMLOAD, 0);
 
-    /* XXX: invalid in 32 bit */
-    addr = EAX;
-    if (loglevel & CPU_LOG_TB_IN_ASM)
-        fprintf(logfile,"vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
                 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
                 env->segs[R_FS].base);
 
@@ -4998,13 +5162,17 @@ void helper_vmload(void)
     env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
 }
 
-void helper_vmsave(void)
+void helper_vmsave(int aflag)
 {
     target_ulong addr;
     helper_svm_check_intercept_param(SVM_EXIT_VMSAVE, 0);
-    addr = EAX;
-    if (loglevel & CPU_LOG_TB_IN_ASM)
-        fprintf(logfile,"vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
+
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
                 addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
                 env->segs[R_FS].base);
 
@@ -5032,28 +5200,35 @@ void helper_vmsave(void)
 void helper_stgi(void)
 {
     helper_svm_check_intercept_param(SVM_EXIT_STGI, 0);
-    env->hflags |= HF_GIF_MASK;
+    env->hflags2 |= HF2_GIF_MASK;
 }
 
 void helper_clgi(void)
 {
     helper_svm_check_intercept_param(SVM_EXIT_CLGI, 0);
-    env->hflags &= ~HF_GIF_MASK;
+    env->hflags2 &= ~HF2_GIF_MASK;
 }
 
 void helper_skinit(void)
 {
     helper_svm_check_intercept_param(SVM_EXIT_SKINIT, 0);
     /* XXX: not implemented */
-    if (loglevel & CPU_LOG_TB_IN_ASM)
-        fprintf(logfile,"skinit!\n");
     raise_exception(EXCP06_ILLOP);
 }
 
-void helper_invlpga(void)
+void helper_invlpga(int aflag)
 {
+    target_ulong addr;
     helper_svm_check_intercept_param(SVM_EXIT_INVLPGA, 0);
-    tlb_flush(env, 0);
+    
+    if (aflag == 2)
+        addr = EAX;
+    else
+        addr = (uint32_t)EAX;
+
+    /* XXX: could use the ASID to see if it is needed to do the
+       flush */
+    tlb_flush_page(env, addr);
 }
 
 void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
@@ -5094,7 +5269,7 @@ void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
             switch((uint32_t)ECX) {
             case 0 ... 0x1fff:
                 t0 = (ECX * 2) % 8;
-                t1 = ECX / 8;
+                t1 = (ECX * 2) / 8;
                 break;
             case 0xc0000000 ... 0xc0001fff:
                 t0 = (8192 + ECX - 0xc0000000) * 2;
@@ -5124,6 +5299,16 @@ void helper_svm_check_intercept_param(uint32_t type, uint64_t param)
     }
 }
 
+void svm_check_intercept(CPUState *env1, uint32_t type)
+{
+    CPUState *saved_env;
+
+    saved_env = env;
+    env = env1;
+    helper_svm_check_intercept_param(type, 0);
+    env = saved_env;
+}
+
 void helper_svm_check_io(uint32_t port, uint32_t param, 
                          uint32_t next_eip_addend)
 {
@@ -5145,8 +5330,7 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
 {
     uint32_t int_ctl;
 
-    if (loglevel & CPU_LOG_TB_IN_ASM)
-        fprintf(logfile,"vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
+    qemu_log_mask(CPU_LOG_TB_IN_ASM, "vmexit(%08x, %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
                 exit_code, exit_info_1,
                 ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
                 EIP);
@@ -5180,11 +5364,12 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
 
-    if ((int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl))) & V_INTR_MASKING_MASK) {
-        int_ctl &= ~V_TPR_MASK;
-        int_ctl |= env->cr[8] & V_TPR_MASK;
-        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
-    }
+    int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
+    int_ctl &= ~(V_TPR_MASK | V_IRQ_MASK);
+    int_ctl |= env->v_tpr & V_TPR_MASK;
+    if (env->interrupt_request & CPU_INTERRUPT_VIRQ)
+        int_ctl |= V_IRQ_MASK;
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
 
     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
     stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
@@ -5195,11 +5380,12 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
     stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
 
     /* Reload the host state from vm_hsave */
-    env->hflags &= ~HF_HIF_MASK;
+    env->hflags2 &= ~(HF2_HIF_MASK | HF2_VINTR_MASK);
     env->hflags &= ~HF_SVMI_MASK;
     env->intercept = 0;
     env->intercept_exceptions = 0;
     env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
+    env->tsc_offset = 0;
 
     env->gdt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
     env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
@@ -5210,26 +5396,10 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
     cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
     cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
     cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
-    if (int_ctl & V_INTR_MASKING_MASK) {
-        env->cr[8] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8));
-        cpu_set_apic_tpr(env, env->cr[8]);
-    }
-    /* we need to set the efer after the crs so the hidden flags get set properly */
-#ifdef TARGET_X86_64
-    env->efer  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer));
-    env->hflags &= ~HF_LMA_MASK;
-    if (env->efer & MSR_EFER_LMA)
-       env->hflags |= HF_LMA_MASK;
-    /* XXX: should also emulate the VM_CR MSR */
-    env->hflags &= ~HF_SVME_MASK;
-    if (env->cpuid_ext3_features & CPUID_EXT3_SVM) {
-        if (env->efer & MSR_EFER_SVME)
-            env->hflags |= HF_SVME_MASK;
-    } else {
-        env->efer &= ~MSR_EFER_SVME;
-    }
-#endif
-
+    /* we need to set the efer after the crs so the hidden flags get
+       set properly */
+    cpu_load_efer(env, 
+                  ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
     env->eflags = 0;
     load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
                 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
@@ -5256,7 +5426,13 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
     stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
     stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
 
-    helper_clgi();
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info),
+             ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj)));
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_int_info_err),
+             ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err)));
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), 0);
+
+    env->hflags2 &= ~HF2_GIF_MASK;
     /* FIXME: Resets the current ASID register to zero (host ASID). */
 
     /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
@@ -5284,7 +5460,7 @@ void helper_vmexit(uint32_t exit_code, uint64_t exit_info_1)
     env->error_code = 0;
     env->old_exception = -1;
 
-    cpu_loop_exit();
+    cpu_loop_exit(env);
 }
 
 #endif
@@ -5306,9 +5482,9 @@ void helper_emms(void)
 }
 
 /* XXX: suppress */
-void helper_movq(uint64_t *d, uint64_t *s)
+void helper_movq(void *d, void *s)
 {
-    *d = *s;
+    *(uint64_t *)d = *(uint64_t *)s;
 }
 
 #define SHIFT 0
@@ -5352,11 +5528,14 @@ target_ulong helper_bsf(target_ulong t0)
     return count;
 }
 
-target_ulong helper_bsr(target_ulong t0)
+target_ulong helper_lzcnt(target_ulong t0, int wordsize)
 {
     int count;
     target_ulong res, mask;
-    
+
+    if (wordsize > 0 && t0 == 0) {
+        return wordsize;
+    }
     res = t0;
     count = TARGET_LONG_BITS - 1;
     mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
@@ -5364,9 +5543,16 @@ target_ulong helper_bsr(target_ulong t0)
         count--;
         res <<= 1;
     }
+    if (wordsize > 0) {
+        return wordsize - 1 - count;
+    }
     return count;
 }
 
+target_ulong helper_bsr(target_ulong t0)
+{
+       return helper_lzcnt(t0, 0);
+}
 
 static int compute_all_eflags(void)
 {
@@ -5378,71 +5564,156 @@ static int compute_c_eflags(void)
     return CC_SRC & CC_C;
 }
 
-CCTable cc_table[CC_OP_NB] = {
-    [CC_OP_DYNAMIC] = { /* should never happen */ },
+uint32_t helper_cc_compute_all(int op)
+{
+    switch (op) {
+    default: /* should never happen */ return 0;
 
-    [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags },
+    case CC_OP_EFLAGS: return compute_all_eflags();
 
-    [CC_OP_MULB] = { compute_all_mulb, compute_c_mull },
-    [CC_OP_MULW] = { compute_all_mulw, compute_c_mull },
-    [CC_OP_MULL] = { compute_all_mull, compute_c_mull },
+    case CC_OP_MULB: return compute_all_mulb();
+    case CC_OP_MULW: return compute_all_mulw();
+    case CC_OP_MULL: return compute_all_mull();
 
-    [CC_OP_ADDB] = { compute_all_addb, compute_c_addb },
-    [CC_OP_ADDW] = { compute_all_addw, compute_c_addw  },
-    [CC_OP_ADDL] = { compute_all_addl, compute_c_addl  },
+    case CC_OP_ADDB: return compute_all_addb();
+    case CC_OP_ADDW: return compute_all_addw();
+    case CC_OP_ADDL: return compute_all_addl();
 
-    [CC_OP_ADCB] = { compute_all_adcb, compute_c_adcb },
-    [CC_OP_ADCW] = { compute_all_adcw, compute_c_adcw  },
-    [CC_OP_ADCL] = { compute_all_adcl, compute_c_adcl  },
+    case CC_OP_ADCB: return compute_all_adcb();
+    case CC_OP_ADCW: return compute_all_adcw();
+    case CC_OP_ADCL: return compute_all_adcl();
 
-    [CC_OP_SUBB] = { compute_all_subb, compute_c_subb  },
-    [CC_OP_SUBW] = { compute_all_subw, compute_c_subw  },
-    [CC_OP_SUBL] = { compute_all_subl, compute_c_subl  },
+    case CC_OP_SUBB: return compute_all_subb();
+    case CC_OP_SUBW: return compute_all_subw();
+    case CC_OP_SUBL: return compute_all_subl();
 
-    [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb  },
-    [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw  },
-    [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl  },
+    case CC_OP_SBBB: return compute_all_sbbb();
+    case CC_OP_SBBW: return compute_all_sbbw();
+    case CC_OP_SBBL: return compute_all_sbbl();
 
-    [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb },
-    [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw },
-    [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl },
+    case CC_OP_LOGICB: return compute_all_logicb();
+    case CC_OP_LOGICW: return compute_all_logicw();
+    case CC_OP_LOGICL: return compute_all_logicl();
 
-    [CC_OP_INCB] = { compute_all_incb, compute_c_incl },
-    [CC_OP_INCW] = { compute_all_incw, compute_c_incl },
-    [CC_OP_INCL] = { compute_all_incl, compute_c_incl },
+    case CC_OP_INCB: return compute_all_incb();
+    case CC_OP_INCW: return compute_all_incw();
+    case CC_OP_INCL: return compute_all_incl();
 
-    [CC_OP_DECB] = { compute_all_decb, compute_c_incl },
-    [CC_OP_DECW] = { compute_all_decw, compute_c_incl },
-    [CC_OP_DECL] = { compute_all_decl, compute_c_incl },
+    case CC_OP_DECB: return compute_all_decb();
+    case CC_OP_DECW: return compute_all_decw();
+    case CC_OP_DECL: return compute_all_decl();
 
-    [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb },
-    [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw },
-    [CC_OP_SHLL] = { compute_all_shll, compute_c_shll },
+    case CC_OP_SHLB: return compute_all_shlb();
+    case CC_OP_SHLW: return compute_all_shlw();
+    case CC_OP_SHLL: return compute_all_shll();
 
-    [CC_OP_SARB] = { compute_all_sarb, compute_c_sarl },
-    [CC_OP_SARW] = { compute_all_sarw, compute_c_sarl },
-    [CC_OP_SARL] = { compute_all_sarl, compute_c_sarl },
+    case CC_OP_SARB: return compute_all_sarb();
+    case CC_OP_SARW: return compute_all_sarw();
+    case CC_OP_SARL: return compute_all_sarl();
 
 #ifdef TARGET_X86_64
-    [CC_OP_MULQ] = { compute_all_mulq, compute_c_mull },
+    case CC_OP_MULQ: return compute_all_mulq();
 
-    [CC_OP_ADDQ] = { compute_all_addq, compute_c_addq  },
+    case CC_OP_ADDQ: return compute_all_addq();
 
-    [CC_OP_ADCQ] = { compute_all_adcq, compute_c_adcq  },
+    case CC_OP_ADCQ: return compute_all_adcq();
 
-    [CC_OP_SUBQ] = { compute_all_subq, compute_c_subq  },
+    case CC_OP_SUBQ: return compute_all_subq();
 
-    [CC_OP_SBBQ] = { compute_all_sbbq, compute_c_sbbq  },
+    case CC_OP_SBBQ: return compute_all_sbbq();
 
-    [CC_OP_LOGICQ] = { compute_all_logicq, compute_c_logicq },
+    case CC_OP_LOGICQ: return compute_all_logicq();
 
-    [CC_OP_INCQ] = { compute_all_incq, compute_c_incl },
+    case CC_OP_INCQ: return compute_all_incq();
 
-    [CC_OP_DECQ] = { compute_all_decq, compute_c_incl },
+    case CC_OP_DECQ: return compute_all_decq();
 
-    [CC_OP_SHLQ] = { compute_all_shlq, compute_c_shlq },
+    case CC_OP_SHLQ: return compute_all_shlq();
 
-    [CC_OP_SARQ] = { compute_all_sarq, compute_c_sarl },
+    case CC_OP_SARQ: return compute_all_sarq();
 #endif
-};
+    }
+}
+
+uint32_t cpu_cc_compute_all(CPUState *env1, int op)
+{
+    CPUState *saved_env;
+    uint32_t ret;
+
+    saved_env = env;
+    env = env1;
+    ret = helper_cc_compute_all(op);
+    env = saved_env;
+    return ret;
+}
 
+uint32_t helper_cc_compute_c(int op)
+{
+    switch (op) {
+    default: /* should never happen */ return 0;
+
+    case CC_OP_EFLAGS: return compute_c_eflags();
+
+    case CC_OP_MULB: return compute_c_mull();
+    case CC_OP_MULW: return compute_c_mull();
+    case CC_OP_MULL: return compute_c_mull();
+
+    case CC_OP_ADDB: return compute_c_addb();
+    case CC_OP_ADDW: return compute_c_addw();
+    case CC_OP_ADDL: return compute_c_addl();
+
+    case CC_OP_ADCB: return compute_c_adcb();
+    case CC_OP_ADCW: return compute_c_adcw();
+    case CC_OP_ADCL: return compute_c_adcl();
+
+    case CC_OP_SUBB: return compute_c_subb();
+    case CC_OP_SUBW: return compute_c_subw();
+    case CC_OP_SUBL: return compute_c_subl();
+
+    case CC_OP_SBBB: return compute_c_sbbb();
+    case CC_OP_SBBW: return compute_c_sbbw();
+    case CC_OP_SBBL: return compute_c_sbbl();
+
+    case CC_OP_LOGICB: return compute_c_logicb();
+    case CC_OP_LOGICW: return compute_c_logicw();
+    case CC_OP_LOGICL: return compute_c_logicl();
+
+    case CC_OP_INCB: return compute_c_incl();
+    case CC_OP_INCW: return compute_c_incl();
+    case CC_OP_INCL: return compute_c_incl();
+
+    case CC_OP_DECB: return compute_c_incl();
+    case CC_OP_DECW: return compute_c_incl();
+    case CC_OP_DECL: return compute_c_incl();
+
+    case CC_OP_SHLB: return compute_c_shlb();
+    case CC_OP_SHLW: return compute_c_shlw();
+    case CC_OP_SHLL: return compute_c_shll();
+
+    case CC_OP_SARB: return compute_c_sarl();
+    case CC_OP_SARW: return compute_c_sarl();
+    case CC_OP_SARL: return compute_c_sarl();
+
+#ifdef TARGET_X86_64
+    case CC_OP_MULQ: return compute_c_mull();
+
+    case CC_OP_ADDQ: return compute_c_addq();
+
+    case CC_OP_ADCQ: return compute_c_adcq();
+
+    case CC_OP_SUBQ: return compute_c_subq();
+
+    case CC_OP_SBBQ: return compute_c_sbbq();
+
+    case CC_OP_LOGICQ: return compute_c_logicq();
+
+    case CC_OP_INCQ: return compute_c_incl();
+
+    case CC_OP_DECQ: return compute_c_incl();
+
+    case CC_OP_SHLQ: return compute_c_shlq();
+
+    case CC_OP_SARQ: return compute_c_sarl();
+#endif
+    }
+}