*/
#include <math.h>
-#include "exec.h"
-#include "exec-all.h"
+#include "cpu.h"
+#include "dyngen-exec.h"
#include "host-utils.h"
#include "ioport.h"
+#include "qemu-common.h"
+#include "qemu-log.h"
+#include "cpu-defs.h"
+#include "helper.h"
-//#define DEBUG_PCALL
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+//#define DEBUG_PCALL
#ifdef DEBUG_PCALL
# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__)
# define LOG_PCALL_STATE(env) do { } while (0)
#endif
+/* n must be a constant to be efficient */
+static inline target_long lshift(target_long x, int n)
+{
+ if (n >= 0) {
+ return x << n;
+ } else {
+ return x >> (-n);
+ }
+}
+
+#define RC_MASK 0xc00
+#define RC_NEAR 0x000
+#define RC_DOWN 0x400
+#define RC_UP 0x800
+#define RC_CHOP 0xc00
+
+#define MAXTAN 9223372036854775808.0
+
+/* the following deal with x86 long double-precision numbers */
+#define MAXEXPD 0x7fff
+#define EXPBIAS 16383
+#define EXPD(fp) (fp.l.upper & 0x7fff)
+#define SIGND(fp) ((fp.l.upper) & 0x8000)
+#define MANTD(fp) (fp.l.lower)
+#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
+
+static inline void fpush(void)
+{
+ env->fpstt = (env->fpstt - 1) & 7;
+ env->fptags[env->fpstt] = 0; /* validate stack entry */
+}
+
+static inline void fpop(void)
+{
+ env->fptags[env->fpstt] = 1; /* invvalidate stack entry */
+ env->fpstt = (env->fpstt + 1) & 7;
+}
+
+static inline floatx80 helper_fldt(target_ulong ptr)
+{
+ CPU_LDoubleU temp;
+
+ temp.l.lower = ldq(ptr);
+ temp.l.upper = lduw(ptr + 8);
+ return temp.d;
+}
+
+static inline void helper_fstt(floatx80 f, target_ulong ptr)
+{
+ CPU_LDoubleU temp;
+
+ temp.d = f;
+ stq(ptr, temp.l.lower);
+ stw(ptr + 8, temp.l.upper);
+}
+
+#define FPUS_IE (1 << 0)
+#define FPUS_DE (1 << 1)
+#define FPUS_ZE (1 << 2)
+#define FPUS_OE (1 << 3)
+#define FPUS_UE (1 << 4)
+#define FPUS_PE (1 << 5)
+#define FPUS_SF (1 << 6)
+#define FPUS_SE (1 << 7)
+#define FPUS_B (1 << 15)
+
+#define FPUC_EM 0x3f
+
+static inline uint32_t compute_eflags(void)
+{
+ return env->eflags | helper_cc_compute_all(CC_OP) | (DF & DF_MASK);
+}
+
+/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
+static inline void load_eflags(int eflags, int update_mask)
+{
+ CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((eflags >> 10) & 1));
+ env->eflags = (env->eflags & ~update_mask) |
+ (eflags & update_mask) | 0x2;
+}
+
+/* load efer and update the corresponding hflags. XXX: do consistency
+ checks with cpuid bits ? */
+static inline void cpu_load_efer(CPUState *env, uint64_t val)
+{
+ env->efer = val;
+ env->hflags &= ~(HF_LMA_MASK | HF_SVME_MASK);
+ if (env->efer & MSR_EFER_LMA) {
+ env->hflags |= HF_LMA_MASK;
+ }
+ if (env->efer & MSR_EFER_SVME) {
+ env->hflags |= HF_SVME_MASK;
+ }
+}
#if 0
#define raise_exception_err(a, b)\
} while (0)
#endif
+static void QEMU_NORETURN raise_exception_err(int exception_index,
+ int error_code);
+
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,
#define floatx80_l2e make_floatx80( 0x3fff, 0xb8aa3b295c17f0bcLL )
#define floatx80_l2t make_floatx80( 0x4000, 0xd49a784bcd1b8afeLL )
-static const floatx80 f15rk[7] =
-{
- floatx80_zero,
- floatx80_one,
- floatx80_pi,
- floatx80_lg2,
- floatx80_ln2,
- floatx80_l2e,
- floatx80_l2t,
-};
-
/* broken thread support */
static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
{
env->exception_index = EXCP_SYSCALL;
env->exception_next_eip = env->eip + next_eip_addend;
- cpu_loop_exit();
+ cpu_loop_exit(env);
}
#else
void helper_syscall(int next_eip_addend)
env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
}
+#if defined(CONFIG_USER_ONLY)
/* fake user mode interrupt */
-void do_interrupt_user(int intno, int is_int, int error_code,
- target_ulong next_eip)
+static void do_interrupt_user(int intno, int is_int, int error_code,
+ target_ulong next_eip)
{
SegmentCache *dt;
target_ulong ptr;
EIP = next_eip;
}
-#if !defined(CONFIG_USER_ONLY)
+#else
+
static void handle_even_inj(int intno, int is_int, int error_code,
int is_hw, int rm)
{
* the int instruction. next_eip is the EIP value AFTER the interrupt
* instruction. It is only relevant if is_int is TRUE.
*/
-void do_interrupt(int intno, int is_int, int error_code,
- target_ulong next_eip, int is_hw)
+static void do_interrupt_all(int intno, int is_int, int error_code,
+ target_ulong next_eip, int is_hw)
{
if (qemu_loglevel_mask(CPU_LOG_INT)) {
if ((env->cr[0] & CR0_PE_MASK)) {
#endif
}
+void do_interrupt(CPUState *env1)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+#if defined(CONFIG_USER_ONLY)
+ /* if user mode only, we simulate a fake exception
+ which will be handled outside the cpu execution
+ loop */
+ do_interrupt_user(env->exception_index,
+ env->exception_is_int,
+ env->error_code,
+ env->exception_next_eip);
+ /* successfully delivered */
+ env->old_exception = -1;
+#else
+ /* simulate a real cpu exception. On i386, it can
+ trigger new exceptions, but we do not handle
+ double or triple faults yet. */
+ do_interrupt_all(env->exception_index,
+ env->exception_is_int,
+ env->error_code,
+ env->exception_next_eip, 0);
+ /* successfully delivered */
+ env->old_exception = -1;
+#endif
+ env = saved_env;
+}
+
+void do_interrupt_x86_hardirq(CPUState *env1, int intno, int is_hw)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ do_interrupt_all(intno, 0, 0, 0, is_hw);
+ env = saved_env;
+}
+
/* This should come from sysemu.h - if we could include it here... */
void qemu_system_reset_request(void);
env->error_code = error_code;
env->exception_is_int = is_int;
env->exception_next_eip = env->eip + next_eip_addend;
- cpu_loop_exit();
+ cpu_loop_exit(env);
}
/* shortcuts to generate exceptions */
-void raise_exception_err(int exception_index, int error_code)
+static void QEMU_NORETURN raise_exception_err(int exception_index,
+ int error_code)
+{
+ raise_interrupt(exception_index, 0, error_code, 0);
+}
+
+void raise_exception_err_env(CPUState *nenv, int exception_index,
+ int error_code)
{
+ env = nenv;
raise_interrupt(exception_index, 0, error_code, 0);
}
-void raise_exception(int exception_index)
+static void QEMU_NORETURN raise_exception(int exception_index)
{
raise_interrupt(exception_index, 0, 0, 0);
}
#if defined(CONFIG_USER_ONLY)
-void do_smm_enter(void)
+void do_smm_enter(CPUState *env1)
{
}
#define SMM_REVISION_ID 0x00020000
#endif
-void do_smm_enter(void)
+void do_smm_enter(CPUState *env1)
{
target_ulong sm_state;
SegmentCache *dt;
int i, offset;
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
qemu_log_mask(CPU_LOG_INT, "SMM: enter\n");
log_cpu_state_mask(CPU_LOG_INT, env, X86_DUMP_CCOP);
cpu_x86_update_cr4(env, 0);
env->dr[7] = 0x00000400;
CC_OP = CC_OP_EFLAGS;
+ env = saved_env;
}
void helper_rsm(void)
void helper_daa(void)
{
- int al, af, cf;
+ int old_al, al, af, cf;
int eflags;
eflags = helper_cc_compute_all(CC_OP);
cf = eflags & CC_C;
af = eflags & CC_A;
- al = EAX & 0xff;
+ old_al = al = EAX & 0xff;
eflags = 0;
if (((al & 0x0f) > 9 ) || af) {
al = (al + 6) & 0xff;
eflags |= CC_A;
}
- if ((al > 0x9f) || cf) {
+ if ((old_al > 0x99) || cf) {
al = (al + 0x60) & 0xff;
eflags |= CC_C;
}
case MSR_TSC_AUX:
env->tsc_aux = val;
break;
+ case MSR_IA32_MISC_ENABLE:
+ env->msr_ia32_misc_enable = val;
+ break;
default:
if ((uint32_t)ECX >= MSR_MC0_CTL
&& (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
case MSR_MCG_STATUS:
val = env->mcg_status;
break;
+ case MSR_IA32_MISC_ENABLE:
+ val = env->msr_ia32_misc_enable;
+ break;
default:
if ((uint32_t)ECX >= MSR_MC0_CTL
&& (uint32_t)ECX < MSR_MC0_CTL + (4 * env->mcg_cap & 0xff)) {
void helper_fld1_ST0(void)
{
- ST0 = f15rk[1];
+ ST0 = floatx80_one;
}
void helper_fldl2t_ST0(void)
{
- ST0 = f15rk[6];
+ ST0 = floatx80_l2t;
}
void helper_fldl2e_ST0(void)
{
- ST0 = f15rk[5];
+ ST0 = floatx80_l2e;
}
void helper_fldpi_ST0(void)
{
- ST0 = f15rk[2];
+ ST0 = floatx80_pi;
}
void helper_fldlg2_ST0(void)
{
- ST0 = f15rk[3];
+ ST0 = floatx80_lg2;
}
void helper_fldln2_ST0(void)
{
- ST0 = f15rk[4];
+ ST0 = floatx80_ln2;
}
void helper_fldz_ST0(void)
{
- ST0 = f15rk[0];
+ ST0 = floatx80_zero;
}
void helper_fldz_FT0(void)
{
- FT0 = f15rk[0];
+ FT0 = floatx80_zero;
}
uint32_t helper_fnstsw(void)
}
}
+
+#if defined(CONFIG_USER_ONLY)
+void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
+{
+ CPUX86State *saved_env;
+
+ saved_env = env;
+ env = s;
+ if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
+ selector &= 0xffff;
+ cpu_x86_load_seg_cache(env, seg_reg, selector,
+ (selector << 4), 0xffff, 0);
+ } else {
+ helper_load_seg(seg_reg, selector);
+ }
+ env = saved_env;
+}
+
+void cpu_x86_fsave(CPUX86State *s, target_ulong ptr, int data32)
+{
+ CPUX86State *saved_env;
+
+ saved_env = env;
+ env = s;
+
+ helper_fsave(ptr, data32);
+
+ env = saved_env;
+}
+
+void cpu_x86_frstor(CPUX86State *s, target_ulong ptr, int data32)
+{
+ CPUX86State *saved_env;
+
+ saved_env = env;
+ env = s;
+
+ helper_frstor(ptr, data32);
+
+ env = saved_env;
+}
+#endif
+
void helper_fxsave(target_ulong ptr, int data64)
{
int fpus, fptag, i, nb_xmm_regs;
env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
env->halted = 1;
env->exception_index = EXCP_HLT;
- cpu_loop_exit();
+ cpu_loop_exit(env);
}
void helper_hlt(int next_eip_addend)
void helper_debug(void)
{
env->exception_index = EXCP_DEBUG;
- cpu_loop_exit();
+ cpu_loop_exit(env);
}
void helper_reset_rf(void)
NULL, it means that the function was called in C code (i.e. not
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
-void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr)
+void tlb_fill(CPUState *env1, target_ulong addr, int is_write, int mmu_idx,
+ void *retaddr)
{
TranslationBlock *tb;
int ret;
unsigned long pc;
CPUX86State *saved_env;
- /* XXX: hack to restore env in all cases, even if not called from
- generated code */
saved_env = env;
- env = cpu_single_env;
+ env = env1;
- ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+ ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (ret) {
if (retaddr) {
/* now we have a real cpu fault */
{
}
+void svm_check_intercept(CPUState *env1, uint32_t type)
+{
+}
+
void helper_svm_check_io(uint32_t port, uint32_t param,
uint32_t next_eip_addend)
{
env->exception_next_eip = -1;
qemu_log_mask(CPU_LOG_TB_IN_ASM, "INTR");
/* XXX: is it always correct ? */
- do_interrupt(vector, 0, 0, 0, 1);
+ do_interrupt_all(vector, 0, 0, 0, 1);
break;
case SVM_EVTINJ_TYPE_NMI:
env->exception_index = EXCP02_NMI;
env->exception_is_int = 0;
env->exception_next_eip = EIP;
qemu_log_mask(CPU_LOG_TB_IN_ASM, "NMI");
- cpu_loop_exit();
+ cpu_loop_exit(env);
break;
case SVM_EVTINJ_TYPE_EXEPT:
env->exception_index = vector;
env->exception_is_int = 0;
env->exception_next_eip = -1;
qemu_log_mask(CPU_LOG_TB_IN_ASM, "EXEPT");
- cpu_loop_exit();
+ cpu_loop_exit(env);
break;
case SVM_EVTINJ_TYPE_SOFT:
env->exception_index = vector;
env->exception_is_int = 1;
env->exception_next_eip = EIP;
qemu_log_mask(CPU_LOG_TB_IN_ASM, "SOFT");
- cpu_loop_exit();
+ cpu_loop_exit(env);
break;
}
qemu_log_mask(CPU_LOG_TB_IN_ASM, " %#x %#x\n", env->exception_index, env->error_code);
}
}
+void svm_check_intercept(CPUState *env1, uint32_t type)
+{
+ CPUState *saved_env;
+
+ saved_env = env;
+ env = env1;
+ helper_svm_check_intercept_param(type, 0);
+ env = saved_env;
+}
+
void helper_svm_check_io(uint32_t port, uint32_t param,
uint32_t next_eip_addend)
{
env->error_code = 0;
env->old_exception = -1;
- cpu_loop_exit();
+ cpu_loop_exit(env);
}
#endif
}
}
+uint32_t cpu_cc_compute_all(CPUState *env1, int op)
+{
+ CPUState *saved_env;
+ uint32_t ret;
+
+ saved_env = env;
+ env = env1;
+ ret = helper_cc_compute_all(op);
+ env = saved_env;
+ return ret;
+}
+
uint32_t helper_cc_compute_c(int op)
{
switch (op) {