* 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 "exec.h"
+#include "exec-all.h"
#include "host-utils.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,
};
/* 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,
};
/* 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,
/* broken thread support */
-spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
void helper_lock(void)
{
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;
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) {
/* 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 */
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)
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 {\
#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)\
{\
#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)\
#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;\
}
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
}
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 */
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
}
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 */
}
#endif
+#ifdef TARGET_X86_64
#if defined(CONFIG_USER_ONLY)
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;
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);
}
}
#endif
+#endif
+#ifdef TARGET_X86_64
void helper_sysret(int dflag)
{
int cpl, selector;
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,
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 |
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,
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);
EIP = next_eip;
}
+#if !defined(CONFIG_USER_ONLY)
+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
void do_interrupt(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=");
+ 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
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
}
+/* 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.
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 &&
* 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);
/* 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);
}
SegmentCache *dt;
int i, offset;
- if (loglevel & CPU_LOG_INT) {
- fprintf(logfile, "SMM: enter\n");
- cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
- }
+ 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);
/* 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;
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;
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 */
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;
}
EAX = (EAX & ~0xffff) | al | (ah << 8);
CC_SRC = eflags;
- FORCE_RET();
}
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;
}
EAX = (EAX & ~0xffff) | al | (ah << 8);
CC_SRC = eflags;
- FORCE_RET();
}
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;
eflags |= parity_table[al]; /* pf */
eflags |= (al & 0x80); /* sf */
CC_SRC = eflags;
- FORCE_RET();
}
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;
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);
}
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;
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) {
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;
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, (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)
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
}
{
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);
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)
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 */
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;
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)
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)
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),
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*/
} 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)
}
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 |
EIP = env->sysenter_eip;
}
-void helper_sysexit(void)
+void helper_sysexit(int dflag)
{
int cpl;
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)
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)
{
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;
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)
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)
}
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)) {
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:
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;
}
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;
case MSR_KERNELGSBASE:
val = env->kernelgsbase;
break;
+ case MSR_TSC_AUX:
+ val = env->tsc_aux;
+ break;
#endif
-#ifdef USE_KQEMU
- case MSR_QPI_COMMBASE:
- if (env->kqemu_enabled) {
- val = kqemu_comm_base;
- } else {
+ 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;
-#endif
+ 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;
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;
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)
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)
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)
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);
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)
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};
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)
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)
{
if (env->fpus & FPUS_SE)
fpu_raise_exception();
- FORCE_RET();
}
void helper_fninit(void)
CPU86_LDouble 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++) {
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;
+ }
}
}
}
CPU86_LDouble 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);
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;
+ }
}
}
}
}
#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)
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();
}
}
cpu_loop_exit();
}
+void helper_reset_rf(void)
+{
+ env->eflags &= ~RF_MASK;
+}
+
void helper_raise_interrupt(int intno, int next_eip_addend)
{
raise_interrupt(intno, 1, 0, next_eip_addend);
if (v < low || v > high) {
raise_exception(EXCP05_BOUND);
}
- FORCE_RET();
}
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)
#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) */
}
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)
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)
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)
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;
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;
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]);
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);
/* 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));
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));
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));
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:
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(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();
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();
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();
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;
+ qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code);
}
-
- cpu_loop_exit();
}
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);
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);
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)
{
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);
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);
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));
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));
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)));
+
+ 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. */
}
/* 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
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);
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)
{
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
+ }
+}