]> git.proxmox.com Git - mirror_qemu.git/blobdiff - target-i386/op_helper.c
Update FSF address in GPL/LGPL boilerplate
[mirror_qemu.git] / target-i386 / op_helper.c
index cd8521fdc85cb7a7381bfec8597056594a06d5d9..6e0e32e75b93d1ebf5bab991842476efa269b2e0 100644 (file)
  *
  * 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
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 USA
  */
 #define CPU_NO_GLOBAL_REGS
 #include "exec.h"
+#include "exec-all.h"
 #include "host-utils.h"
 
 //#define DEBUG_PCALL
@@ -32,7 +33,7 @@ do {\
 } 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 +69,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,14 +77,14 @@ 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] =
+static const CPU86_LDouble f15rk[7] =
 {
     0.00000000000000000000L,
     1.00000000000000000000L,
@@ -96,7 +97,7 @@ const CPU86_LDouble f15rk[7] =
 
 /* 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 +117,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;
@@ -496,6 +497,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 */
@@ -590,6 +602,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 +616,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 +627,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;\
 }
 
@@ -980,6 +996,7 @@ 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)
 {
@@ -996,7 +1013,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 +1038,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 +1057,9 @@ void helper_syscall(int next_eip_addend)
     }
 }
 #endif
+#endif
 
+#ifdef TARGET_X86_64
 void helper_sysret(int dflag)
 {
     int cpl, selector;
@@ -1056,7 +1072,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 +1097,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 |
@@ -1108,6 +1121,7 @@ void helper_sysret(int dflag)
     }
 #endif
 }
+#endif
 
 /* real mode interrupt */
 static void do_interrupt_real(int intno, int is_int, int error_code,
@@ -1217,7 +1231,7 @@ void do_interrupt(int intno, int is_int, int error_code,
         }
     }
     if (env->cr[0] & CR0_PE_MASK) {
-#if TARGET_X86_64
+#ifdef TARGET_X86_64
         if (env->hflags & HF_LMA_MASK) {
             do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
         } else
@@ -1270,8 +1284,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 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);
@@ -1289,7 +1303,7 @@ void raise_interrupt(int intno, int is_int, int error_code,
 
 /* 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);
 }
@@ -1714,7 +1728,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;
@@ -1730,7 +1744,6 @@ void helper_aaa(void)
     }
     EAX = (EAX & ~0xffff) | al | (ah << 8);
     CC_SRC = eflags;
-    FORCE_RET();
 }
 
 void helper_aas(void)
@@ -1739,7 +1752,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;
@@ -1755,7 +1768,6 @@ void helper_aas(void)
     }
     EAX = (EAX & ~0xffff) | al | (ah << 8);
     CC_SRC = eflags;
-    FORCE_RET();
 }
 
 void helper_daa(void)
@@ -1763,7 +1775,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;
@@ -1783,7 +1795,6 @@ void helper_daa(void)
     eflags |= parity_table[al]; /* pf */
     eflags |= (al & 0x80); /* sf */
     CC_SRC = eflags;
-    FORCE_RET();
 }
 
 void helper_das(void)
@@ -1791,7 +1802,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;
@@ -1814,13 +1825,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);
     }
@@ -1831,12 +1841,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;
@@ -1850,7 +1862,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) {
@@ -1858,6 +1872,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;
@@ -1868,116 +1885,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 (env->cpuid_ext2_features & CPUID_EXT2_LM) {
-            /* 64 bit processor */
-#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
-        }
-        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, &eax, &ebx, &ecx, &edx);
+    EAX = eax;
+    EBX = ebx;
+    ECX = ecx;
+    EDX = edx;
 }
 
 void helper_enter_level(int level, int data32, target_ulong t1)
@@ -2582,7 +2507,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;
@@ -2591,7 +2517,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)
@@ -2843,7 +2769,7 @@ void helper_iret_protected(int shift, int next_eip)
     } else {
         helper_ret_protected(shift, 1, 0);
     }
-    env->hflags &= ~HF_NMI_MASK;
+    env->hflags2 &= ~HF2_NMI_MASK;
 #ifdef USE_KQEMU
     if (kqemu_is_ok(env)) {
         CC_OP = CC_OP_EFLAGS;
@@ -2871,11 +2797,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 |
@@ -2885,7 +2823,7 @@ void helper_sysenter(void)
     EIP = env->sysenter_eip;
 }
 
-void helper_sysexit(void)
+void helper_sysexit(int dflag)
 {
     int cpl;
 
@@ -2894,16 +2832,32 @@ 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
@@ -2923,6 +2877,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)
 {
@@ -2934,7 +2892,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);
+        } else {
+            val = env->v_tpr;
+        }
         break;
     }
     return val;
@@ -2954,14 +2916,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, 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)
@@ -2978,19 +2960,6 @@ 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);
@@ -3006,7 +2975,7 @@ 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);
 }
@@ -3136,6 +3105,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;
@@ -3182,7 +3157,7 @@ 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 (load_segment(&e1, &e2, selector) != 0)
         goto fail;
     rpl = selector & 3;
@@ -3224,7 +3199,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)
@@ -3270,7 +3245,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)
@@ -3303,7 +3278,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)
@@ -3343,7 +3318,7 @@ static inline CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
     return a / b;
 }
 
-void fpu_raise_exception(void)
+static void fpu_raise_exception(void)
 {
     if (env->cr[0] & CR0_NE_MASK) {
         raise_exception(EXCP10_COPR);
@@ -3573,7 +3548,6 @@ void helper_fcom_ST0_FT0(void)
 
     ret = floatx_compare(ST0, FT0, &env->fp_status);
     env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
-    FORCE_RET();
 }
 
 void helper_fucom_ST0_FT0(void)
@@ -3582,7 +3556,6 @@ void helper_fucom_ST0_FT0(void)
 
     ret = floatx_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};
@@ -3593,10 +3566,9 @@ void helper_fcomi_ST0_FT0(void)
     int ret;
 
     ret = floatx_compare(ST0, FT0, &env->fp_status);
-    eflags = cc_table[CC_OP].compute_all();
+    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)
@@ -3605,10 +3577,9 @@ void helper_fucomi_ST0_FT0(void)
     int ret;
 
     ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
-    eflags = cc_table[CC_OP].compute_all();
+    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)
@@ -3793,7 +3764,6 @@ void helper_fwait(void)
 {
     if (env->fpus & FPUS_SE)
         fpu_raise_exception();
-    FORCE_RET();
 }
 
 void helper_fninit(void)
@@ -4548,16 +4518,22 @@ 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();
 }
 
+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)
 {
     if ((uint32_t)ECX != 0)
@@ -4566,17 +4542,19 @@ 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();
     }
 }
 
@@ -4641,7 +4619,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)
@@ -4652,7 +4629,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)
@@ -4683,6 +4659,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) */
@@ -4715,13 +4692,13 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
     }
     env = saved_env;
 }
-
+#endif
 
 /* Secure Virtual Machine helpers */
 
 #if defined(CONFIG_USER_ONLY)
 
-void helper_vmrun(int aflag)
+void helper_vmrun(int aflag, int next_eip_addend)
 { 
 }
 void helper_vmmcall(void) 
@@ -4768,7 +4745,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)
@@ -4791,7 +4768,7 @@ static inline void svm_load_seg_cache(target_phys_addr_t addr,
                            sc->base, sc->limit, sc->flags);
 }
 
-void helper_vmrun(int aflag)
+void helper_vmrun(int aflag, int next_eip_addend)
 {
     target_ulong addr;
     uint32_t event_inj;
@@ -4820,7 +4797,6 @@ void helper_vmrun(int aflag)
     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]);
 
@@ -4836,7 +4812,8 @@ void helper_vmrun(int aflag)
     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);
 
@@ -4852,6 +4829,8 @@ void helper_vmrun(int aflag)
     /* 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));
 
@@ -4866,17 +4845,16 @@ void helper_vmrun(int aflag)
     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
     cpu_load_efer(env, 
                   ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer)));
-#endif
     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));
@@ -4910,7 +4888,11 @@ void helper_vmrun(int aflag)
         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));
@@ -4931,14 +4913,17 @@ void helper_vmrun(int aflag)
                 env->exception_next_eip = -1;
                 if (loglevel & CPU_LOG_TB_IN_ASM)
                     fprintf(logfile, "INTR");
+                /* XXX: is it always correct ? */
+                do_interrupt(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");
+                cpu_loop_exit();
                 break;
         case SVM_EVTINJ_TYPE_EXEPT:
                 env->exception_index = vector;
@@ -4947,6 +4932,7 @@ void helper_vmrun(int aflag)
                 env->exception_next_eip = -1;
                 if (loglevel & CPU_LOG_TB_IN_ASM)
                     fprintf(logfile, "EXEPT");
+                cpu_loop_exit();
                 break;
         case SVM_EVTINJ_TYPE_SOFT:
                 env->exception_index = vector;
@@ -4955,17 +4941,12 @@ void helper_vmrun(int aflag)
                 env->exception_next_eip = EIP;
                 if (loglevel & CPU_LOG_TB_IN_ASM)
                     fprintf(logfile, "SOFT");
+                cpu_loop_exit();
                 break;
         }
         if (loglevel & CPU_LOG_TB_IN_ASM)
             fprintf(logfile, " %#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)
@@ -5049,13 +5030,13 @@ void helper_vmsave(int aflag)
 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)
@@ -5204,11 +5185,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);
@@ -5219,11 +5201,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));
@@ -5234,17 +5217,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
     cpu_load_efer(env, 
                   ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer)));
-#endif
-
     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));
@@ -5271,7 +5247,7 @@ 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();
+    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. */
@@ -5321,9 +5297,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
@@ -5393,71 +5369,144 @@ 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 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
+    }
+}