Commit d3eead2eec2f74fded2bed2cb8c21fd8404aeeb9
1 parent
853d6f7a
new directory structure
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@390 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
9 changed files
with
0 additions
and
3834 deletions
Too many changes to show.
To preserve performance only 9 of 20 files are displayed.
cpu-arm.h deleted
100644 → 0
| 1 | -/* | |
| 2 | - * ARM virtual CPU header | |
| 3 | - * | |
| 4 | - * Copyright (c) 2003 Fabrice Bellard | |
| 5 | - * | |
| 6 | - * This library is free software; you can redistribute it and/or | |
| 7 | - * modify it under the terms of the GNU Lesser General Public | |
| 8 | - * License as published by the Free Software Foundation; either | |
| 9 | - * version 2 of the License, or (at your option) any later version. | |
| 10 | - * | |
| 11 | - * This library is distributed in the hope that it will be useful, | |
| 12 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | - * Lesser General Public License for more details. | |
| 15 | - * | |
| 16 | - * You should have received a copy of the GNU Lesser General Public | |
| 17 | - * License along with this library; if not, write to the Free Software | |
| 18 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 | - */ | |
| 20 | -#ifndef CPU_ARM_H | |
| 21 | -#define CPU_ARM_H | |
| 22 | - | |
| 23 | -#include "cpu-defs.h" | |
| 24 | - | |
| 25 | -#define EXCP_UDEF 1 /* undefined instruction */ | |
| 26 | -#define EXCP_SWI 2 /* software interrupt */ | |
| 27 | - | |
| 28 | -typedef struct CPUARMState { | |
| 29 | - uint32_t regs[16]; | |
| 30 | - uint32_t cpsr; | |
| 31 | - | |
| 32 | - /* cpsr flag cache for faster execution */ | |
| 33 | - uint32_t CF; /* 0 or 1 */ | |
| 34 | - uint32_t VF; /* V is the bit 31. All other bits are undefined */ | |
| 35 | - uint32_t NZF; /* N is bit 31. Z is computed from NZF */ | |
| 36 | - | |
| 37 | - /* exception/interrupt handling */ | |
| 38 | - jmp_buf jmp_env; | |
| 39 | - int exception_index; | |
| 40 | - int interrupt_request; | |
| 41 | - struct TranslationBlock *current_tb; | |
| 42 | - int user_mode_only; | |
| 43 | - | |
| 44 | - /* user data */ | |
| 45 | - void *opaque; | |
| 46 | -} CPUARMState; | |
| 47 | - | |
| 48 | -CPUARMState *cpu_arm_init(void); | |
| 49 | -int cpu_arm_exec(CPUARMState *s); | |
| 50 | -void cpu_arm_close(CPUARMState *s); | |
| 51 | -/* you can call this signal handler from your SIGBUS and SIGSEGV | |
| 52 | - signal handlers to inform the virtual CPU of exceptions. non zero | |
| 53 | - is returned if the signal was handled by the virtual CPU. */ | |
| 54 | -struct siginfo; | |
| 55 | -int cpu_arm_signal_handler(int host_signum, struct siginfo *info, | |
| 56 | - void *puc); | |
| 57 | - | |
| 58 | -void cpu_arm_dump_state(CPUARMState *env, FILE *f, int flags); | |
| 59 | - | |
| 60 | -#define TARGET_PAGE_BITS 12 | |
| 61 | -#include "cpu-all.h" | |
| 62 | - | |
| 63 | -#endif |
cpu-i386.h deleted
100644 → 0
| 1 | -/* | |
| 2 | - * i386 virtual CPU header | |
| 3 | - * | |
| 4 | - * Copyright (c) 2003 Fabrice Bellard | |
| 5 | - * | |
| 6 | - * This library is free software; you can redistribute it and/or | |
| 7 | - * modify it under the terms of the GNU Lesser General Public | |
| 8 | - * License as published by the Free Software Foundation; either | |
| 9 | - * version 2 of the License, or (at your option) any later version. | |
| 10 | - * | |
| 11 | - * This library is distributed in the hope that it will be useful, | |
| 12 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | - * Lesser General Public License for more details. | |
| 15 | - * | |
| 16 | - * You should have received a copy of the GNU Lesser General Public | |
| 17 | - * License along with this library; if not, write to the Free Software | |
| 18 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 | - */ | |
| 20 | -#ifndef CPU_I386_H | |
| 21 | -#define CPU_I386_H | |
| 22 | - | |
| 23 | -#include "cpu-defs.h" | |
| 24 | - | |
| 25 | -#define R_EAX 0 | |
| 26 | -#define R_ECX 1 | |
| 27 | -#define R_EDX 2 | |
| 28 | -#define R_EBX 3 | |
| 29 | -#define R_ESP 4 | |
| 30 | -#define R_EBP 5 | |
| 31 | -#define R_ESI 6 | |
| 32 | -#define R_EDI 7 | |
| 33 | - | |
| 34 | -#define R_AL 0 | |
| 35 | -#define R_CL 1 | |
| 36 | -#define R_DL 2 | |
| 37 | -#define R_BL 3 | |
| 38 | -#define R_AH 4 | |
| 39 | -#define R_CH 5 | |
| 40 | -#define R_DH 6 | |
| 41 | -#define R_BH 7 | |
| 42 | - | |
| 43 | -#define R_ES 0 | |
| 44 | -#define R_CS 1 | |
| 45 | -#define R_SS 2 | |
| 46 | -#define R_DS 3 | |
| 47 | -#define R_FS 4 | |
| 48 | -#define R_GS 5 | |
| 49 | - | |
| 50 | -/* segment descriptor fields */ | |
| 51 | -#define DESC_G_MASK (1 << 23) | |
| 52 | -#define DESC_B_SHIFT 22 | |
| 53 | -#define DESC_B_MASK (1 << DESC_B_SHIFT) | |
| 54 | -#define DESC_AVL_MASK (1 << 20) | |
| 55 | -#define DESC_P_MASK (1 << 15) | |
| 56 | -#define DESC_DPL_SHIFT 13 | |
| 57 | -#define DESC_S_MASK (1 << 12) | |
| 58 | -#define DESC_TYPE_SHIFT 8 | |
| 59 | -#define DESC_A_MASK (1 << 8) | |
| 60 | - | |
| 61 | -#define DESC_CS_MASK (1 << 11) | |
| 62 | -#define DESC_C_MASK (1 << 10) | |
| 63 | -#define DESC_R_MASK (1 << 9) | |
| 64 | - | |
| 65 | -#define DESC_E_MASK (1 << 10) | |
| 66 | -#define DESC_W_MASK (1 << 9) | |
| 67 | - | |
| 68 | -/* eflags masks */ | |
| 69 | -#define CC_C 0x0001 | |
| 70 | -#define CC_P 0x0004 | |
| 71 | -#define CC_A 0x0010 | |
| 72 | -#define CC_Z 0x0040 | |
| 73 | -#define CC_S 0x0080 | |
| 74 | -#define CC_O 0x0800 | |
| 75 | - | |
| 76 | -#define TF_SHIFT 8 | |
| 77 | -#define IOPL_SHIFT 12 | |
| 78 | -#define VM_SHIFT 17 | |
| 79 | - | |
| 80 | -#define TF_MASK 0x00000100 | |
| 81 | -#define IF_MASK 0x00000200 | |
| 82 | -#define DF_MASK 0x00000400 | |
| 83 | -#define IOPL_MASK 0x00003000 | |
| 84 | -#define NT_MASK 0x00004000 | |
| 85 | -#define RF_MASK 0x00010000 | |
| 86 | -#define VM_MASK 0x00020000 | |
| 87 | -#define AC_MASK 0x00040000 | |
| 88 | -#define VIF_MASK 0x00080000 | |
| 89 | -#define VIP_MASK 0x00100000 | |
| 90 | -#define ID_MASK 0x00200000 | |
| 91 | - | |
| 92 | -/* hidden flags - used internally by qemu to represent additionnal cpu | |
| 93 | - states. Only the CPL and INHIBIT_IRQ are not redundant. We avoid | |
| 94 | - using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring | |
| 95 | - with eflags. */ | |
| 96 | -/* current cpl */ | |
| 97 | -#define HF_CPL_SHIFT 0 | |
| 98 | -/* true if soft mmu is being used */ | |
| 99 | -#define HF_SOFTMMU_SHIFT 2 | |
| 100 | -/* true if hardware interrupts must be disabled for next instruction */ | |
| 101 | -#define HF_INHIBIT_IRQ_SHIFT 3 | |
| 102 | -/* 16 or 32 segments */ | |
| 103 | -#define HF_CS32_SHIFT 4 | |
| 104 | -#define HF_SS32_SHIFT 5 | |
| 105 | -/* zero base for DS, ES and SS */ | |
| 106 | -#define HF_ADDSEG_SHIFT 6 | |
| 107 | - | |
| 108 | -#define HF_CPL_MASK (3 << HF_CPL_SHIFT) | |
| 109 | -#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT) | |
| 110 | -#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT) | |
| 111 | -#define HF_CS32_MASK (1 << HF_CS32_SHIFT) | |
| 112 | -#define HF_SS32_MASK (1 << HF_SS32_SHIFT) | |
| 113 | -#define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT) | |
| 114 | - | |
| 115 | -#define CR0_PE_MASK (1 << 0) | |
| 116 | -#define CR0_TS_MASK (1 << 3) | |
| 117 | -#define CR0_WP_MASK (1 << 16) | |
| 118 | -#define CR0_AM_MASK (1 << 18) | |
| 119 | -#define CR0_PG_MASK (1 << 31) | |
| 120 | - | |
| 121 | -#define CR4_VME_MASK (1 << 0) | |
| 122 | -#define CR4_PVI_MASK (1 << 1) | |
| 123 | -#define CR4_TSD_MASK (1 << 2) | |
| 124 | -#define CR4_DE_MASK (1 << 3) | |
| 125 | -#define CR4_PSE_MASK (1 << 4) | |
| 126 | - | |
| 127 | -#define PG_PRESENT_BIT 0 | |
| 128 | -#define PG_RW_BIT 1 | |
| 129 | -#define PG_USER_BIT 2 | |
| 130 | -#define PG_PWT_BIT 3 | |
| 131 | -#define PG_PCD_BIT 4 | |
| 132 | -#define PG_ACCESSED_BIT 5 | |
| 133 | -#define PG_DIRTY_BIT 6 | |
| 134 | -#define PG_PSE_BIT 7 | |
| 135 | -#define PG_GLOBAL_BIT 8 | |
| 136 | - | |
| 137 | -#define PG_PRESENT_MASK (1 << PG_PRESENT_BIT) | |
| 138 | -#define PG_RW_MASK (1 << PG_RW_BIT) | |
| 139 | -#define PG_USER_MASK (1 << PG_USER_BIT) | |
| 140 | -#define PG_PWT_MASK (1 << PG_PWT_BIT) | |
| 141 | -#define PG_PCD_MASK (1 << PG_PCD_BIT) | |
| 142 | -#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT) | |
| 143 | -#define PG_DIRTY_MASK (1 << PG_DIRTY_BIT) | |
| 144 | -#define PG_PSE_MASK (1 << PG_PSE_BIT) | |
| 145 | -#define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT) | |
| 146 | - | |
| 147 | -#define PG_ERROR_W_BIT 1 | |
| 148 | - | |
| 149 | -#define PG_ERROR_P_MASK 0x01 | |
| 150 | -#define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT) | |
| 151 | -#define PG_ERROR_U_MASK 0x04 | |
| 152 | -#define PG_ERROR_RSVD_MASK 0x08 | |
| 153 | - | |
| 154 | -#define MSR_IA32_APICBASE 0x1b | |
| 155 | -#define MSR_IA32_APICBASE_BSP (1<<8) | |
| 156 | -#define MSR_IA32_APICBASE_ENABLE (1<<11) | |
| 157 | -#define MSR_IA32_APICBASE_BASE (0xfffff<<12) | |
| 158 | - | |
| 159 | -#define MSR_IA32_SYSENTER_CS 0x174 | |
| 160 | -#define MSR_IA32_SYSENTER_ESP 0x175 | |
| 161 | -#define MSR_IA32_SYSENTER_EIP 0x176 | |
| 162 | - | |
| 163 | -#define EXCP00_DIVZ 0 | |
| 164 | -#define EXCP01_SSTP 1 | |
| 165 | -#define EXCP02_NMI 2 | |
| 166 | -#define EXCP03_INT3 3 | |
| 167 | -#define EXCP04_INTO 4 | |
| 168 | -#define EXCP05_BOUND 5 | |
| 169 | -#define EXCP06_ILLOP 6 | |
| 170 | -#define EXCP07_PREX 7 | |
| 171 | -#define EXCP08_DBLE 8 | |
| 172 | -#define EXCP09_XERR 9 | |
| 173 | -#define EXCP0A_TSS 10 | |
| 174 | -#define EXCP0B_NOSEG 11 | |
| 175 | -#define EXCP0C_STACK 12 | |
| 176 | -#define EXCP0D_GPF 13 | |
| 177 | -#define EXCP0E_PAGE 14 | |
| 178 | -#define EXCP10_COPR 16 | |
| 179 | -#define EXCP11_ALGN 17 | |
| 180 | -#define EXCP12_MCHK 18 | |
| 181 | - | |
| 182 | -enum { | |
| 183 | - CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */ | |
| 184 | - CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */ | |
| 185 | - CC_OP_MUL, /* modify all flags, C, O = (CC_SRC != 0) */ | |
| 186 | - | |
| 187 | - CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ | |
| 188 | - CC_OP_ADDW, | |
| 189 | - CC_OP_ADDL, | |
| 190 | - | |
| 191 | - CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ | |
| 192 | - CC_OP_ADCW, | |
| 193 | - CC_OP_ADCL, | |
| 194 | - | |
| 195 | - CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ | |
| 196 | - CC_OP_SUBW, | |
| 197 | - CC_OP_SUBL, | |
| 198 | - | |
| 199 | - CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */ | |
| 200 | - CC_OP_SBBW, | |
| 201 | - CC_OP_SBBL, | |
| 202 | - | |
| 203 | - CC_OP_LOGICB, /* modify all flags, CC_DST = res */ | |
| 204 | - CC_OP_LOGICW, | |
| 205 | - CC_OP_LOGICL, | |
| 206 | - | |
| 207 | - CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */ | |
| 208 | - CC_OP_INCW, | |
| 209 | - CC_OP_INCL, | |
| 210 | - | |
| 211 | - CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */ | |
| 212 | - CC_OP_DECW, | |
| 213 | - CC_OP_DECL, | |
| 214 | - | |
| 215 | - CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ | |
| 216 | - CC_OP_SHLW, | |
| 217 | - CC_OP_SHLL, | |
| 218 | - | |
| 219 | - CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */ | |
| 220 | - CC_OP_SARW, | |
| 221 | - CC_OP_SARL, | |
| 222 | - | |
| 223 | - CC_OP_NB, | |
| 224 | -}; | |
| 225 | - | |
| 226 | -#ifdef __i386__ | |
| 227 | -#define USE_X86LDOUBLE | |
| 228 | -#endif | |
| 229 | - | |
| 230 | -#ifdef USE_X86LDOUBLE | |
| 231 | -typedef long double CPU86_LDouble; | |
| 232 | -#else | |
| 233 | -typedef double CPU86_LDouble; | |
| 234 | -#endif | |
| 235 | - | |
| 236 | -typedef struct SegmentCache { | |
| 237 | - uint32_t selector; | |
| 238 | - uint8_t *base; | |
| 239 | - uint32_t limit; | |
| 240 | - uint32_t flags; | |
| 241 | -} SegmentCache; | |
| 242 | - | |
| 243 | -typedef struct CPUX86State { | |
| 244 | - /* standard registers */ | |
| 245 | - uint32_t regs[8]; | |
| 246 | - uint32_t eip; | |
| 247 | - uint32_t eflags; /* eflags register. During CPU emulation, CC | |
| 248 | - flags and DF are set to zero because they are | |
| 249 | - stored elsewhere */ | |
| 250 | - | |
| 251 | - /* emulator internal eflags handling */ | |
| 252 | - uint32_t cc_src; | |
| 253 | - uint32_t cc_dst; | |
| 254 | - uint32_t cc_op; | |
| 255 | - int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */ | |
| 256 | - uint32_t hflags; /* hidden flags, see HF_xxx constants */ | |
| 257 | - | |
| 258 | - /* FPU state */ | |
| 259 | - unsigned int fpstt; /* top of stack index */ | |
| 260 | - unsigned int fpus; | |
| 261 | - unsigned int fpuc; | |
| 262 | - uint8_t fptags[8]; /* 0 = valid, 1 = empty */ | |
| 263 | - CPU86_LDouble fpregs[8]; | |
| 264 | - | |
| 265 | - /* emulator internal variables */ | |
| 266 | - CPU86_LDouble ft0; | |
| 267 | - union { | |
| 268 | - float f; | |
| 269 | - double d; | |
| 270 | - int i32; | |
| 271 | - int64_t i64; | |
| 272 | - } fp_convert; | |
| 273 | - | |
| 274 | - /* segments */ | |
| 275 | - SegmentCache segs[6]; /* selector values */ | |
| 276 | - SegmentCache ldt; | |
| 277 | - SegmentCache tr; | |
| 278 | - SegmentCache gdt; /* only base and limit are used */ | |
| 279 | - SegmentCache idt; /* only base and limit are used */ | |
| 280 | - | |
| 281 | - /* sysenter registers */ | |
| 282 | - uint32_t sysenter_cs; | |
| 283 | - uint32_t sysenter_esp; | |
| 284 | - uint32_t sysenter_eip; | |
| 285 | - | |
| 286 | - /* exception/interrupt handling */ | |
| 287 | - jmp_buf jmp_env; | |
| 288 | - int exception_index; | |
| 289 | - int error_code; | |
| 290 | - int exception_is_int; | |
| 291 | - int exception_next_eip; | |
| 292 | - struct TranslationBlock *current_tb; /* currently executing TB */ | |
| 293 | - uint32_t cr[5]; /* NOTE: cr1 is unused */ | |
| 294 | - uint32_t dr[8]; /* debug registers */ | |
| 295 | - int interrupt_request; | |
| 296 | - int user_mode_only; /* user mode only simulation */ | |
| 297 | - | |
| 298 | - /* soft mmu support */ | |
| 299 | - /* 0 = kernel, 1 = user */ | |
| 300 | - CPUTLBEntry tlb_read[2][CPU_TLB_SIZE]; | |
| 301 | - CPUTLBEntry tlb_write[2][CPU_TLB_SIZE]; | |
| 302 | - | |
| 303 | - /* ice debug support */ | |
| 304 | - uint32_t breakpoints[MAX_BREAKPOINTS]; | |
| 305 | - int nb_breakpoints; | |
| 306 | - int singlestep_enabled; | |
| 307 | - | |
| 308 | - /* user data */ | |
| 309 | - void *opaque; | |
| 310 | -} CPUX86State; | |
| 311 | - | |
| 312 | -#ifndef IN_OP_I386 | |
| 313 | -void cpu_x86_outb(CPUX86State *env, int addr, int val); | |
| 314 | -void cpu_x86_outw(CPUX86State *env, int addr, int val); | |
| 315 | -void cpu_x86_outl(CPUX86State *env, int addr, int val); | |
| 316 | -int cpu_x86_inb(CPUX86State *env, int addr); | |
| 317 | -int cpu_x86_inw(CPUX86State *env, int addr); | |
| 318 | -int cpu_x86_inl(CPUX86State *env, int addr); | |
| 319 | -#endif | |
| 320 | - | |
| 321 | -CPUX86State *cpu_x86_init(void); | |
| 322 | -int cpu_x86_exec(CPUX86State *s); | |
| 323 | -void cpu_x86_close(CPUX86State *s); | |
| 324 | -int cpu_x86_get_pic_interrupt(CPUX86State *s); | |
| 325 | - | |
| 326 | -/* this function must always be used to load data in the segment | |
| 327 | - cache: it synchronizes the hflags with the segment cache values */ | |
| 328 | -static inline void cpu_x86_load_seg_cache(CPUX86State *env, | |
| 329 | - int seg_reg, unsigned int selector, | |
| 330 | - uint8_t *base, unsigned int limit, | |
| 331 | - unsigned int flags) | |
| 332 | -{ | |
| 333 | - SegmentCache *sc; | |
| 334 | - unsigned int new_hflags; | |
| 335 | - | |
| 336 | - sc = &env->segs[seg_reg]; | |
| 337 | - sc->selector = selector; | |
| 338 | - sc->base = base; | |
| 339 | - sc->limit = limit; | |
| 340 | - sc->flags = flags; | |
| 341 | - | |
| 342 | - /* update the hidden flags */ | |
| 343 | - new_hflags = (env->segs[R_CS].flags & DESC_B_MASK) | |
| 344 | - >> (DESC_B_SHIFT - HF_CS32_SHIFT); | |
| 345 | - new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK) | |
| 346 | - >> (DESC_B_SHIFT - HF_SS32_SHIFT); | |
| 347 | - if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { | |
| 348 | - /* XXX: try to avoid this test. The problem comes from the | |
| 349 | - fact that is real mode or vm86 mode we only modify the | |
| 350 | - 'base' and 'selector' fields of the segment cache to go | |
| 351 | - faster. A solution may be to force addseg to one in | |
| 352 | - translate-i386.c. */ | |
| 353 | - new_hflags |= HF_ADDSEG_MASK; | |
| 354 | - } else { | |
| 355 | - new_hflags |= (((unsigned long)env->segs[R_DS].base | | |
| 356 | - (unsigned long)env->segs[R_ES].base | | |
| 357 | - (unsigned long)env->segs[R_SS].base) != 0) << | |
| 358 | - HF_ADDSEG_SHIFT; | |
| 359 | - } | |
| 360 | - env->hflags = (env->hflags & | |
| 361 | - ~(HF_CS32_MASK | HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags; | |
| 362 | -} | |
| 363 | - | |
| 364 | -/* wrapper, just in case memory mappings must be changed */ | |
| 365 | -static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl) | |
| 366 | -{ | |
| 367 | -#if HF_CPL_MASK == 3 | |
| 368 | - s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl; | |
| 369 | -#else | |
| 370 | -#error HF_CPL_MASK is hardcoded | |
| 371 | -#endif | |
| 372 | -} | |
| 373 | - | |
| 374 | -/* the following helpers are only usable in user mode simulation as | |
| 375 | - they can trigger unexpected exceptions */ | |
| 376 | -void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector); | |
| 377 | -void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32); | |
| 378 | -void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32); | |
| 379 | - | |
| 380 | -/* you can call this signal handler from your SIGBUS and SIGSEGV | |
| 381 | - signal handlers to inform the virtual CPU of exceptions. non zero | |
| 382 | - is returned if the signal was handled by the virtual CPU. */ | |
| 383 | -struct siginfo; | |
| 384 | -int cpu_x86_signal_handler(int host_signum, struct siginfo *info, | |
| 385 | - void *puc); | |
| 386 | - | |
| 387 | -/* MMU defines */ | |
| 388 | -void cpu_x86_init_mmu(CPUX86State *env); | |
| 389 | -extern int phys_ram_size; | |
| 390 | -extern int phys_ram_fd; | |
| 391 | -extern uint8_t *phys_ram_base; | |
| 392 | - | |
| 393 | -/* used to debug */ | |
| 394 | -#define X86_DUMP_FPU 0x0001 /* dump FPU state too */ | |
| 395 | -#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */ | |
| 396 | -void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags); | |
| 397 | - | |
| 398 | -#define TARGET_PAGE_BITS 12 | |
| 399 | -#include "cpu-all.h" | |
| 400 | - | |
| 401 | -#endif /* CPU_I386_H */ |
exec.h renamed to exec-all.h
exec-arm.h deleted
100644 → 0
| 1 | -/* | |
| 2 | - * ARM execution defines | |
| 3 | - * | |
| 4 | - * Copyright (c) 2003 Fabrice Bellard | |
| 5 | - * | |
| 6 | - * This library is free software; you can redistribute it and/or | |
| 7 | - * modify it under the terms of the GNU Lesser General Public | |
| 8 | - * License as published by the Free Software Foundation; either | |
| 9 | - * version 2 of the License, or (at your option) any later version. | |
| 10 | - * | |
| 11 | - * This library is distributed in the hope that it will be useful, | |
| 12 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | - * Lesser General Public License for more details. | |
| 15 | - * | |
| 16 | - * You should have received a copy of the GNU Lesser General Public | |
| 17 | - * License along with this library; if not, write to the Free Software | |
| 18 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 | - */ | |
| 20 | -#include "dyngen-exec.h" | |
| 21 | - | |
| 22 | -register struct CPUARMState *env asm(AREG0); | |
| 23 | -register uint32_t T0 asm(AREG1); | |
| 24 | -register uint32_t T1 asm(AREG2); | |
| 25 | -register uint32_t T2 asm(AREG3); | |
| 26 | - | |
| 27 | -#include "cpu-arm.h" | |
| 28 | -#include "exec.h" | |
| 29 | - | |
| 30 | -void cpu_lock(void); | |
| 31 | -void cpu_unlock(void); | |
| 32 | -void cpu_loop_exit(void); | |
| 33 | - | |
| 34 | -static inline int compute_cpsr(void) | |
| 35 | -{ | |
| 36 | - int ZF; | |
| 37 | - ZF = (env->NZF == 0); | |
| 38 | - return env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) | | |
| 39 | - (env->CF << 29) | ((env->VF & 0x80000000) >> 3); | |
| 40 | -} |
exec-i386.h deleted
100644 → 0
| 1 | -/* | |
| 2 | - * i386 execution defines | |
| 3 | - * | |
| 4 | - * Copyright (c) 2003 Fabrice Bellard | |
| 5 | - * | |
| 6 | - * This library is free software; you can redistribute it and/or | |
| 7 | - * modify it under the terms of the GNU Lesser General Public | |
| 8 | - * License as published by the Free Software Foundation; either | |
| 9 | - * version 2 of the License, or (at your option) any later version. | |
| 10 | - * | |
| 11 | - * This library is distributed in the hope that it will be useful, | |
| 12 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | - * Lesser General Public License for more details. | |
| 15 | - * | |
| 16 | - * You should have received a copy of the GNU Lesser General Public | |
| 17 | - * License along with this library; if not, write to the Free Software | |
| 18 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 | - */ | |
| 20 | -#include "dyngen-exec.h" | |
| 21 | - | |
| 22 | -/* at least 4 register variables are defines */ | |
| 23 | -register struct CPUX86State *env asm(AREG0); | |
| 24 | -register uint32_t T0 asm(AREG1); | |
| 25 | -register uint32_t T1 asm(AREG2); | |
| 26 | -register uint32_t T2 asm(AREG3); | |
| 27 | - | |
| 28 | -#define A0 T2 | |
| 29 | - | |
| 30 | -/* if more registers are available, we define some registers too */ | |
| 31 | -#ifdef AREG4 | |
| 32 | -register uint32_t EAX asm(AREG4); | |
| 33 | -#define reg_EAX | |
| 34 | -#endif | |
| 35 | - | |
| 36 | -#ifdef AREG5 | |
| 37 | -register uint32_t ESP asm(AREG5); | |
| 38 | -#define reg_ESP | |
| 39 | -#endif | |
| 40 | - | |
| 41 | -#ifdef AREG6 | |
| 42 | -register uint32_t EBP asm(AREG6); | |
| 43 | -#define reg_EBP | |
| 44 | -#endif | |
| 45 | - | |
| 46 | -#ifdef AREG7 | |
| 47 | -register uint32_t ECX asm(AREG7); | |
| 48 | -#define reg_ECX | |
| 49 | -#endif | |
| 50 | - | |
| 51 | -#ifdef AREG8 | |
| 52 | -register uint32_t EDX asm(AREG8); | |
| 53 | -#define reg_EDX | |
| 54 | -#endif | |
| 55 | - | |
| 56 | -#ifdef AREG9 | |
| 57 | -register uint32_t EBX asm(AREG9); | |
| 58 | -#define reg_EBX | |
| 59 | -#endif | |
| 60 | - | |
| 61 | -#ifdef AREG10 | |
| 62 | -register uint32_t ESI asm(AREG10); | |
| 63 | -#define reg_ESI | |
| 64 | -#endif | |
| 65 | - | |
| 66 | -#ifdef AREG11 | |
| 67 | -register uint32_t EDI asm(AREG11); | |
| 68 | -#define reg_EDI | |
| 69 | -#endif | |
| 70 | - | |
| 71 | -extern FILE *logfile; | |
| 72 | -extern int loglevel; | |
| 73 | - | |
| 74 | -#ifndef reg_EAX | |
| 75 | -#define EAX (env->regs[R_EAX]) | |
| 76 | -#endif | |
| 77 | -#ifndef reg_ECX | |
| 78 | -#define ECX (env->regs[R_ECX]) | |
| 79 | -#endif | |
| 80 | -#ifndef reg_EDX | |
| 81 | -#define EDX (env->regs[R_EDX]) | |
| 82 | -#endif | |
| 83 | -#ifndef reg_EBX | |
| 84 | -#define EBX (env->regs[R_EBX]) | |
| 85 | -#endif | |
| 86 | -#ifndef reg_ESP | |
| 87 | -#define ESP (env->regs[R_ESP]) | |
| 88 | -#endif | |
| 89 | -#ifndef reg_EBP | |
| 90 | -#define EBP (env->regs[R_EBP]) | |
| 91 | -#endif | |
| 92 | -#ifndef reg_ESI | |
| 93 | -#define ESI (env->regs[R_ESI]) | |
| 94 | -#endif | |
| 95 | -#ifndef reg_EDI | |
| 96 | -#define EDI (env->regs[R_EDI]) | |
| 97 | -#endif | |
| 98 | -#define EIP (env->eip) | |
| 99 | -#define DF (env->df) | |
| 100 | - | |
| 101 | -#define CC_SRC (env->cc_src) | |
| 102 | -#define CC_DST (env->cc_dst) | |
| 103 | -#define CC_OP (env->cc_op) | |
| 104 | - | |
| 105 | -/* float macros */ | |
| 106 | -#define FT0 (env->ft0) | |
| 107 | -#define ST0 (env->fpregs[env->fpstt]) | |
| 108 | -#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7]) | |
| 109 | -#define ST1 ST(1) | |
| 110 | - | |
| 111 | -#ifdef USE_FP_CONVERT | |
| 112 | -#define FP_CONVERT (env->fp_convert) | |
| 113 | -#endif | |
| 114 | - | |
| 115 | -#include "cpu-i386.h" | |
| 116 | -#include "exec.h" | |
| 117 | - | |
| 118 | -typedef struct CCTable { | |
| 119 | - int (*compute_all)(void); /* return all the flags */ | |
| 120 | - int (*compute_c)(void); /* return the C flag */ | |
| 121 | -} CCTable; | |
| 122 | - | |
| 123 | -extern CCTable cc_table[]; | |
| 124 | - | |
| 125 | -void load_seg(int seg_reg, int selector, unsigned cur_eip); | |
| 126 | -void helper_ljmp_protected_T0_T1(void); | |
| 127 | -void helper_lcall_real_T0_T1(int shift, int next_eip); | |
| 128 | -void helper_lcall_protected_T0_T1(int shift, int next_eip); | |
| 129 | -void helper_iret_real(int shift); | |
| 130 | -void helper_iret_protected(int shift); | |
| 131 | -void helper_lret_protected(int shift, int addend); | |
| 132 | -void helper_lldt_T0(void); | |
| 133 | -void helper_ltr_T0(void); | |
| 134 | -void helper_movl_crN_T0(int reg); | |
| 135 | -void helper_movl_drN_T0(int reg); | |
| 136 | -void helper_invlpg(unsigned int addr); | |
| 137 | -void cpu_x86_update_cr0(CPUX86State *env); | |
| 138 | -void cpu_x86_update_cr3(CPUX86State *env); | |
| 139 | -void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr); | |
| 140 | -int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write); | |
| 141 | -void tlb_fill(unsigned long addr, int is_write, void *retaddr); | |
| 142 | -void __hidden cpu_lock(void); | |
| 143 | -void __hidden cpu_unlock(void); | |
| 144 | -void do_interrupt(int intno, int is_int, int error_code, | |
| 145 | - unsigned int next_eip, int is_hw); | |
| 146 | -void do_interrupt_user(int intno, int is_int, int error_code, | |
| 147 | - unsigned int next_eip); | |
| 148 | -void raise_interrupt(int intno, int is_int, int error_code, | |
| 149 | - unsigned int next_eip); | |
| 150 | -void raise_exception_err(int exception_index, int error_code); | |
| 151 | -void raise_exception(int exception_index); | |
| 152 | -void __hidden cpu_loop_exit(void); | |
| 153 | -void helper_fsave(uint8_t *ptr, int data32); | |
| 154 | -void helper_frstor(uint8_t *ptr, int data32); | |
| 155 | - | |
| 156 | -void OPPROTO op_movl_eflags_T0(void); | |
| 157 | -void OPPROTO op_movl_T0_eflags(void); | |
| 158 | -void raise_interrupt(int intno, int is_int, int error_code, | |
| 159 | - unsigned int next_eip); | |
| 160 | -void raise_exception_err(int exception_index, int error_code); | |
| 161 | -void raise_exception(int exception_index); | |
| 162 | -void helper_divl_EAX_T0(uint32_t eip); | |
| 163 | -void helper_idivl_EAX_T0(uint32_t eip); | |
| 164 | -void helper_cmpxchg8b(void); | |
| 165 | -void helper_cpuid(void); | |
| 166 | -void helper_rdtsc(void); | |
| 167 | -void helper_rdmsr(void); | |
| 168 | -void helper_wrmsr(void); | |
| 169 | -void helper_lsl(void); | |
| 170 | -void helper_lar(void); | |
| 171 | - | |
| 172 | -#ifdef USE_X86LDOUBLE | |
| 173 | -/* use long double functions */ | |
| 174 | -#define lrint lrintl | |
| 175 | -#define llrint llrintl | |
| 176 | -#define fabs fabsl | |
| 177 | -#define sin sinl | |
| 178 | -#define cos cosl | |
| 179 | -#define sqrt sqrtl | |
| 180 | -#define pow powl | |
| 181 | -#define log logl | |
| 182 | -#define tan tanl | |
| 183 | -#define atan2 atan2l | |
| 184 | -#define floor floorl | |
| 185 | -#define ceil ceill | |
| 186 | -#define rint rintl | |
| 187 | -#endif | |
| 188 | - | |
| 189 | -extern int lrint(CPU86_LDouble x); | |
| 190 | -extern int64_t llrint(CPU86_LDouble x); | |
| 191 | -extern CPU86_LDouble fabs(CPU86_LDouble x); | |
| 192 | -extern CPU86_LDouble sin(CPU86_LDouble x); | |
| 193 | -extern CPU86_LDouble cos(CPU86_LDouble x); | |
| 194 | -extern CPU86_LDouble sqrt(CPU86_LDouble x); | |
| 195 | -extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble); | |
| 196 | -extern CPU86_LDouble log(CPU86_LDouble x); | |
| 197 | -extern CPU86_LDouble tan(CPU86_LDouble x); | |
| 198 | -extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble); | |
| 199 | -extern CPU86_LDouble floor(CPU86_LDouble x); | |
| 200 | -extern CPU86_LDouble ceil(CPU86_LDouble x); | |
| 201 | -extern CPU86_LDouble rint(CPU86_LDouble x); | |
| 202 | - | |
| 203 | -#define RC_MASK 0xc00 | |
| 204 | -#define RC_NEAR 0x000 | |
| 205 | -#define RC_DOWN 0x400 | |
| 206 | -#define RC_UP 0x800 | |
| 207 | -#define RC_CHOP 0xc00 | |
| 208 | - | |
| 209 | -#define MAXTAN 9223372036854775808.0 | |
| 210 | - | |
| 211 | -#ifdef __arm__ | |
| 212 | -/* we have no way to do correct rounding - a FPU emulator is needed */ | |
| 213 | -#define FE_DOWNWARD FE_TONEAREST | |
| 214 | -#define FE_UPWARD FE_TONEAREST | |
| 215 | -#define FE_TOWARDZERO FE_TONEAREST | |
| 216 | -#endif | |
| 217 | - | |
| 218 | -#ifdef USE_X86LDOUBLE | |
| 219 | - | |
| 220 | -/* only for x86 */ | |
| 221 | -typedef union { | |
| 222 | - long double d; | |
| 223 | - struct { | |
| 224 | - unsigned long long lower; | |
| 225 | - unsigned short upper; | |
| 226 | - } l; | |
| 227 | -} CPU86_LDoubleU; | |
| 228 | - | |
| 229 | -/* the following deal with x86 long double-precision numbers */ | |
| 230 | -#define MAXEXPD 0x7fff | |
| 231 | -#define EXPBIAS 16383 | |
| 232 | -#define EXPD(fp) (fp.l.upper & 0x7fff) | |
| 233 | -#define SIGND(fp) ((fp.l.upper) & 0x8000) | |
| 234 | -#define MANTD(fp) (fp.l.lower) | |
| 235 | -#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS | |
| 236 | - | |
| 237 | -#else | |
| 238 | - | |
| 239 | -/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */ | |
| 240 | -typedef union { | |
| 241 | - double d; | |
| 242 | -#if !defined(WORDS_BIGENDIAN) && !defined(__arm__) | |
| 243 | - struct { | |
| 244 | - uint32_t lower; | |
| 245 | - int32_t upper; | |
| 246 | - } l; | |
| 247 | -#else | |
| 248 | - struct { | |
| 249 | - int32_t upper; | |
| 250 | - uint32_t lower; | |
| 251 | - } l; | |
| 252 | -#endif | |
| 253 | -#ifndef __arm__ | |
| 254 | - int64_t ll; | |
| 255 | -#endif | |
| 256 | -} CPU86_LDoubleU; | |
| 257 | - | |
| 258 | -/* the following deal with IEEE double-precision numbers */ | |
| 259 | -#define MAXEXPD 0x7ff | |
| 260 | -#define EXPBIAS 1023 | |
| 261 | -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) | |
| 262 | -#define SIGND(fp) ((fp.l.upper) & 0x80000000) | |
| 263 | -#ifdef __arm__ | |
| 264 | -#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32)) | |
| 265 | -#else | |
| 266 | -#define MANTD(fp) (fp.ll & ((1LL << 52) - 1)) | |
| 267 | -#endif | |
| 268 | -#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20) | |
| 269 | -#endif | |
| 270 | - | |
| 271 | -static inline void fpush(void) | |
| 272 | -{ | |
| 273 | - env->fpstt = (env->fpstt - 1) & 7; | |
| 274 | - env->fptags[env->fpstt] = 0; /* validate stack entry */ | |
| 275 | -} | |
| 276 | - | |
| 277 | -static inline void fpop(void) | |
| 278 | -{ | |
| 279 | - env->fptags[env->fpstt] = 1; /* invvalidate stack entry */ | |
| 280 | - env->fpstt = (env->fpstt + 1) & 7; | |
| 281 | -} | |
| 282 | - | |
| 283 | -#ifndef USE_X86LDOUBLE | |
| 284 | -static inline CPU86_LDouble helper_fldt(uint8_t *ptr) | |
| 285 | -{ | |
| 286 | - CPU86_LDoubleU temp; | |
| 287 | - int upper, e; | |
| 288 | - uint64_t ll; | |
| 289 | - | |
| 290 | - /* mantissa */ | |
| 291 | - upper = lduw(ptr + 8); | |
| 292 | - /* XXX: handle overflow ? */ | |
| 293 | - e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */ | |
| 294 | - e |= (upper >> 4) & 0x800; /* sign */ | |
| 295 | - ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1); | |
| 296 | -#ifdef __arm__ | |
| 297 | - temp.l.upper = (e << 20) | (ll >> 32); | |
| 298 | - temp.l.lower = ll; | |
| 299 | -#else | |
| 300 | - temp.ll = ll | ((uint64_t)e << 52); | |
| 301 | -#endif | |
| 302 | - return temp.d; | |
| 303 | -} | |
| 304 | - | |
| 305 | -static inline void helper_fstt(CPU86_LDouble f, uint8_t *ptr) | |
| 306 | -{ | |
| 307 | - CPU86_LDoubleU temp; | |
| 308 | - int e; | |
| 309 | - | |
| 310 | - temp.d = f; | |
| 311 | - /* mantissa */ | |
| 312 | - stq(ptr, (MANTD(temp) << 11) | (1LL << 63)); | |
| 313 | - /* exponent + sign */ | |
| 314 | - e = EXPD(temp) - EXPBIAS + 16383; | |
| 315 | - e |= SIGND(temp) >> 16; | |
| 316 | - stw(ptr + 8, e); | |
| 317 | -} | |
| 318 | -#endif | |
| 319 | - | |
| 320 | -const CPU86_LDouble f15rk[7]; | |
| 321 | - | |
| 322 | -void helper_fldt_ST0_A0(void); | |
| 323 | -void helper_fstt_ST0_A0(void); | |
| 324 | -void helper_fbld_ST0_A0(void); | |
| 325 | -void helper_fbst_ST0_A0(void); | |
| 326 | -void helper_f2xm1(void); | |
| 327 | -void helper_fyl2x(void); | |
| 328 | -void helper_fptan(void); | |
| 329 | -void helper_fpatan(void); | |
| 330 | -void helper_fxtract(void); | |
| 331 | -void helper_fprem1(void); | |
| 332 | -void helper_fprem(void); | |
| 333 | -void helper_fyl2xp1(void); | |
| 334 | -void helper_fsqrt(void); | |
| 335 | -void helper_fsincos(void); | |
| 336 | -void helper_frndint(void); | |
| 337 | -void helper_fscale(void); | |
| 338 | -void helper_fsin(void); | |
| 339 | -void helper_fcos(void); | |
| 340 | -void helper_fxam_ST0(void); | |
| 341 | -void helper_fstenv(uint8_t *ptr, int data32); | |
| 342 | -void helper_fldenv(uint8_t *ptr, int data32); | |
| 343 | -void helper_fsave(uint8_t *ptr, int data32); | |
| 344 | -void helper_frstor(uint8_t *ptr, int data32); | |
| 345 | - | |
| 346 | -const uint8_t parity_table[256]; | |
| 347 | -const uint8_t rclw_table[32]; | |
| 348 | -const uint8_t rclb_table[32]; | |
| 349 | - | |
| 350 | -static inline uint32_t compute_eflags(void) | |
| 351 | -{ | |
| 352 | - return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); | |
| 353 | -} | |
| 354 | - | |
| 355 | -#define FL_UPDATE_MASK32 (TF_MASK | AC_MASK | ID_MASK) | |
| 356 | - | |
| 357 | -#define FL_UPDATE_CPL0_MASK (TF_MASK | IF_MASK | IOPL_MASK | NT_MASK | \ | |
| 358 | - RF_MASK | AC_MASK | ID_MASK) | |
| 359 | - | |
| 360 | -/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */ | |
| 361 | -static inline void load_eflags(int eflags, int update_mask) | |
| 362 | -{ | |
| 363 | - CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); | |
| 364 | - DF = 1 - (2 * ((eflags >> 10) & 1)); | |
| 365 | - env->eflags = (env->eflags & ~update_mask) | | |
| 366 | - (eflags & update_mask); | |
| 367 | -} | |
| 368 | - | |
| 369 | -/* memory access macros */ | |
| 370 | - | |
| 371 | -#define ldul ldl | |
| 372 | -#define lduq ldq | |
| 373 | -#define ldul_user ldl_user | |
| 374 | -#define ldul_kernel ldl_kernel | |
| 375 | - | |
| 376 | -#define ldub_raw ldub | |
| 377 | -#define ldsb_raw ldsb | |
| 378 | -#define lduw_raw lduw | |
| 379 | -#define ldsw_raw ldsw | |
| 380 | -#define ldl_raw ldl | |
| 381 | -#define ldq_raw ldq | |
| 382 | - | |
| 383 | -#define stb_raw stb | |
| 384 | -#define stw_raw stw | |
| 385 | -#define stl_raw stl | |
| 386 | -#define stq_raw stq | |
| 387 | - | |
| 388 | -#define MEMUSER 0 | |
| 389 | -#define DATA_SIZE 1 | |
| 390 | -#include "softmmu_header.h" | |
| 391 | - | |
| 392 | -#define DATA_SIZE 2 | |
| 393 | -#include "softmmu_header.h" | |
| 394 | - | |
| 395 | -#define DATA_SIZE 4 | |
| 396 | -#include "softmmu_header.h" | |
| 397 | - | |
| 398 | -#define DATA_SIZE 8 | |
| 399 | -#include "softmmu_header.h" | |
| 400 | - | |
| 401 | -#undef MEMUSER | |
| 402 | -#define MEMUSER 1 | |
| 403 | -#define DATA_SIZE 1 | |
| 404 | -#include "softmmu_header.h" | |
| 405 | - | |
| 406 | -#define DATA_SIZE 2 | |
| 407 | -#include "softmmu_header.h" | |
| 408 | - | |
| 409 | -#define DATA_SIZE 4 | |
| 410 | -#include "softmmu_header.h" | |
| 411 | - | |
| 412 | -#define DATA_SIZE 8 | |
| 413 | -#include "softmmu_header.h" | |
| 414 | - | |
| 415 | -#undef MEMUSER | |
| 416 | - |
helper-i386.c deleted
100644 → 0
| 1 | -/* | |
| 2 | - * i386 helpers | |
| 3 | - * | |
| 4 | - * Copyright (c) 2003 Fabrice Bellard | |
| 5 | - * | |
| 6 | - * This library is free software; you can redistribute it and/or | |
| 7 | - * modify it under the terms of the GNU Lesser General Public | |
| 8 | - * License as published by the Free Software Foundation; either | |
| 9 | - * version 2 of the License, or (at your option) any later version. | |
| 10 | - * | |
| 11 | - * This library is distributed in the hope that it will be useful, | |
| 12 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | - * Lesser General Public License for more details. | |
| 15 | - * | |
| 16 | - * You should have received a copy of the GNU Lesser General Public | |
| 17 | - * License along with this library; if not, write to the Free Software | |
| 18 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 | - */ | |
| 20 | -#include "exec-i386.h" | |
| 21 | - | |
| 22 | -const uint8_t parity_table[256] = { | |
| 23 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 24 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 25 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 26 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 27 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 28 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 29 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 30 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 31 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 32 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 33 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 34 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 35 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 36 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 37 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 38 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 39 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 40 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 41 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 42 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 43 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 44 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 45 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 46 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 47 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 48 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 49 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 50 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 51 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 52 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 53 | - CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0, | |
| 54 | - 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P, | |
| 55 | -}; | |
| 56 | - | |
| 57 | -/* modulo 17 table */ | |
| 58 | -const uint8_t rclw_table[32] = { | |
| 59 | - 0, 1, 2, 3, 4, 5, 6, 7, | |
| 60 | - 8, 9,10,11,12,13,14,15, | |
| 61 | - 16, 0, 1, 2, 3, 4, 5, 6, | |
| 62 | - 7, 8, 9,10,11,12,13,14, | |
| 63 | -}; | |
| 64 | - | |
| 65 | -/* modulo 9 table */ | |
| 66 | -const uint8_t rclb_table[32] = { | |
| 67 | - 0, 1, 2, 3, 4, 5, 6, 7, | |
| 68 | - 8, 0, 1, 2, 3, 4, 5, 6, | |
| 69 | - 7, 8, 0, 1, 2, 3, 4, 5, | |
| 70 | - 6, 7, 8, 0, 1, 2, 3, 4, | |
| 71 | -}; | |
| 72 | - | |
| 73 | -const CPU86_LDouble f15rk[7] = | |
| 74 | -{ | |
| 75 | - 0.00000000000000000000L, | |
| 76 | - 1.00000000000000000000L, | |
| 77 | - 3.14159265358979323851L, /*pi*/ | |
| 78 | - 0.30102999566398119523L, /*lg2*/ | |
| 79 | - 0.69314718055994530943L, /*ln2*/ | |
| 80 | - 1.44269504088896340739L, /*l2e*/ | |
| 81 | - 3.32192809488736234781L, /*l2t*/ | |
| 82 | -}; | |
| 83 | - | |
| 84 | -/* thread support */ | |
| 85 | - | |
| 86 | -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; | |
| 87 | - | |
| 88 | -void cpu_lock(void) | |
| 89 | -{ | |
| 90 | - spin_lock(&global_cpu_lock); | |
| 91 | -} | |
| 92 | - | |
| 93 | -void cpu_unlock(void) | |
| 94 | -{ | |
| 95 | - spin_unlock(&global_cpu_lock); | |
| 96 | -} | |
| 97 | - | |
| 98 | -void cpu_loop_exit(void) | |
| 99 | -{ | |
| 100 | - /* NOTE: the register at this point must be saved by hand because | |
| 101 | - longjmp restore them */ | |
| 102 | -#ifdef reg_EAX | |
| 103 | - env->regs[R_EAX] = EAX; | |
| 104 | -#endif | |
| 105 | -#ifdef reg_ECX | |
| 106 | - env->regs[R_ECX] = ECX; | |
| 107 | -#endif | |
| 108 | -#ifdef reg_EDX | |
| 109 | - env->regs[R_EDX] = EDX; | |
| 110 | -#endif | |
| 111 | -#ifdef reg_EBX | |
| 112 | - env->regs[R_EBX] = EBX; | |
| 113 | -#endif | |
| 114 | -#ifdef reg_ESP | |
| 115 | - env->regs[R_ESP] = ESP; | |
| 116 | -#endif | |
| 117 | -#ifdef reg_EBP | |
| 118 | - env->regs[R_EBP] = EBP; | |
| 119 | -#endif | |
| 120 | -#ifdef reg_ESI | |
| 121 | - env->regs[R_ESI] = ESI; | |
| 122 | -#endif | |
| 123 | -#ifdef reg_EDI | |
| 124 | - env->regs[R_EDI] = EDI; | |
| 125 | -#endif | |
| 126 | - longjmp(env->jmp_env, 1); | |
| 127 | -} | |
| 128 | - | |
| 129 | -static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, | |
| 130 | - uint32_t *esp_ptr, int dpl) | |
| 131 | -{ | |
| 132 | - int type, index, shift; | |
| 133 | - | |
| 134 | -#if 0 | |
| 135 | - { | |
| 136 | - int i; | |
| 137 | - printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit); | |
| 138 | - for(i=0;i<env->tr.limit;i++) { | |
| 139 | - printf("%02x ", env->tr.base[i]); | |
| 140 | - if ((i & 7) == 7) printf("\n"); | |
| 141 | - } | |
| 142 | - printf("\n"); | |
| 143 | - } | |
| 144 | -#endif | |
| 145 | - | |
| 146 | - if (!(env->tr.flags & DESC_P_MASK)) | |
| 147 | - cpu_abort(env, "invalid tss"); | |
| 148 | - type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf; | |
| 149 | - if ((type & 7) != 1) | |
| 150 | - cpu_abort(env, "invalid tss type"); | |
| 151 | - shift = type >> 3; | |
| 152 | - index = (dpl * 4 + 2) << shift; | |
| 153 | - if (index + (4 << shift) - 1 > env->tr.limit) | |
| 154 | - raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc); | |
| 155 | - if (shift == 0) { | |
| 156 | - *esp_ptr = lduw(env->tr.base + index); | |
| 157 | - *ss_ptr = lduw(env->tr.base + index + 2); | |
| 158 | - } else { | |
| 159 | - *esp_ptr = ldl(env->tr.base + index); | |
| 160 | - *ss_ptr = lduw(env->tr.base + index + 4); | |
| 161 | - } | |
| 162 | -} | |
| 163 | - | |
| 164 | -/* return non zero if error */ | |
| 165 | -static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr, | |
| 166 | - int selector) | |
| 167 | -{ | |
| 168 | - SegmentCache *dt; | |
| 169 | - int index; | |
| 170 | - uint8_t *ptr; | |
| 171 | - | |
| 172 | - if (selector & 0x4) | |
| 173 | - dt = &env->ldt; | |
| 174 | - else | |
| 175 | - dt = &env->gdt; | |
| 176 | - index = selector & ~7; | |
| 177 | - if ((index + 7) > dt->limit) | |
| 178 | - return -1; | |
| 179 | - ptr = dt->base + index; | |
| 180 | - *e1_ptr = ldl(ptr); | |
| 181 | - *e2_ptr = ldl(ptr + 4); | |
| 182 | - return 0; | |
| 183 | -} | |
| 184 | - | |
| 185 | -static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2) | |
| 186 | -{ | |
| 187 | - unsigned int limit; | |
| 188 | - limit = (e1 & 0xffff) | (e2 & 0x000f0000); | |
| 189 | - if (e2 & DESC_G_MASK) | |
| 190 | - limit = (limit << 12) | 0xfff; | |
| 191 | - return limit; | |
| 192 | -} | |
| 193 | - | |
| 194 | -static inline uint8_t *get_seg_base(uint32_t e1, uint32_t e2) | |
| 195 | -{ | |
| 196 | - return (uint8_t *)((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000)); | |
| 197 | -} | |
| 198 | - | |
| 199 | -static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2) | |
| 200 | -{ | |
| 201 | - sc->base = get_seg_base(e1, e2); | |
| 202 | - sc->limit = get_seg_limit(e1, e2); | |
| 203 | - sc->flags = e2; | |
| 204 | -} | |
| 205 | - | |
| 206 | -/* init the segment cache in vm86 mode. */ | |
| 207 | -static inline void load_seg_vm(int seg, int selector) | |
| 208 | -{ | |
| 209 | - selector &= 0xffff; | |
| 210 | - cpu_x86_load_seg_cache(env, seg, selector, | |
| 211 | - (uint8_t *)(selector << 4), 0xffff, 0); | |
| 212 | -} | |
| 213 | - | |
| 214 | -/* protected mode interrupt */ | |
| 215 | -static void do_interrupt_protected(int intno, int is_int, int error_code, | |
| 216 | - unsigned int next_eip, int is_hw) | |
| 217 | -{ | |
| 218 | - SegmentCache *dt; | |
| 219 | - uint8_t *ptr, *ssp; | |
| 220 | - int type, dpl, selector, ss_dpl, cpl; | |
| 221 | - int has_error_code, new_stack, shift; | |
| 222 | - uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2, push_size; | |
| 223 | - uint32_t old_cs, old_ss, old_esp, old_eip; | |
| 224 | - | |
| 225 | - dt = &env->idt; | |
| 226 | - if (intno * 8 + 7 > dt->limit) | |
| 227 | - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | |
| 228 | - ptr = dt->base + intno * 8; | |
| 229 | - e1 = ldl(ptr); | |
| 230 | - e2 = ldl(ptr + 4); | |
| 231 | - /* check gate type */ | |
| 232 | - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; | |
| 233 | - switch(type) { | |
| 234 | - case 5: /* task gate */ | |
| 235 | - cpu_abort(env, "task gate not supported"); | |
| 236 | - break; | |
| 237 | - case 6: /* 286 interrupt gate */ | |
| 238 | - case 7: /* 286 trap gate */ | |
| 239 | - case 14: /* 386 interrupt gate */ | |
| 240 | - case 15: /* 386 trap gate */ | |
| 241 | - break; | |
| 242 | - default: | |
| 243 | - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | |
| 244 | - break; | |
| 245 | - } | |
| 246 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
| 247 | - cpl = env->hflags & HF_CPL_MASK; | |
| 248 | - /* check privledge if software int */ | |
| 249 | - if (is_int && dpl < cpl) | |
| 250 | - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | |
| 251 | - /* check valid bit */ | |
| 252 | - if (!(e2 & DESC_P_MASK)) | |
| 253 | - raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2); | |
| 254 | - selector = e1 >> 16; | |
| 255 | - offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); | |
| 256 | - if ((selector & 0xfffc) == 0) | |
| 257 | - raise_exception_err(EXCP0D_GPF, 0); | |
| 258 | - | |
| 259 | - if (load_segment(&e1, &e2, selector) != 0) | |
| 260 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 261 | - if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) | |
| 262 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 263 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
| 264 | - if (dpl > cpl) | |
| 265 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 266 | - if (!(e2 & DESC_P_MASK)) | |
| 267 | - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
| 268 | - if (!(e2 & DESC_C_MASK) && dpl < cpl) { | |
| 269 | - /* to inner priviledge */ | |
| 270 | - get_ss_esp_from_tss(&ss, &esp, dpl); | |
| 271 | - if ((ss & 0xfffc) == 0) | |
| 272 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 273 | - if ((ss & 3) != dpl) | |
| 274 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 275 | - if (load_segment(&ss_e1, &ss_e2, ss) != 0) | |
| 276 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 277 | - ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; | |
| 278 | - if (ss_dpl != dpl) | |
| 279 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 280 | - if (!(ss_e2 & DESC_S_MASK) || | |
| 281 | - (ss_e2 & DESC_CS_MASK) || | |
| 282 | - !(ss_e2 & DESC_W_MASK)) | |
| 283 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 284 | - if (!(ss_e2 & DESC_P_MASK)) | |
| 285 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 286 | - new_stack = 1; | |
| 287 | - } else if ((e2 & DESC_C_MASK) || dpl == cpl) { | |
| 288 | - /* to same priviledge */ | |
| 289 | - new_stack = 0; | |
| 290 | - } else { | |
| 291 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 292 | - new_stack = 0; /* avoid warning */ | |
| 293 | - } | |
| 294 | - | |
| 295 | - shift = type >> 3; | |
| 296 | - has_error_code = 0; | |
| 297 | - if (!is_int && !is_hw) { | |
| 298 | - switch(intno) { | |
| 299 | - case 8: | |
| 300 | - case 10: | |
| 301 | - case 11: | |
| 302 | - case 12: | |
| 303 | - case 13: | |
| 304 | - case 14: | |
| 305 | - case 17: | |
| 306 | - has_error_code = 1; | |
| 307 | - break; | |
| 308 | - } | |
| 309 | - } | |
| 310 | - push_size = 6 + (new_stack << 2) + (has_error_code << 1); | |
| 311 | - if (env->eflags & VM_MASK) | |
| 312 | - push_size += 8; | |
| 313 | - push_size <<= shift; | |
| 314 | - | |
| 315 | - /* XXX: check that enough room is available */ | |
| 316 | - if (new_stack) { | |
| 317 | - old_esp = ESP; | |
| 318 | - old_ss = env->segs[R_SS].selector; | |
| 319 | - ss = (ss & ~3) | dpl; | |
| 320 | - cpu_x86_load_seg_cache(env, R_SS, ss, | |
| 321 | - get_seg_base(ss_e1, ss_e2), | |
| 322 | - get_seg_limit(ss_e1, ss_e2), | |
| 323 | - ss_e2); | |
| 324 | - } else { | |
| 325 | - old_esp = 0; | |
| 326 | - old_ss = 0; | |
| 327 | - esp = ESP; | |
| 328 | - } | |
| 329 | - if (is_int) | |
| 330 | - old_eip = next_eip; | |
| 331 | - else | |
| 332 | - old_eip = env->eip; | |
| 333 | - old_cs = env->segs[R_CS].selector; | |
| 334 | - selector = (selector & ~3) | dpl; | |
| 335 | - cpu_x86_load_seg_cache(env, R_CS, selector, | |
| 336 | - get_seg_base(e1, e2), | |
| 337 | - get_seg_limit(e1, e2), | |
| 338 | - e2); | |
| 339 | - cpu_x86_set_cpl(env, dpl); | |
| 340 | - env->eip = offset; | |
| 341 | - ESP = esp - push_size; | |
| 342 | - ssp = env->segs[R_SS].base + esp; | |
| 343 | - if (shift == 1) { | |
| 344 | - int old_eflags; | |
| 345 | - if (env->eflags & VM_MASK) { | |
| 346 | - ssp -= 4; | |
| 347 | - stl(ssp, env->segs[R_GS].selector); | |
| 348 | - ssp -= 4; | |
| 349 | - stl(ssp, env->segs[R_FS].selector); | |
| 350 | - ssp -= 4; | |
| 351 | - stl(ssp, env->segs[R_DS].selector); | |
| 352 | - ssp -= 4; | |
| 353 | - stl(ssp, env->segs[R_ES].selector); | |
| 354 | - } | |
| 355 | - if (new_stack) { | |
| 356 | - ssp -= 4; | |
| 357 | - stl(ssp, old_ss); | |
| 358 | - ssp -= 4; | |
| 359 | - stl(ssp, old_esp); | |
| 360 | - } | |
| 361 | - ssp -= 4; | |
| 362 | - old_eflags = compute_eflags(); | |
| 363 | - stl(ssp, old_eflags); | |
| 364 | - ssp -= 4; | |
| 365 | - stl(ssp, old_cs); | |
| 366 | - ssp -= 4; | |
| 367 | - stl(ssp, old_eip); | |
| 368 | - if (has_error_code) { | |
| 369 | - ssp -= 4; | |
| 370 | - stl(ssp, error_code); | |
| 371 | - } | |
| 372 | - } else { | |
| 373 | - if (new_stack) { | |
| 374 | - ssp -= 2; | |
| 375 | - stw(ssp, old_ss); | |
| 376 | - ssp -= 2; | |
| 377 | - stw(ssp, old_esp); | |
| 378 | - } | |
| 379 | - ssp -= 2; | |
| 380 | - stw(ssp, compute_eflags()); | |
| 381 | - ssp -= 2; | |
| 382 | - stw(ssp, old_cs); | |
| 383 | - ssp -= 2; | |
| 384 | - stw(ssp, old_eip); | |
| 385 | - if (has_error_code) { | |
| 386 | - ssp -= 2; | |
| 387 | - stw(ssp, error_code); | |
| 388 | - } | |
| 389 | - } | |
| 390 | - | |
| 391 | - /* interrupt gate clear IF mask */ | |
| 392 | - if ((type & 1) == 0) { | |
| 393 | - env->eflags &= ~IF_MASK; | |
| 394 | - } | |
| 395 | - env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK); | |
| 396 | -} | |
| 397 | - | |
| 398 | -/* real mode interrupt */ | |
| 399 | -static void do_interrupt_real(int intno, int is_int, int error_code, | |
| 400 | - unsigned int next_eip) | |
| 401 | -{ | |
| 402 | - SegmentCache *dt; | |
| 403 | - uint8_t *ptr, *ssp; | |
| 404 | - int selector; | |
| 405 | - uint32_t offset, esp; | |
| 406 | - uint32_t old_cs, old_eip; | |
| 407 | - | |
| 408 | - /* real mode (simpler !) */ | |
| 409 | - dt = &env->idt; | |
| 410 | - if (intno * 4 + 3 > dt->limit) | |
| 411 | - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | |
| 412 | - ptr = dt->base + intno * 4; | |
| 413 | - offset = lduw(ptr); | |
| 414 | - selector = lduw(ptr + 2); | |
| 415 | - esp = ESP; | |
| 416 | - ssp = env->segs[R_SS].base; | |
| 417 | - if (is_int) | |
| 418 | - old_eip = next_eip; | |
| 419 | - else | |
| 420 | - old_eip = env->eip; | |
| 421 | - old_cs = env->segs[R_CS].selector; | |
| 422 | - esp -= 2; | |
| 423 | - stw(ssp + (esp & 0xffff), compute_eflags()); | |
| 424 | - esp -= 2; | |
| 425 | - stw(ssp + (esp & 0xffff), old_cs); | |
| 426 | - esp -= 2; | |
| 427 | - stw(ssp + (esp & 0xffff), old_eip); | |
| 428 | - | |
| 429 | - /* update processor state */ | |
| 430 | - ESP = (ESP & ~0xffff) | (esp & 0xffff); | |
| 431 | - env->eip = offset; | |
| 432 | - env->segs[R_CS].selector = selector; | |
| 433 | - env->segs[R_CS].base = (uint8_t *)(selector << 4); | |
| 434 | - env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK); | |
| 435 | -} | |
| 436 | - | |
| 437 | -/* fake user mode interrupt */ | |
| 438 | -void do_interrupt_user(int intno, int is_int, int error_code, | |
| 439 | - unsigned int next_eip) | |
| 440 | -{ | |
| 441 | - SegmentCache *dt; | |
| 442 | - uint8_t *ptr; | |
| 443 | - int dpl, cpl; | |
| 444 | - uint32_t e2; | |
| 445 | - | |
| 446 | - dt = &env->idt; | |
| 447 | - ptr = dt->base + (intno * 8); | |
| 448 | - e2 = ldl(ptr + 4); | |
| 449 | - | |
| 450 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
| 451 | - cpl = env->hflags & HF_CPL_MASK; | |
| 452 | - /* check privledge if software int */ | |
| 453 | - if (is_int && dpl < cpl) | |
| 454 | - raise_exception_err(EXCP0D_GPF, intno * 8 + 2); | |
| 455 | - | |
| 456 | - /* Since we emulate only user space, we cannot do more than | |
| 457 | - exiting the emulation with the suitable exception and error | |
| 458 | - code */ | |
| 459 | - if (is_int) | |
| 460 | - EIP = next_eip; | |
| 461 | -} | |
| 462 | - | |
| 463 | -/* | |
| 464 | - * Begin excution of an interruption. is_int is TRUE if coming from | |
| 465 | - * the int instruction. next_eip is the EIP value AFTER the interrupt | |
| 466 | - * instruction. It is only relevant if is_int is TRUE. | |
| 467 | - */ | |
| 468 | -void do_interrupt(int intno, int is_int, int error_code, | |
| 469 | - unsigned int next_eip, int is_hw) | |
| 470 | -{ | |
| 471 | - if (env->cr[0] & CR0_PE_MASK) { | |
| 472 | - do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw); | |
| 473 | - } else { | |
| 474 | - do_interrupt_real(intno, is_int, error_code, next_eip); | |
| 475 | - } | |
| 476 | -} | |
| 477 | - | |
| 478 | -/* | |
| 479 | - * Signal an interruption. It is executed in the main CPU loop. | |
| 480 | - * is_int is TRUE if coming from the int instruction. next_eip is the | |
| 481 | - * EIP value AFTER the interrupt instruction. It is only relevant if | |
| 482 | - * is_int is TRUE. | |
| 483 | - */ | |
| 484 | -void raise_interrupt(int intno, int is_int, int error_code, | |
| 485 | - unsigned int next_eip) | |
| 486 | -{ | |
| 487 | - env->exception_index = intno; | |
| 488 | - env->error_code = error_code; | |
| 489 | - env->exception_is_int = is_int; | |
| 490 | - env->exception_next_eip = next_eip; | |
| 491 | - cpu_loop_exit(); | |
| 492 | -} | |
| 493 | - | |
| 494 | -/* shortcuts to generate exceptions */ | |
| 495 | -void raise_exception_err(int exception_index, int error_code) | |
| 496 | -{ | |
| 497 | - raise_interrupt(exception_index, 0, error_code, 0); | |
| 498 | -} | |
| 499 | - | |
| 500 | -void raise_exception(int exception_index) | |
| 501 | -{ | |
| 502 | - raise_interrupt(exception_index, 0, 0, 0); | |
| 503 | -} | |
| 504 | - | |
| 505 | -#ifdef BUGGY_GCC_DIV64 | |
| 506 | -/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we | |
| 507 | - call it from another function */ | |
| 508 | -uint32_t div64(uint32_t *q_ptr, uint64_t num, uint32_t den) | |
| 509 | -{ | |
| 510 | - *q_ptr = num / den; | |
| 511 | - return num % den; | |
| 512 | -} | |
| 513 | - | |
| 514 | -int32_t idiv64(int32_t *q_ptr, int64_t num, int32_t den) | |
| 515 | -{ | |
| 516 | - *q_ptr = num / den; | |
| 517 | - return num % den; | |
| 518 | -} | |
| 519 | -#endif | |
| 520 | - | |
| 521 | -void helper_divl_EAX_T0(uint32_t eip) | |
| 522 | -{ | |
| 523 | - unsigned int den, q, r; | |
| 524 | - uint64_t num; | |
| 525 | - | |
| 526 | - num = EAX | ((uint64_t)EDX << 32); | |
| 527 | - den = T0; | |
| 528 | - if (den == 0) { | |
| 529 | - EIP = eip; | |
| 530 | - raise_exception(EXCP00_DIVZ); | |
| 531 | - } | |
| 532 | -#ifdef BUGGY_GCC_DIV64 | |
| 533 | - r = div64(&q, num, den); | |
| 534 | -#else | |
| 535 | - q = (num / den); | |
| 536 | - r = (num % den); | |
| 537 | -#endif | |
| 538 | - EAX = q; | |
| 539 | - EDX = r; | |
| 540 | -} | |
| 541 | - | |
| 542 | -void helper_idivl_EAX_T0(uint32_t eip) | |
| 543 | -{ | |
| 544 | - int den, q, r; | |
| 545 | - int64_t num; | |
| 546 | - | |
| 547 | - num = EAX | ((uint64_t)EDX << 32); | |
| 548 | - den = T0; | |
| 549 | - if (den == 0) { | |
| 550 | - EIP = eip; | |
| 551 | - raise_exception(EXCP00_DIVZ); | |
| 552 | - } | |
| 553 | -#ifdef BUGGY_GCC_DIV64 | |
| 554 | - r = idiv64(&q, num, den); | |
| 555 | -#else | |
| 556 | - q = (num / den); | |
| 557 | - r = (num % den); | |
| 558 | -#endif | |
| 559 | - EAX = q; | |
| 560 | - EDX = r; | |
| 561 | -} | |
| 562 | - | |
| 563 | -void helper_cmpxchg8b(void) | |
| 564 | -{ | |
| 565 | - uint64_t d; | |
| 566 | - int eflags; | |
| 567 | - | |
| 568 | - eflags = cc_table[CC_OP].compute_all(); | |
| 569 | - d = ldq((uint8_t *)A0); | |
| 570 | - if (d == (((uint64_t)EDX << 32) | EAX)) { | |
| 571 | - stq((uint8_t *)A0, ((uint64_t)ECX << 32) | EBX); | |
| 572 | - eflags |= CC_Z; | |
| 573 | - } else { | |
| 574 | - EDX = d >> 32; | |
| 575 | - EAX = d; | |
| 576 | - eflags &= ~CC_Z; | |
| 577 | - } | |
| 578 | - CC_SRC = eflags; | |
| 579 | -} | |
| 580 | - | |
| 581 | -/* We simulate a pre-MMX pentium as in valgrind */ | |
| 582 | -#define CPUID_FP87 (1 << 0) | |
| 583 | -#define CPUID_VME (1 << 1) | |
| 584 | -#define CPUID_DE (1 << 2) | |
| 585 | -#define CPUID_PSE (1 << 3) | |
| 586 | -#define CPUID_TSC (1 << 4) | |
| 587 | -#define CPUID_MSR (1 << 5) | |
| 588 | -#define CPUID_PAE (1 << 6) | |
| 589 | -#define CPUID_MCE (1 << 7) | |
| 590 | -#define CPUID_CX8 (1 << 8) | |
| 591 | -#define CPUID_APIC (1 << 9) | |
| 592 | -#define CPUID_SEP (1 << 11) /* sysenter/sysexit */ | |
| 593 | -#define CPUID_MTRR (1 << 12) | |
| 594 | -#define CPUID_PGE (1 << 13) | |
| 595 | -#define CPUID_MCA (1 << 14) | |
| 596 | -#define CPUID_CMOV (1 << 15) | |
| 597 | -/* ... */ | |
| 598 | -#define CPUID_MMX (1 << 23) | |
| 599 | -#define CPUID_FXSR (1 << 24) | |
| 600 | -#define CPUID_SSE (1 << 25) | |
| 601 | -#define CPUID_SSE2 (1 << 26) | |
| 602 | - | |
| 603 | -void helper_cpuid(void) | |
| 604 | -{ | |
| 605 | - if (EAX == 0) { | |
| 606 | - EAX = 1; /* max EAX index supported */ | |
| 607 | - EBX = 0x756e6547; | |
| 608 | - ECX = 0x6c65746e; | |
| 609 | - EDX = 0x49656e69; | |
| 610 | - } else if (EAX == 1) { | |
| 611 | - int family, model, stepping; | |
| 612 | - /* EAX = 1 info */ | |
| 613 | -#if 0 | |
| 614 | - /* pentium 75-200 */ | |
| 615 | - family = 5; | |
| 616 | - model = 2; | |
| 617 | - stepping = 11; | |
| 618 | -#else | |
| 619 | - /* pentium pro */ | |
| 620 | - family = 6; | |
| 621 | - model = 1; | |
| 622 | - stepping = 3; | |
| 623 | -#endif | |
| 624 | - EAX = (family << 8) | (model << 4) | stepping; | |
| 625 | - EBX = 0; | |
| 626 | - ECX = 0; | |
| 627 | - EDX = CPUID_FP87 | CPUID_DE | CPUID_PSE | | |
| 628 | - CPUID_TSC | CPUID_MSR | CPUID_MCE | | |
| 629 | - CPUID_CX8 | CPUID_PGE | CPUID_CMOV; | |
| 630 | - } | |
| 631 | -} | |
| 632 | - | |
| 633 | -void helper_lldt_T0(void) | |
| 634 | -{ | |
| 635 | - int selector; | |
| 636 | - SegmentCache *dt; | |
| 637 | - uint32_t e1, e2; | |
| 638 | - int index; | |
| 639 | - uint8_t *ptr; | |
| 640 | - | |
| 641 | - selector = T0 & 0xffff; | |
| 642 | - if ((selector & 0xfffc) == 0) { | |
| 643 | - /* XXX: NULL selector case: invalid LDT */ | |
| 644 | - env->ldt.base = NULL; | |
| 645 | - env->ldt.limit = 0; | |
| 646 | - } else { | |
| 647 | - if (selector & 0x4) | |
| 648 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 649 | - dt = &env->gdt; | |
| 650 | - index = selector & ~7; | |
| 651 | - if ((index + 7) > dt->limit) | |
| 652 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 653 | - ptr = dt->base + index; | |
| 654 | - e1 = ldl(ptr); | |
| 655 | - e2 = ldl(ptr + 4); | |
| 656 | - if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2) | |
| 657 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 658 | - if (!(e2 & DESC_P_MASK)) | |
| 659 | - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
| 660 | - load_seg_cache_raw_dt(&env->ldt, e1, e2); | |
| 661 | - } | |
| 662 | - env->ldt.selector = selector; | |
| 663 | -} | |
| 664 | - | |
| 665 | -void helper_ltr_T0(void) | |
| 666 | -{ | |
| 667 | - int selector; | |
| 668 | - SegmentCache *dt; | |
| 669 | - uint32_t e1, e2; | |
| 670 | - int index, type; | |
| 671 | - uint8_t *ptr; | |
| 672 | - | |
| 673 | - selector = T0 & 0xffff; | |
| 674 | - if ((selector & 0xfffc) == 0) { | |
| 675 | - /* NULL selector case: invalid LDT */ | |
| 676 | - env->tr.base = NULL; | |
| 677 | - env->tr.limit = 0; | |
| 678 | - env->tr.flags = 0; | |
| 679 | - } else { | |
| 680 | - if (selector & 0x4) | |
| 681 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 682 | - dt = &env->gdt; | |
| 683 | - index = selector & ~7; | |
| 684 | - if ((index + 7) > dt->limit) | |
| 685 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 686 | - ptr = dt->base + index; | |
| 687 | - e1 = ldl(ptr); | |
| 688 | - e2 = ldl(ptr + 4); | |
| 689 | - type = (e2 >> DESC_TYPE_SHIFT) & 0xf; | |
| 690 | - if ((e2 & DESC_S_MASK) || | |
| 691 | - (type != 2 && type != 9)) | |
| 692 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 693 | - if (!(e2 & DESC_P_MASK)) | |
| 694 | - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
| 695 | - load_seg_cache_raw_dt(&env->tr, e1, e2); | |
| 696 | - e2 |= 0x00000200; /* set the busy bit */ | |
| 697 | - stl(ptr + 4, e2); | |
| 698 | - } | |
| 699 | - env->tr.selector = selector; | |
| 700 | -} | |
| 701 | - | |
| 702 | -/* only works if protected mode and not VM86. Calling load_seg with | |
| 703 | - seg_reg == R_CS is discouraged */ | |
| 704 | -void load_seg(int seg_reg, int selector, unsigned int cur_eip) | |
| 705 | -{ | |
| 706 | - uint32_t e1, e2; | |
| 707 | - | |
| 708 | - if ((selector & 0xfffc) == 0) { | |
| 709 | - /* null selector case */ | |
| 710 | - if (seg_reg == R_SS) { | |
| 711 | - EIP = cur_eip; | |
| 712 | - raise_exception_err(EXCP0D_GPF, 0); | |
| 713 | - } else { | |
| 714 | - cpu_x86_load_seg_cache(env, seg_reg, selector, NULL, 0, 0); | |
| 715 | - } | |
| 716 | - } else { | |
| 717 | - if (load_segment(&e1, &e2, selector) != 0) { | |
| 718 | - EIP = cur_eip; | |
| 719 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 720 | - } | |
| 721 | - if (!(e2 & DESC_S_MASK) || | |
| 722 | - (e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { | |
| 723 | - EIP = cur_eip; | |
| 724 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 725 | - } | |
| 726 | - | |
| 727 | - if (seg_reg == R_SS) { | |
| 728 | - if ((e2 & (DESC_CS_MASK | DESC_W_MASK)) == 0) { | |
| 729 | - EIP = cur_eip; | |
| 730 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 731 | - } | |
| 732 | - } else { | |
| 733 | - if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK) { | |
| 734 | - EIP = cur_eip; | |
| 735 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 736 | - } | |
| 737 | - } | |
| 738 | - | |
| 739 | - if (!(e2 & DESC_P_MASK)) { | |
| 740 | - EIP = cur_eip; | |
| 741 | - if (seg_reg == R_SS) | |
| 742 | - raise_exception_err(EXCP0C_STACK, selector & 0xfffc); | |
| 743 | - else | |
| 744 | - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
| 745 | - } | |
| 746 | - cpu_x86_load_seg_cache(env, seg_reg, selector, | |
| 747 | - get_seg_base(e1, e2), | |
| 748 | - get_seg_limit(e1, e2), | |
| 749 | - e2); | |
| 750 | -#if 0 | |
| 751 | - fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", | |
| 752 | - selector, (unsigned long)sc->base, sc->limit, sc->flags); | |
| 753 | -#endif | |
| 754 | - } | |
| 755 | -} | |
| 756 | - | |
| 757 | -/* protected mode jump */ | |
| 758 | -void helper_ljmp_protected_T0_T1(void) | |
| 759 | -{ | |
| 760 | - int new_cs, new_eip; | |
| 761 | - uint32_t e1, e2, cpl, dpl, rpl, limit; | |
| 762 | - | |
| 763 | - new_cs = T0; | |
| 764 | - new_eip = T1; | |
| 765 | - if ((new_cs & 0xfffc) == 0) | |
| 766 | - raise_exception_err(EXCP0D_GPF, 0); | |
| 767 | - if (load_segment(&e1, &e2, new_cs) != 0) | |
| 768 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 769 | - cpl = env->hflags & HF_CPL_MASK; | |
| 770 | - if (e2 & DESC_S_MASK) { | |
| 771 | - if (!(e2 & DESC_CS_MASK)) | |
| 772 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 773 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
| 774 | - if (e2 & DESC_CS_MASK) { | |
| 775 | - /* conforming code segment */ | |
| 776 | - if (dpl > cpl) | |
| 777 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 778 | - } else { | |
| 779 | - /* non conforming code segment */ | |
| 780 | - rpl = new_cs & 3; | |
| 781 | - if (rpl > cpl) | |
| 782 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 783 | - if (dpl != cpl) | |
| 784 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 785 | - } | |
| 786 | - if (!(e2 & DESC_P_MASK)) | |
| 787 | - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | |
| 788 | - limit = get_seg_limit(e1, e2); | |
| 789 | - if (new_eip > limit) | |
| 790 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 791 | - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, | |
| 792 | - get_seg_base(e1, e2), limit, e2); | |
| 793 | - EIP = new_eip; | |
| 794 | - } else { | |
| 795 | - cpu_abort(env, "jmp to call/task gate not supported 0x%04x:0x%08x", | |
| 796 | - new_cs, new_eip); | |
| 797 | - } | |
| 798 | -} | |
| 799 | - | |
| 800 | -/* real mode call */ | |
| 801 | -void helper_lcall_real_T0_T1(int shift, int next_eip) | |
| 802 | -{ | |
| 803 | - int new_cs, new_eip; | |
| 804 | - uint32_t esp, esp_mask; | |
| 805 | - uint8_t *ssp; | |
| 806 | - | |
| 807 | - new_cs = T0; | |
| 808 | - new_eip = T1; | |
| 809 | - esp = ESP; | |
| 810 | - esp_mask = 0xffffffff; | |
| 811 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
| 812 | - esp_mask = 0xffff; | |
| 813 | - ssp = env->segs[R_SS].base; | |
| 814 | - if (shift) { | |
| 815 | - esp -= 4; | |
| 816 | - stl(ssp + (esp & esp_mask), env->segs[R_CS].selector); | |
| 817 | - esp -= 4; | |
| 818 | - stl(ssp + (esp & esp_mask), next_eip); | |
| 819 | - } else { | |
| 820 | - esp -= 2; | |
| 821 | - stw(ssp + (esp & esp_mask), env->segs[R_CS].selector); | |
| 822 | - esp -= 2; | |
| 823 | - stw(ssp + (esp & esp_mask), next_eip); | |
| 824 | - } | |
| 825 | - | |
| 826 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
| 827 | - ESP = (ESP & ~0xffff) | (esp & 0xffff); | |
| 828 | - else | |
| 829 | - ESP = esp; | |
| 830 | - env->eip = new_eip; | |
| 831 | - env->segs[R_CS].selector = new_cs; | |
| 832 | - env->segs[R_CS].base = (uint8_t *)(new_cs << 4); | |
| 833 | -} | |
| 834 | - | |
| 835 | -/* protected mode call */ | |
| 836 | -void helper_lcall_protected_T0_T1(int shift, int next_eip) | |
| 837 | -{ | |
| 838 | - int new_cs, new_eip; | |
| 839 | - uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count; | |
| 840 | - uint32_t ss, ss_e1, ss_e2, push_size, sp, type, ss_dpl; | |
| 841 | - uint32_t old_ss, old_esp, val, i, limit; | |
| 842 | - uint8_t *ssp, *old_ssp; | |
| 843 | - | |
| 844 | - new_cs = T0; | |
| 845 | - new_eip = T1; | |
| 846 | - if ((new_cs & 0xfffc) == 0) | |
| 847 | - raise_exception_err(EXCP0D_GPF, 0); | |
| 848 | - if (load_segment(&e1, &e2, new_cs) != 0) | |
| 849 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 850 | - cpl = env->hflags & HF_CPL_MASK; | |
| 851 | - if (e2 & DESC_S_MASK) { | |
| 852 | - if (!(e2 & DESC_CS_MASK)) | |
| 853 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 854 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
| 855 | - if (e2 & DESC_CS_MASK) { | |
| 856 | - /* conforming code segment */ | |
| 857 | - if (dpl > cpl) | |
| 858 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 859 | - } else { | |
| 860 | - /* non conforming code segment */ | |
| 861 | - rpl = new_cs & 3; | |
| 862 | - if (rpl > cpl) | |
| 863 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 864 | - if (dpl != cpl) | |
| 865 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 866 | - } | |
| 867 | - if (!(e2 & DESC_P_MASK)) | |
| 868 | - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | |
| 869 | - | |
| 870 | - sp = ESP; | |
| 871 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
| 872 | - sp &= 0xffff; | |
| 873 | - ssp = env->segs[R_SS].base + sp; | |
| 874 | - if (shift) { | |
| 875 | - ssp -= 4; | |
| 876 | - stl(ssp, env->segs[R_CS].selector); | |
| 877 | - ssp -= 4; | |
| 878 | - stl(ssp, next_eip); | |
| 879 | - } else { | |
| 880 | - ssp -= 2; | |
| 881 | - stw(ssp, env->segs[R_CS].selector); | |
| 882 | - ssp -= 2; | |
| 883 | - stw(ssp, next_eip); | |
| 884 | - } | |
| 885 | - sp -= (4 << shift); | |
| 886 | - | |
| 887 | - limit = get_seg_limit(e1, e2); | |
| 888 | - if (new_eip > limit) | |
| 889 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 890 | - /* from this point, not restartable */ | |
| 891 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
| 892 | - ESP = (ESP & 0xffff0000) | (sp & 0xffff); | |
| 893 | - else | |
| 894 | - ESP = sp; | |
| 895 | - cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl, | |
| 896 | - get_seg_base(e1, e2), limit, e2); | |
| 897 | - EIP = new_eip; | |
| 898 | - } else { | |
| 899 | - /* check gate type */ | |
| 900 | - type = (e2 >> DESC_TYPE_SHIFT) & 0x1f; | |
| 901 | - switch(type) { | |
| 902 | - case 1: /* available 286 TSS */ | |
| 903 | - case 9: /* available 386 TSS */ | |
| 904 | - case 5: /* task gate */ | |
| 905 | - cpu_abort(env, "task gate not supported"); | |
| 906 | - break; | |
| 907 | - case 4: /* 286 call gate */ | |
| 908 | - case 12: /* 386 call gate */ | |
| 909 | - break; | |
| 910 | - default: | |
| 911 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 912 | - break; | |
| 913 | - } | |
| 914 | - shift = type >> 3; | |
| 915 | - | |
| 916 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
| 917 | - rpl = new_cs & 3; | |
| 918 | - if (dpl < cpl || dpl < rpl) | |
| 919 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 920 | - /* check valid bit */ | |
| 921 | - if (!(e2 & DESC_P_MASK)) | |
| 922 | - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | |
| 923 | - selector = e1 >> 16; | |
| 924 | - offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff); | |
| 925 | - if ((selector & 0xfffc) == 0) | |
| 926 | - raise_exception_err(EXCP0D_GPF, 0); | |
| 927 | - | |
| 928 | - if (load_segment(&e1, &e2, selector) != 0) | |
| 929 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 930 | - if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK))) | |
| 931 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 932 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
| 933 | - if (dpl > cpl) | |
| 934 | - raise_exception_err(EXCP0D_GPF, selector & 0xfffc); | |
| 935 | - if (!(e2 & DESC_P_MASK)) | |
| 936 | - raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc); | |
| 937 | - | |
| 938 | - if (!(e2 & DESC_C_MASK) && dpl < cpl) { | |
| 939 | - /* to inner priviledge */ | |
| 940 | - get_ss_esp_from_tss(&ss, &sp, dpl); | |
| 941 | - if ((ss & 0xfffc) == 0) | |
| 942 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 943 | - if ((ss & 3) != dpl) | |
| 944 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 945 | - if (load_segment(&ss_e1, &ss_e2, ss) != 0) | |
| 946 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 947 | - ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; | |
| 948 | - if (ss_dpl != dpl) | |
| 949 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 950 | - if (!(ss_e2 & DESC_S_MASK) || | |
| 951 | - (ss_e2 & DESC_CS_MASK) || | |
| 952 | - !(ss_e2 & DESC_W_MASK)) | |
| 953 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 954 | - if (!(ss_e2 & DESC_P_MASK)) | |
| 955 | - raise_exception_err(EXCP0A_TSS, ss & 0xfffc); | |
| 956 | - | |
| 957 | - param_count = e2 & 0x1f; | |
| 958 | - push_size = ((param_count * 2) + 8) << shift; | |
| 959 | - | |
| 960 | - old_esp = ESP; | |
| 961 | - old_ss = env->segs[R_SS].selector; | |
| 962 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
| 963 | - old_esp &= 0xffff; | |
| 964 | - old_ssp = env->segs[R_SS].base + old_esp; | |
| 965 | - | |
| 966 | - /* XXX: from this point not restartable */ | |
| 967 | - ss = (ss & ~3) | dpl; | |
| 968 | - cpu_x86_load_seg_cache(env, R_SS, ss, | |
| 969 | - get_seg_base(ss_e1, ss_e2), | |
| 970 | - get_seg_limit(ss_e1, ss_e2), | |
| 971 | - ss_e2); | |
| 972 | - | |
| 973 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
| 974 | - sp &= 0xffff; | |
| 975 | - ssp = env->segs[R_SS].base + sp; | |
| 976 | - if (shift) { | |
| 977 | - ssp -= 4; | |
| 978 | - stl(ssp, old_ss); | |
| 979 | - ssp -= 4; | |
| 980 | - stl(ssp, old_esp); | |
| 981 | - ssp -= 4 * param_count; | |
| 982 | - for(i = 0; i < param_count; i++) { | |
| 983 | - val = ldl(old_ssp + i * 4); | |
| 984 | - stl(ssp + i * 4, val); | |
| 985 | - } | |
| 986 | - } else { | |
| 987 | - ssp -= 2; | |
| 988 | - stw(ssp, old_ss); | |
| 989 | - ssp -= 2; | |
| 990 | - stw(ssp, old_esp); | |
| 991 | - ssp -= 2 * param_count; | |
| 992 | - for(i = 0; i < param_count; i++) { | |
| 993 | - val = lduw(old_ssp + i * 2); | |
| 994 | - stw(ssp + i * 2, val); | |
| 995 | - } | |
| 996 | - } | |
| 997 | - } else { | |
| 998 | - /* to same priviledge */ | |
| 999 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
| 1000 | - sp &= 0xffff; | |
| 1001 | - ssp = env->segs[R_SS].base + sp; | |
| 1002 | - push_size = (4 << shift); | |
| 1003 | - } | |
| 1004 | - | |
| 1005 | - if (shift) { | |
| 1006 | - ssp -= 4; | |
| 1007 | - stl(ssp, env->segs[R_CS].selector); | |
| 1008 | - ssp -= 4; | |
| 1009 | - stl(ssp, next_eip); | |
| 1010 | - } else { | |
| 1011 | - ssp -= 2; | |
| 1012 | - stw(ssp, env->segs[R_CS].selector); | |
| 1013 | - ssp -= 2; | |
| 1014 | - stw(ssp, next_eip); | |
| 1015 | - } | |
| 1016 | - | |
| 1017 | - sp -= push_size; | |
| 1018 | - selector = (selector & ~3) | dpl; | |
| 1019 | - cpu_x86_load_seg_cache(env, R_CS, selector, | |
| 1020 | - get_seg_base(e1, e2), | |
| 1021 | - get_seg_limit(e1, e2), | |
| 1022 | - e2); | |
| 1023 | - cpu_x86_set_cpl(env, dpl); | |
| 1024 | - | |
| 1025 | - /* from this point, not restartable if same priviledge */ | |
| 1026 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
| 1027 | - ESP = (ESP & 0xffff0000) | (sp & 0xffff); | |
| 1028 | - else | |
| 1029 | - ESP = sp; | |
| 1030 | - EIP = offset; | |
| 1031 | - } | |
| 1032 | -} | |
| 1033 | - | |
| 1034 | -/* real mode iret */ | |
| 1035 | -void helper_iret_real(int shift) | |
| 1036 | -{ | |
| 1037 | - uint32_t sp, new_cs, new_eip, new_eflags, new_esp; | |
| 1038 | - uint8_t *ssp; | |
| 1039 | - int eflags_mask; | |
| 1040 | - | |
| 1041 | - sp = ESP & 0xffff; | |
| 1042 | - ssp = env->segs[R_SS].base + sp; | |
| 1043 | - if (shift == 1) { | |
| 1044 | - /* 32 bits */ | |
| 1045 | - new_eflags = ldl(ssp + 8); | |
| 1046 | - new_cs = ldl(ssp + 4) & 0xffff; | |
| 1047 | - new_eip = ldl(ssp) & 0xffff; | |
| 1048 | - } else { | |
| 1049 | - /* 16 bits */ | |
| 1050 | - new_eflags = lduw(ssp + 4); | |
| 1051 | - new_cs = lduw(ssp + 2); | |
| 1052 | - new_eip = lduw(ssp); | |
| 1053 | - } | |
| 1054 | - new_esp = sp + (6 << shift); | |
| 1055 | - ESP = (ESP & 0xffff0000) | | |
| 1056 | - (new_esp & 0xffff); | |
| 1057 | - load_seg_vm(R_CS, new_cs); | |
| 1058 | - env->eip = new_eip; | |
| 1059 | - eflags_mask = FL_UPDATE_CPL0_MASK; | |
| 1060 | - if (shift == 0) | |
| 1061 | - eflags_mask &= 0xffff; | |
| 1062 | - load_eflags(new_eflags, eflags_mask); | |
| 1063 | -} | |
| 1064 | - | |
| 1065 | -/* protected mode iret */ | |
| 1066 | -static inline void helper_ret_protected(int shift, int is_iret, int addend) | |
| 1067 | -{ | |
| 1068 | - uint32_t sp, new_cs, new_eip, new_eflags, new_esp, new_ss; | |
| 1069 | - uint32_t new_es, new_ds, new_fs, new_gs; | |
| 1070 | - uint32_t e1, e2, ss_e1, ss_e2; | |
| 1071 | - int cpl, dpl, rpl, eflags_mask; | |
| 1072 | - uint8_t *ssp; | |
| 1073 | - | |
| 1074 | - sp = ESP; | |
| 1075 | - if (!(env->segs[R_SS].flags & DESC_B_MASK)) | |
| 1076 | - sp &= 0xffff; | |
| 1077 | - ssp = env->segs[R_SS].base + sp; | |
| 1078 | - if (shift == 1) { | |
| 1079 | - /* 32 bits */ | |
| 1080 | - if (is_iret) | |
| 1081 | - new_eflags = ldl(ssp + 8); | |
| 1082 | - new_cs = ldl(ssp + 4) & 0xffff; | |
| 1083 | - new_eip = ldl(ssp); | |
| 1084 | - if (is_iret && (new_eflags & VM_MASK)) | |
| 1085 | - goto return_to_vm86; | |
| 1086 | - } else { | |
| 1087 | - /* 16 bits */ | |
| 1088 | - if (is_iret) | |
| 1089 | - new_eflags = lduw(ssp + 4); | |
| 1090 | - new_cs = lduw(ssp + 2); | |
| 1091 | - new_eip = lduw(ssp); | |
| 1092 | - } | |
| 1093 | - if ((new_cs & 0xfffc) == 0) | |
| 1094 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 1095 | - if (load_segment(&e1, &e2, new_cs) != 0) | |
| 1096 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 1097 | - if (!(e2 & DESC_S_MASK) || | |
| 1098 | - !(e2 & DESC_CS_MASK)) | |
| 1099 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 1100 | - cpl = env->hflags & HF_CPL_MASK; | |
| 1101 | - rpl = new_cs & 3; | |
| 1102 | - if (rpl < cpl) | |
| 1103 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 1104 | - dpl = (e2 >> DESC_DPL_SHIFT) & 3; | |
| 1105 | - if (e2 & DESC_CS_MASK) { | |
| 1106 | - if (dpl > rpl) | |
| 1107 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 1108 | - } else { | |
| 1109 | - if (dpl != rpl) | |
| 1110 | - raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc); | |
| 1111 | - } | |
| 1112 | - if (!(e2 & DESC_P_MASK)) | |
| 1113 | - raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc); | |
| 1114 | - | |
| 1115 | - if (rpl == cpl) { | |
| 1116 | - /* return to same priledge level */ | |
| 1117 | - cpu_x86_load_seg_cache(env, R_CS, new_cs, | |
| 1118 | - get_seg_base(e1, e2), | |
| 1119 | - get_seg_limit(e1, e2), | |
| 1120 | - e2); | |
| 1121 | - new_esp = sp + (4 << shift) + ((2 * is_iret) << shift) + addend; | |
| 1122 | - } else { | |
| 1123 | - /* return to different priviledge level */ | |
| 1124 | - ssp += (4 << shift) + ((2 * is_iret) << shift) + addend; | |
| 1125 | - if (shift == 1) { | |
| 1126 | - /* 32 bits */ | |
| 1127 | - new_esp = ldl(ssp); | |
| 1128 | - new_ss = ldl(ssp + 4) & 0xffff; | |
| 1129 | - } else { | |
| 1130 | - /* 16 bits */ | |
| 1131 | - new_esp = lduw(ssp); | |
| 1132 | - new_ss = lduw(ssp + 2); | |
| 1133 | - } | |
| 1134 | - | |
| 1135 | - if ((new_ss & 3) != rpl) | |
| 1136 | - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | |
| 1137 | - if (load_segment(&ss_e1, &ss_e2, new_ss) != 0) | |
| 1138 | - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | |
| 1139 | - if (!(ss_e2 & DESC_S_MASK) || | |
| 1140 | - (ss_e2 & DESC_CS_MASK) || | |
| 1141 | - !(ss_e2 & DESC_W_MASK)) | |
| 1142 | - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | |
| 1143 | - dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3; | |
| 1144 | - if (dpl != rpl) | |
| 1145 | - raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc); | |
| 1146 | - if (!(ss_e2 & DESC_P_MASK)) | |
| 1147 | - raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc); | |
| 1148 | - | |
| 1149 | - cpu_x86_load_seg_cache(env, R_CS, new_cs, | |
| 1150 | - get_seg_base(e1, e2), | |
| 1151 | - get_seg_limit(e1, e2), | |
| 1152 | - e2); | |
| 1153 | - cpu_x86_load_seg_cache(env, R_SS, new_ss, | |
| 1154 | - get_seg_base(ss_e1, ss_e2), | |
| 1155 | - get_seg_limit(ss_e1, ss_e2), | |
| 1156 | - ss_e2); | |
| 1157 | - cpu_x86_set_cpl(env, rpl); | |
| 1158 | - } | |
| 1159 | - if (env->segs[R_SS].flags & DESC_B_MASK) | |
| 1160 | - ESP = new_esp; | |
| 1161 | - else | |
| 1162 | - ESP = (ESP & 0xffff0000) | | |
| 1163 | - (new_esp & 0xffff); | |
| 1164 | - env->eip = new_eip; | |
| 1165 | - if (is_iret) { | |
| 1166 | - /* NOTE: 'cpl' can be different from the current CPL */ | |
| 1167 | - if (cpl == 0) | |
| 1168 | - eflags_mask = FL_UPDATE_CPL0_MASK; | |
| 1169 | - else | |
| 1170 | - eflags_mask = FL_UPDATE_MASK32; | |
| 1171 | - if (shift == 0) | |
| 1172 | - eflags_mask &= 0xffff; | |
| 1173 | - load_eflags(new_eflags, eflags_mask); | |
| 1174 | - } | |
| 1175 | - return; | |
| 1176 | - | |
| 1177 | - return_to_vm86: | |
| 1178 | - new_esp = ldl(ssp + 12); | |
| 1179 | - new_ss = ldl(ssp + 16); | |
| 1180 | - new_es = ldl(ssp + 20); | |
| 1181 | - new_ds = ldl(ssp + 24); | |
| 1182 | - new_fs = ldl(ssp + 28); | |
| 1183 | - new_gs = ldl(ssp + 32); | |
| 1184 | - | |
| 1185 | - /* modify processor state */ | |
| 1186 | - load_eflags(new_eflags, FL_UPDATE_CPL0_MASK | VM_MASK | VIF_MASK | VIP_MASK); | |
| 1187 | - load_seg_vm(R_CS, new_cs); | |
| 1188 | - cpu_x86_set_cpl(env, 3); | |
| 1189 | - load_seg_vm(R_SS, new_ss); | |
| 1190 | - load_seg_vm(R_ES, new_es); | |
| 1191 | - load_seg_vm(R_DS, new_ds); | |
| 1192 | - load_seg_vm(R_FS, new_fs); | |
| 1193 | - load_seg_vm(R_GS, new_gs); | |
| 1194 | - | |
| 1195 | - env->eip = new_eip; | |
| 1196 | - ESP = new_esp; | |
| 1197 | -} | |
| 1198 | - | |
| 1199 | -void helper_iret_protected(int shift) | |
| 1200 | -{ | |
| 1201 | - helper_ret_protected(shift, 1, 0); | |
| 1202 | -} | |
| 1203 | - | |
| 1204 | -void helper_lret_protected(int shift, int addend) | |
| 1205 | -{ | |
| 1206 | - helper_ret_protected(shift, 0, addend); | |
| 1207 | -} | |
| 1208 | - | |
| 1209 | -void helper_movl_crN_T0(int reg) | |
| 1210 | -{ | |
| 1211 | - env->cr[reg] = T0; | |
| 1212 | - switch(reg) { | |
| 1213 | - case 0: | |
| 1214 | - cpu_x86_update_cr0(env); | |
| 1215 | - break; | |
| 1216 | - case 3: | |
| 1217 | - cpu_x86_update_cr3(env); | |
| 1218 | - break; | |
| 1219 | - } | |
| 1220 | -} | |
| 1221 | - | |
| 1222 | -/* XXX: do more */ | |
| 1223 | -void helper_movl_drN_T0(int reg) | |
| 1224 | -{ | |
| 1225 | - env->dr[reg] = T0; | |
| 1226 | -} | |
| 1227 | - | |
| 1228 | -void helper_invlpg(unsigned int addr) | |
| 1229 | -{ | |
| 1230 | - cpu_x86_flush_tlb(env, addr); | |
| 1231 | -} | |
| 1232 | - | |
| 1233 | -/* rdtsc */ | |
| 1234 | -#ifndef __i386__ | |
| 1235 | -uint64_t emu_time; | |
| 1236 | -#endif | |
| 1237 | - | |
| 1238 | -void helper_rdtsc(void) | |
| 1239 | -{ | |
| 1240 | - uint64_t val; | |
| 1241 | -#ifdef __i386__ | |
| 1242 | - asm("rdtsc" : "=A" (val)); | |
| 1243 | -#else | |
| 1244 | - /* better than nothing: the time increases */ | |
| 1245 | - val = emu_time++; | |
| 1246 | -#endif | |
| 1247 | - EAX = val; | |
| 1248 | - EDX = val >> 32; | |
| 1249 | -} | |
| 1250 | - | |
| 1251 | -void helper_wrmsr(void) | |
| 1252 | -{ | |
| 1253 | - switch(ECX) { | |
| 1254 | - case MSR_IA32_SYSENTER_CS: | |
| 1255 | - env->sysenter_cs = EAX & 0xffff; | |
| 1256 | - break; | |
| 1257 | - case MSR_IA32_SYSENTER_ESP: | |
| 1258 | - env->sysenter_esp = EAX; | |
| 1259 | - break; | |
| 1260 | - case MSR_IA32_SYSENTER_EIP: | |
| 1261 | - env->sysenter_eip = EAX; | |
| 1262 | - break; | |
| 1263 | - default: | |
| 1264 | - /* XXX: exception ? */ | |
| 1265 | - break; | |
| 1266 | - } | |
| 1267 | -} | |
| 1268 | - | |
| 1269 | -void helper_rdmsr(void) | |
| 1270 | -{ | |
| 1271 | - switch(ECX) { | |
| 1272 | - case MSR_IA32_SYSENTER_CS: | |
| 1273 | - EAX = env->sysenter_cs; | |
| 1274 | - EDX = 0; | |
| 1275 | - break; | |
| 1276 | - case MSR_IA32_SYSENTER_ESP: | |
| 1277 | - EAX = env->sysenter_esp; | |
| 1278 | - EDX = 0; | |
| 1279 | - break; | |
| 1280 | - case MSR_IA32_SYSENTER_EIP: | |
| 1281 | - EAX = env->sysenter_eip; | |
| 1282 | - EDX = 0; | |
| 1283 | - break; | |
| 1284 | - default: | |
| 1285 | - /* XXX: exception ? */ | |
| 1286 | - break; | |
| 1287 | - } | |
| 1288 | -} | |
| 1289 | - | |
| 1290 | -void helper_lsl(void) | |
| 1291 | -{ | |
| 1292 | - unsigned int selector, limit; | |
| 1293 | - uint32_t e1, e2; | |
| 1294 | - | |
| 1295 | - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; | |
| 1296 | - selector = T0 & 0xffff; | |
| 1297 | - if (load_segment(&e1, &e2, selector) != 0) | |
| 1298 | - return; | |
| 1299 | - limit = (e1 & 0xffff) | (e2 & 0x000f0000); | |
| 1300 | - if (e2 & (1 << 23)) | |
| 1301 | - limit = (limit << 12) | 0xfff; | |
| 1302 | - T1 = limit; | |
| 1303 | - CC_SRC |= CC_Z; | |
| 1304 | -} | |
| 1305 | - | |
| 1306 | -void helper_lar(void) | |
| 1307 | -{ | |
| 1308 | - unsigned int selector; | |
| 1309 | - uint32_t e1, e2; | |
| 1310 | - | |
| 1311 | - CC_SRC = cc_table[CC_OP].compute_all() & ~CC_Z; | |
| 1312 | - selector = T0 & 0xffff; | |
| 1313 | - if (load_segment(&e1, &e2, selector) != 0) | |
| 1314 | - return; | |
| 1315 | - T1 = e2 & 0x00f0ff00; | |
| 1316 | - CC_SRC |= CC_Z; | |
| 1317 | -} | |
| 1318 | - | |
| 1319 | -/* FPU helpers */ | |
| 1320 | - | |
| 1321 | -#ifndef USE_X86LDOUBLE | |
| 1322 | -void helper_fldt_ST0_A0(void) | |
| 1323 | -{ | |
| 1324 | - int new_fpstt; | |
| 1325 | - new_fpstt = (env->fpstt - 1) & 7; | |
| 1326 | - env->fpregs[new_fpstt] = helper_fldt((uint8_t *)A0); | |
| 1327 | - env->fpstt = new_fpstt; | |
| 1328 | - env->fptags[new_fpstt] = 0; /* validate stack entry */ | |
| 1329 | -} | |
| 1330 | - | |
| 1331 | -void helper_fstt_ST0_A0(void) | |
| 1332 | -{ | |
| 1333 | - helper_fstt(ST0, (uint8_t *)A0); | |
| 1334 | -} | |
| 1335 | -#endif | |
| 1336 | - | |
| 1337 | -/* BCD ops */ | |
| 1338 | - | |
| 1339 | -#define MUL10(iv) ( iv + iv + (iv << 3) ) | |
| 1340 | - | |
| 1341 | -void helper_fbld_ST0_A0(void) | |
| 1342 | -{ | |
| 1343 | - CPU86_LDouble tmp; | |
| 1344 | - uint64_t val; | |
| 1345 | - unsigned int v; | |
| 1346 | - int i; | |
| 1347 | - | |
| 1348 | - val = 0; | |
| 1349 | - for(i = 8; i >= 0; i--) { | |
| 1350 | - v = ldub((uint8_t *)A0 + i); | |
| 1351 | - val = (val * 100) + ((v >> 4) * 10) + (v & 0xf); | |
| 1352 | - } | |
| 1353 | - tmp = val; | |
| 1354 | - if (ldub((uint8_t *)A0 + 9) & 0x80) | |
| 1355 | - tmp = -tmp; | |
| 1356 | - fpush(); | |
| 1357 | - ST0 = tmp; | |
| 1358 | -} | |
| 1359 | - | |
| 1360 | -void helper_fbst_ST0_A0(void) | |
| 1361 | -{ | |
| 1362 | - CPU86_LDouble tmp; | |
| 1363 | - int v; | |
| 1364 | - uint8_t *mem_ref, *mem_end; | |
| 1365 | - int64_t val; | |
| 1366 | - | |
| 1367 | - tmp = rint(ST0); | |
| 1368 | - val = (int64_t)tmp; | |
| 1369 | - mem_ref = (uint8_t *)A0; | |
| 1370 | - mem_end = mem_ref + 9; | |
| 1371 | - if (val < 0) { | |
| 1372 | - stb(mem_end, 0x80); | |
| 1373 | - val = -val; | |
| 1374 | - } else { | |
| 1375 | - stb(mem_end, 0x00); | |
| 1376 | - } | |
| 1377 | - while (mem_ref < mem_end) { | |
| 1378 | - if (val == 0) | |
| 1379 | - break; | |
| 1380 | - v = val % 100; | |
| 1381 | - val = val / 100; | |
| 1382 | - v = ((v / 10) << 4) | (v % 10); | |
| 1383 | - stb(mem_ref++, v); | |
| 1384 | - } | |
| 1385 | - while (mem_ref < mem_end) { | |
| 1386 | - stb(mem_ref++, 0); | |
| 1387 | - } | |
| 1388 | -} | |
| 1389 | - | |
| 1390 | -void helper_f2xm1(void) | |
| 1391 | -{ | |
| 1392 | - ST0 = pow(2.0,ST0) - 1.0; | |
| 1393 | -} | |
| 1394 | - | |
| 1395 | -void helper_fyl2x(void) | |
| 1396 | -{ | |
| 1397 | - CPU86_LDouble fptemp; | |
| 1398 | - | |
| 1399 | - fptemp = ST0; | |
| 1400 | - if (fptemp>0.0){ | |
| 1401 | - fptemp = log(fptemp)/log(2.0); /* log2(ST) */ | |
| 1402 | - ST1 *= fptemp; | |
| 1403 | - fpop(); | |
| 1404 | - } else { | |
| 1405 | - env->fpus &= (~0x4700); | |
| 1406 | - env->fpus |= 0x400; | |
| 1407 | - } | |
| 1408 | -} | |
| 1409 | - | |
| 1410 | -void helper_fptan(void) | |
| 1411 | -{ | |
| 1412 | - CPU86_LDouble fptemp; | |
| 1413 | - | |
| 1414 | - fptemp = ST0; | |
| 1415 | - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { | |
| 1416 | - env->fpus |= 0x400; | |
| 1417 | - } else { | |
| 1418 | - ST0 = tan(fptemp); | |
| 1419 | - fpush(); | |
| 1420 | - ST0 = 1.0; | |
| 1421 | - env->fpus &= (~0x400); /* C2 <-- 0 */ | |
| 1422 | - /* the above code is for |arg| < 2**52 only */ | |
| 1423 | - } | |
| 1424 | -} | |
| 1425 | - | |
| 1426 | -void helper_fpatan(void) | |
| 1427 | -{ | |
| 1428 | - CPU86_LDouble fptemp, fpsrcop; | |
| 1429 | - | |
| 1430 | - fpsrcop = ST1; | |
| 1431 | - fptemp = ST0; | |
| 1432 | - ST1 = atan2(fpsrcop,fptemp); | |
| 1433 | - fpop(); | |
| 1434 | -} | |
| 1435 | - | |
| 1436 | -void helper_fxtract(void) | |
| 1437 | -{ | |
| 1438 | - CPU86_LDoubleU temp; | |
| 1439 | - unsigned int expdif; | |
| 1440 | - | |
| 1441 | - temp.d = ST0; | |
| 1442 | - expdif = EXPD(temp) - EXPBIAS; | |
| 1443 | - /*DP exponent bias*/ | |
| 1444 | - ST0 = expdif; | |
| 1445 | - fpush(); | |
| 1446 | - BIASEXPONENT(temp); | |
| 1447 | - ST0 = temp.d; | |
| 1448 | -} | |
| 1449 | - | |
| 1450 | -void helper_fprem1(void) | |
| 1451 | -{ | |
| 1452 | - CPU86_LDouble dblq, fpsrcop, fptemp; | |
| 1453 | - CPU86_LDoubleU fpsrcop1, fptemp1; | |
| 1454 | - int expdif; | |
| 1455 | - int q; | |
| 1456 | - | |
| 1457 | - fpsrcop = ST0; | |
| 1458 | - fptemp = ST1; | |
| 1459 | - fpsrcop1.d = fpsrcop; | |
| 1460 | - fptemp1.d = fptemp; | |
| 1461 | - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); | |
| 1462 | - if (expdif < 53) { | |
| 1463 | - dblq = fpsrcop / fptemp; | |
| 1464 | - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); | |
| 1465 | - ST0 = fpsrcop - fptemp*dblq; | |
| 1466 | - q = (int)dblq; /* cutting off top bits is assumed here */ | |
| 1467 | - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ | |
| 1468 | - /* (C0,C1,C3) <-- (q2,q1,q0) */ | |
| 1469 | - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ | |
| 1470 | - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ | |
| 1471 | - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ | |
| 1472 | - } else { | |
| 1473 | - env->fpus |= 0x400; /* C2 <-- 1 */ | |
| 1474 | - fptemp = pow(2.0, expdif-50); | |
| 1475 | - fpsrcop = (ST0 / ST1) / fptemp; | |
| 1476 | - /* fpsrcop = integer obtained by rounding to the nearest */ | |
| 1477 | - fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)? | |
| 1478 | - floor(fpsrcop): ceil(fpsrcop); | |
| 1479 | - ST0 -= (ST1 * fpsrcop * fptemp); | |
| 1480 | - } | |
| 1481 | -} | |
| 1482 | - | |
| 1483 | -void helper_fprem(void) | |
| 1484 | -{ | |
| 1485 | - CPU86_LDouble dblq, fpsrcop, fptemp; | |
| 1486 | - CPU86_LDoubleU fpsrcop1, fptemp1; | |
| 1487 | - int expdif; | |
| 1488 | - int q; | |
| 1489 | - | |
| 1490 | - fpsrcop = ST0; | |
| 1491 | - fptemp = ST1; | |
| 1492 | - fpsrcop1.d = fpsrcop; | |
| 1493 | - fptemp1.d = fptemp; | |
| 1494 | - expdif = EXPD(fpsrcop1) - EXPD(fptemp1); | |
| 1495 | - if ( expdif < 53 ) { | |
| 1496 | - dblq = fpsrcop / fptemp; | |
| 1497 | - dblq = (dblq < 0.0)? ceil(dblq): floor(dblq); | |
| 1498 | - ST0 = fpsrcop - fptemp*dblq; | |
| 1499 | - q = (int)dblq; /* cutting off top bits is assumed here */ | |
| 1500 | - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ | |
| 1501 | - /* (C0,C1,C3) <-- (q2,q1,q0) */ | |
| 1502 | - env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */ | |
| 1503 | - env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */ | |
| 1504 | - env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */ | |
| 1505 | - } else { | |
| 1506 | - env->fpus |= 0x400; /* C2 <-- 1 */ | |
| 1507 | - fptemp = pow(2.0, expdif-50); | |
| 1508 | - fpsrcop = (ST0 / ST1) / fptemp; | |
| 1509 | - /* fpsrcop = integer obtained by chopping */ | |
| 1510 | - fpsrcop = (fpsrcop < 0.0)? | |
| 1511 | - -(floor(fabs(fpsrcop))): floor(fpsrcop); | |
| 1512 | - ST0 -= (ST1 * fpsrcop * fptemp); | |
| 1513 | - } | |
| 1514 | -} | |
| 1515 | - | |
| 1516 | -void helper_fyl2xp1(void) | |
| 1517 | -{ | |
| 1518 | - CPU86_LDouble fptemp; | |
| 1519 | - | |
| 1520 | - fptemp = ST0; | |
| 1521 | - if ((fptemp+1.0)>0.0) { | |
| 1522 | - fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */ | |
| 1523 | - ST1 *= fptemp; | |
| 1524 | - fpop(); | |
| 1525 | - } else { | |
| 1526 | - env->fpus &= (~0x4700); | |
| 1527 | - env->fpus |= 0x400; | |
| 1528 | - } | |
| 1529 | -} | |
| 1530 | - | |
| 1531 | -void helper_fsqrt(void) | |
| 1532 | -{ | |
| 1533 | - CPU86_LDouble fptemp; | |
| 1534 | - | |
| 1535 | - fptemp = ST0; | |
| 1536 | - if (fptemp<0.0) { | |
| 1537 | - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ | |
| 1538 | - env->fpus |= 0x400; | |
| 1539 | - } | |
| 1540 | - ST0 = sqrt(fptemp); | |
| 1541 | -} | |
| 1542 | - | |
| 1543 | -void helper_fsincos(void) | |
| 1544 | -{ | |
| 1545 | - CPU86_LDouble fptemp; | |
| 1546 | - | |
| 1547 | - fptemp = ST0; | |
| 1548 | - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { | |
| 1549 | - env->fpus |= 0x400; | |
| 1550 | - } else { | |
| 1551 | - ST0 = sin(fptemp); | |
| 1552 | - fpush(); | |
| 1553 | - ST0 = cos(fptemp); | |
| 1554 | - env->fpus &= (~0x400); /* C2 <-- 0 */ | |
| 1555 | - /* the above code is for |arg| < 2**63 only */ | |
| 1556 | - } | |
| 1557 | -} | |
| 1558 | - | |
| 1559 | -void helper_frndint(void) | |
| 1560 | -{ | |
| 1561 | - CPU86_LDouble a; | |
| 1562 | - | |
| 1563 | - a = ST0; | |
| 1564 | -#ifdef __arm__ | |
| 1565 | - switch(env->fpuc & RC_MASK) { | |
| 1566 | - default: | |
| 1567 | - case RC_NEAR: | |
| 1568 | - asm("rndd %0, %1" : "=f" (a) : "f"(a)); | |
| 1569 | - break; | |
| 1570 | - case RC_DOWN: | |
| 1571 | - asm("rnddm %0, %1" : "=f" (a) : "f"(a)); | |
| 1572 | - break; | |
| 1573 | - case RC_UP: | |
| 1574 | - asm("rnddp %0, %1" : "=f" (a) : "f"(a)); | |
| 1575 | - break; | |
| 1576 | - case RC_CHOP: | |
| 1577 | - asm("rnddz %0, %1" : "=f" (a) : "f"(a)); | |
| 1578 | - break; | |
| 1579 | - } | |
| 1580 | -#else | |
| 1581 | - a = rint(a); | |
| 1582 | -#endif | |
| 1583 | - ST0 = a; | |
| 1584 | -} | |
| 1585 | - | |
| 1586 | -void helper_fscale(void) | |
| 1587 | -{ | |
| 1588 | - CPU86_LDouble fpsrcop, fptemp; | |
| 1589 | - | |
| 1590 | - fpsrcop = 2.0; | |
| 1591 | - fptemp = pow(fpsrcop,ST1); | |
| 1592 | - ST0 *= fptemp; | |
| 1593 | -} | |
| 1594 | - | |
| 1595 | -void helper_fsin(void) | |
| 1596 | -{ | |
| 1597 | - CPU86_LDouble fptemp; | |
| 1598 | - | |
| 1599 | - fptemp = ST0; | |
| 1600 | - if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { | |
| 1601 | - env->fpus |= 0x400; | |
| 1602 | - } else { | |
| 1603 | - ST0 = sin(fptemp); | |
| 1604 | - env->fpus &= (~0x400); /* C2 <-- 0 */ | |
| 1605 | - /* the above code is for |arg| < 2**53 only */ | |
| 1606 | - } | |
| 1607 | -} | |
| 1608 | - | |
| 1609 | -void helper_fcos(void) | |
| 1610 | -{ | |
| 1611 | - CPU86_LDouble fptemp; | |
| 1612 | - | |
| 1613 | - fptemp = ST0; | |
| 1614 | - if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) { | |
| 1615 | - env->fpus |= 0x400; | |
| 1616 | - } else { | |
| 1617 | - ST0 = cos(fptemp); | |
| 1618 | - env->fpus &= (~0x400); /* C2 <-- 0 */ | |
| 1619 | - /* the above code is for |arg5 < 2**63 only */ | |
| 1620 | - } | |
| 1621 | -} | |
| 1622 | - | |
| 1623 | -void helper_fxam_ST0(void) | |
| 1624 | -{ | |
| 1625 | - CPU86_LDoubleU temp; | |
| 1626 | - int expdif; | |
| 1627 | - | |
| 1628 | - temp.d = ST0; | |
| 1629 | - | |
| 1630 | - env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */ | |
| 1631 | - if (SIGND(temp)) | |
| 1632 | - env->fpus |= 0x200; /* C1 <-- 1 */ | |
| 1633 | - | |
| 1634 | - expdif = EXPD(temp); | |
| 1635 | - if (expdif == MAXEXPD) { | |
| 1636 | - if (MANTD(temp) == 0) | |
| 1637 | - env->fpus |= 0x500 /*Infinity*/; | |
| 1638 | - else | |
| 1639 | - env->fpus |= 0x100 /*NaN*/; | |
| 1640 | - } else if (expdif == 0) { | |
| 1641 | - if (MANTD(temp) == 0) | |
| 1642 | - env->fpus |= 0x4000 /*Zero*/; | |
| 1643 | - else | |
| 1644 | - env->fpus |= 0x4400 /*Denormal*/; | |
| 1645 | - } else { | |
| 1646 | - env->fpus |= 0x400; | |
| 1647 | - } | |
| 1648 | -} | |
| 1649 | - | |
| 1650 | -void helper_fstenv(uint8_t *ptr, int data32) | |
| 1651 | -{ | |
| 1652 | - int fpus, fptag, exp, i; | |
| 1653 | - uint64_t mant; | |
| 1654 | - CPU86_LDoubleU tmp; | |
| 1655 | - | |
| 1656 | - fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11; | |
| 1657 | - fptag = 0; | |
| 1658 | - for (i=7; i>=0; i--) { | |
| 1659 | - fptag <<= 2; | |
| 1660 | - if (env->fptags[i]) { | |
| 1661 | - fptag |= 3; | |
| 1662 | - } else { | |
| 1663 | - tmp.d = env->fpregs[i]; | |
| 1664 | - exp = EXPD(tmp); | |
| 1665 | - mant = MANTD(tmp); | |
| 1666 | - if (exp == 0 && mant == 0) { | |
| 1667 | - /* zero */ | |
| 1668 | - fptag |= 1; | |
| 1669 | - } else if (exp == 0 || exp == MAXEXPD | |
| 1670 | -#ifdef USE_X86LDOUBLE | |
| 1671 | - || (mant & (1LL << 63)) == 0 | |
| 1672 | -#endif | |
| 1673 | - ) { | |
| 1674 | - /* NaNs, infinity, denormal */ | |
| 1675 | - fptag |= 2; | |
| 1676 | - } | |
| 1677 | - } | |
| 1678 | - } | |
| 1679 | - if (data32) { | |
| 1680 | - /* 32 bit */ | |
| 1681 | - stl(ptr, env->fpuc); | |
| 1682 | - stl(ptr + 4, fpus); | |
| 1683 | - stl(ptr + 8, fptag); | |
| 1684 | - stl(ptr + 12, 0); | |
| 1685 | - stl(ptr + 16, 0); | |
| 1686 | - stl(ptr + 20, 0); | |
| 1687 | - stl(ptr + 24, 0); | |
| 1688 | - } else { | |
| 1689 | - /* 16 bit */ | |
| 1690 | - stw(ptr, env->fpuc); | |
| 1691 | - stw(ptr + 2, fpus); | |
| 1692 | - stw(ptr + 4, fptag); | |
| 1693 | - stw(ptr + 6, 0); | |
| 1694 | - stw(ptr + 8, 0); | |
| 1695 | - stw(ptr + 10, 0); | |
| 1696 | - stw(ptr + 12, 0); | |
| 1697 | - } | |
| 1698 | -} | |
| 1699 | - | |
| 1700 | -void helper_fldenv(uint8_t *ptr, int data32) | |
| 1701 | -{ | |
| 1702 | - int i, fpus, fptag; | |
| 1703 | - | |
| 1704 | - if (data32) { | |
| 1705 | - env->fpuc = lduw(ptr); | |
| 1706 | - fpus = lduw(ptr + 4); | |
| 1707 | - fptag = lduw(ptr + 8); | |
| 1708 | - } | |
| 1709 | - else { | |
| 1710 | - env->fpuc = lduw(ptr); | |
| 1711 | - fpus = lduw(ptr + 2); | |
| 1712 | - fptag = lduw(ptr + 4); | |
| 1713 | - } | |
| 1714 | - env->fpstt = (fpus >> 11) & 7; | |
| 1715 | - env->fpus = fpus & ~0x3800; | |
| 1716 | - for(i = 0;i < 7; i++) { | |
| 1717 | - env->fptags[i] = ((fptag & 3) == 3); | |
| 1718 | - fptag >>= 2; | |
| 1719 | - } | |
| 1720 | -} | |
| 1721 | - | |
| 1722 | -void helper_fsave(uint8_t *ptr, int data32) | |
| 1723 | -{ | |
| 1724 | - CPU86_LDouble tmp; | |
| 1725 | - int i; | |
| 1726 | - | |
| 1727 | - helper_fstenv(ptr, data32); | |
| 1728 | - | |
| 1729 | - ptr += (14 << data32); | |
| 1730 | - for(i = 0;i < 8; i++) { | |
| 1731 | - tmp = ST(i); | |
| 1732 | -#ifdef USE_X86LDOUBLE | |
| 1733 | - *(long double *)ptr = tmp; | |
| 1734 | -#else | |
| 1735 | - helper_fstt(tmp, ptr); | |
| 1736 | -#endif | |
| 1737 | - ptr += 10; | |
| 1738 | - } | |
| 1739 | - | |
| 1740 | - /* fninit */ | |
| 1741 | - env->fpus = 0; | |
| 1742 | - env->fpstt = 0; | |
| 1743 | - env->fpuc = 0x37f; | |
| 1744 | - env->fptags[0] = 1; | |
| 1745 | - env->fptags[1] = 1; | |
| 1746 | - env->fptags[2] = 1; | |
| 1747 | - env->fptags[3] = 1; | |
| 1748 | - env->fptags[4] = 1; | |
| 1749 | - env->fptags[5] = 1; | |
| 1750 | - env->fptags[6] = 1; | |
| 1751 | - env->fptags[7] = 1; | |
| 1752 | -} | |
| 1753 | - | |
| 1754 | -void helper_frstor(uint8_t *ptr, int data32) | |
| 1755 | -{ | |
| 1756 | - CPU86_LDouble tmp; | |
| 1757 | - int i; | |
| 1758 | - | |
| 1759 | - helper_fldenv(ptr, data32); | |
| 1760 | - ptr += (14 << data32); | |
| 1761 | - | |
| 1762 | - for(i = 0;i < 8; i++) { | |
| 1763 | -#ifdef USE_X86LDOUBLE | |
| 1764 | - tmp = *(long double *)ptr; | |
| 1765 | -#else | |
| 1766 | - tmp = helper_fldt(ptr); | |
| 1767 | -#endif | |
| 1768 | - ST(i) = tmp; | |
| 1769 | - ptr += 10; | |
| 1770 | - } | |
| 1771 | -} | |
| 1772 | - | |
| 1773 | -#define SHIFT 0 | |
| 1774 | -#include "softmmu_template.h" | |
| 1775 | - | |
| 1776 | -#define SHIFT 1 | |
| 1777 | -#include "softmmu_template.h" | |
| 1778 | - | |
| 1779 | -#define SHIFT 2 | |
| 1780 | -#include "softmmu_template.h" | |
| 1781 | - | |
| 1782 | -#define SHIFT 3 | |
| 1783 | -#include "softmmu_template.h" | |
| 1784 | - | |
| 1785 | -/* try to fill the TLB and return an exception if error */ | |
| 1786 | -void tlb_fill(unsigned long addr, int is_write, void *retaddr) | |
| 1787 | -{ | |
| 1788 | - TranslationBlock *tb; | |
| 1789 | - int ret; | |
| 1790 | - unsigned long pc; | |
| 1791 | - ret = cpu_x86_handle_mmu_fault(env, addr, is_write); | |
| 1792 | - if (ret) { | |
| 1793 | - /* now we have a real cpu fault */ | |
| 1794 | - pc = (unsigned long)retaddr; | |
| 1795 | - tb = tb_find_pc(pc); | |
| 1796 | - if (tb) { | |
| 1797 | - /* the PC is inside the translated code. It means that we have | |
| 1798 | - a virtual CPU fault */ | |
| 1799 | - cpu_restore_state(tb, env, pc); | |
| 1800 | - } | |
| 1801 | - raise_exception_err(EXCP0E_PAGE, env->error_code); | |
| 1802 | - } | |
| 1803 | -} |
helper2-i386.c deleted
100644 → 0
| 1 | -/* | |
| 2 | - * i386 helpers (without register variable usage) | |
| 3 | - * | |
| 4 | - * Copyright (c) 2003 Fabrice Bellard | |
| 5 | - * | |
| 6 | - * This library is free software; you can redistribute it and/or | |
| 7 | - * modify it under the terms of the GNU Lesser General Public | |
| 8 | - * License as published by the Free Software Foundation; either | |
| 9 | - * version 2 of the License, or (at your option) any later version. | |
| 10 | - * | |
| 11 | - * This library is distributed in the hope that it will be useful, | |
| 12 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | - * Lesser General Public License for more details. | |
| 15 | - * | |
| 16 | - * You should have received a copy of the GNU Lesser General Public | |
| 17 | - * License along with this library; if not, write to the Free Software | |
| 18 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 | - */ | |
| 20 | -#include <stdarg.h> | |
| 21 | -#include <stdlib.h> | |
| 22 | -#include <stdio.h> | |
| 23 | -#include <string.h> | |
| 24 | -#include <inttypes.h> | |
| 25 | -#include <signal.h> | |
| 26 | -#include <assert.h> | |
| 27 | -#include <sys/mman.h> | |
| 28 | - | |
| 29 | -#include "cpu-i386.h" | |
| 30 | -#include "exec.h" | |
| 31 | - | |
| 32 | -//#define DEBUG_MMU | |
| 33 | - | |
| 34 | -CPUX86State *cpu_x86_init(void) | |
| 35 | -{ | |
| 36 | - CPUX86State *env; | |
| 37 | - int i; | |
| 38 | - static int inited; | |
| 39 | - | |
| 40 | - cpu_exec_init(); | |
| 41 | - | |
| 42 | - env = malloc(sizeof(CPUX86State)); | |
| 43 | - if (!env) | |
| 44 | - return NULL; | |
| 45 | - memset(env, 0, sizeof(CPUX86State)); | |
| 46 | - /* basic FPU init */ | |
| 47 | - for(i = 0;i < 8; i++) | |
| 48 | - env->fptags[i] = 1; | |
| 49 | - env->fpuc = 0x37f; | |
| 50 | - /* flags setup : we activate the IRQs by default as in user mode */ | |
| 51 | - env->eflags = 0x2 | IF_MASK; | |
| 52 | - | |
| 53 | - tlb_flush(env); | |
| 54 | -#ifdef CONFIG_SOFTMMU | |
| 55 | - env->hflags |= HF_SOFTMMU_MASK; | |
| 56 | -#endif | |
| 57 | - /* init various static tables */ | |
| 58 | - if (!inited) { | |
| 59 | - inited = 1; | |
| 60 | - optimize_flags_init(); | |
| 61 | - } | |
| 62 | - return env; | |
| 63 | -} | |
| 64 | - | |
| 65 | -void cpu_x86_close(CPUX86State *env) | |
| 66 | -{ | |
| 67 | - free(env); | |
| 68 | -} | |
| 69 | - | |
| 70 | -/***********************************************************/ | |
| 71 | -/* x86 debug */ | |
| 72 | - | |
| 73 | -static const char *cc_op_str[] = { | |
| 74 | - "DYNAMIC", | |
| 75 | - "EFLAGS", | |
| 76 | - "MUL", | |
| 77 | - "ADDB", | |
| 78 | - "ADDW", | |
| 79 | - "ADDL", | |
| 80 | - "ADCB", | |
| 81 | - "ADCW", | |
| 82 | - "ADCL", | |
| 83 | - "SUBB", | |
| 84 | - "SUBW", | |
| 85 | - "SUBL", | |
| 86 | - "SBBB", | |
| 87 | - "SBBW", | |
| 88 | - "SBBL", | |
| 89 | - "LOGICB", | |
| 90 | - "LOGICW", | |
| 91 | - "LOGICL", | |
| 92 | - "INCB", | |
| 93 | - "INCW", | |
| 94 | - "INCL", | |
| 95 | - "DECB", | |
| 96 | - "DECW", | |
| 97 | - "DECL", | |
| 98 | - "SHLB", | |
| 99 | - "SHLW", | |
| 100 | - "SHLL", | |
| 101 | - "SARB", | |
| 102 | - "SARW", | |
| 103 | - "SARL", | |
| 104 | -}; | |
| 105 | - | |
| 106 | -void cpu_x86_dump_state(CPUX86State *env, FILE *f, int flags) | |
| 107 | -{ | |
| 108 | - int eflags; | |
| 109 | - char cc_op_name[32]; | |
| 110 | - | |
| 111 | - eflags = env->eflags; | |
| 112 | - fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n" | |
| 113 | - "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n" | |
| 114 | - "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c]\n", | |
| 115 | - env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], | |
| 116 | - env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], | |
| 117 | - env->eip, eflags, | |
| 118 | - eflags & DF_MASK ? 'D' : '-', | |
| 119 | - eflags & CC_O ? 'O' : '-', | |
| 120 | - eflags & CC_S ? 'S' : '-', | |
| 121 | - eflags & CC_Z ? 'Z' : '-', | |
| 122 | - eflags & CC_A ? 'A' : '-', | |
| 123 | - eflags & CC_P ? 'P' : '-', | |
| 124 | - eflags & CC_C ? 'C' : '-'); | |
| 125 | - fprintf(f, "CS=%04x SS=%04x DS=%04x ES=%04x FS=%04x GS=%04x\n", | |
| 126 | - env->segs[R_CS].selector, | |
| 127 | - env->segs[R_SS].selector, | |
| 128 | - env->segs[R_DS].selector, | |
| 129 | - env->segs[R_ES].selector, | |
| 130 | - env->segs[R_FS].selector, | |
| 131 | - env->segs[R_GS].selector); | |
| 132 | - if (flags & X86_DUMP_CCOP) { | |
| 133 | - if ((unsigned)env->cc_op < CC_OP_NB) | |
| 134 | - strcpy(cc_op_name, cc_op_str[env->cc_op]); | |
| 135 | - else | |
| 136 | - snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); | |
| 137 | - fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n", | |
| 138 | - env->cc_src, env->cc_dst, cc_op_name); | |
| 139 | - } | |
| 140 | - if (flags & X86_DUMP_FPU) { | |
| 141 | - fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n", | |
| 142 | - (double)env->fpregs[0], | |
| 143 | - (double)env->fpregs[1], | |
| 144 | - (double)env->fpregs[2], | |
| 145 | - (double)env->fpregs[3]); | |
| 146 | - fprintf(f, "ST4=%f ST5=%f ST6=%f ST7=%f\n", | |
| 147 | - (double)env->fpregs[4], | |
| 148 | - (double)env->fpregs[5], | |
| 149 | - (double)env->fpregs[7], | |
| 150 | - (double)env->fpregs[8]); | |
| 151 | - } | |
| 152 | -} | |
| 153 | - | |
| 154 | -/***********************************************************/ | |
| 155 | -/* x86 mmu */ | |
| 156 | -/* XXX: add PGE support */ | |
| 157 | - | |
| 158 | -/* called when cr3 or PG bit are modified */ | |
| 159 | -static int last_pg_state = -1; | |
| 160 | -static int last_pe_state = 0; | |
| 161 | -int phys_ram_size; | |
| 162 | -int phys_ram_fd; | |
| 163 | -uint8_t *phys_ram_base; | |
| 164 | - | |
| 165 | -void cpu_x86_update_cr0(CPUX86State *env) | |
| 166 | -{ | |
| 167 | - int pg_state, pe_state; | |
| 168 | - | |
| 169 | -#ifdef DEBUG_MMU | |
| 170 | - printf("CR0 update: CR0=0x%08x\n", env->cr[0]); | |
| 171 | -#endif | |
| 172 | - pg_state = env->cr[0] & CR0_PG_MASK; | |
| 173 | - if (pg_state != last_pg_state) { | |
| 174 | - page_unmap(); | |
| 175 | - tlb_flush(env); | |
| 176 | - last_pg_state = pg_state; | |
| 177 | - } | |
| 178 | - pe_state = env->cr[0] & CR0_PE_MASK; | |
| 179 | - if (last_pe_state != pe_state) { | |
| 180 | - tb_flush(); | |
| 181 | - last_pe_state = pe_state; | |
| 182 | - } | |
| 183 | -} | |
| 184 | - | |
| 185 | -void cpu_x86_update_cr3(CPUX86State *env) | |
| 186 | -{ | |
| 187 | - if (env->cr[0] & CR0_PG_MASK) { | |
| 188 | -#if defined(DEBUG_MMU) | |
| 189 | - printf("CR3 update: CR3=%08x\n", env->cr[3]); | |
| 190 | -#endif | |
| 191 | - page_unmap(); | |
| 192 | - tlb_flush(env); | |
| 193 | - } | |
| 194 | -} | |
| 195 | - | |
| 196 | -void cpu_x86_init_mmu(CPUX86State *env) | |
| 197 | -{ | |
| 198 | - last_pg_state = -1; | |
| 199 | - cpu_x86_update_cr0(env); | |
| 200 | -} | |
| 201 | - | |
| 202 | -/* XXX: also flush 4MB pages */ | |
| 203 | -void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr) | |
| 204 | -{ | |
| 205 | - int flags; | |
| 206 | - unsigned long virt_addr; | |
| 207 | - | |
| 208 | - tlb_flush_page(env, addr); | |
| 209 | - | |
| 210 | - flags = page_get_flags(addr); | |
| 211 | - if (flags & PAGE_VALID) { | |
| 212 | - virt_addr = addr & ~0xfff; | |
| 213 | - munmap((void *)virt_addr, 4096); | |
| 214 | - page_set_flags(virt_addr, virt_addr + 4096, 0); | |
| 215 | - } | |
| 216 | -} | |
| 217 | - | |
| 218 | -/* return value: | |
| 219 | - -1 = cannot handle fault | |
| 220 | - 0 = nothing more to do | |
| 221 | - 1 = generate PF fault | |
| 222 | - 2 = soft MMU activation required for this block | |
| 223 | -*/ | |
| 224 | -int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write) | |
| 225 | -{ | |
| 226 | - uint8_t *pde_ptr, *pte_ptr; | |
| 227 | - uint32_t pde, pte, virt_addr; | |
| 228 | - int cpl, error_code, is_dirty, is_user, prot, page_size, ret; | |
| 229 | - unsigned long pd; | |
| 230 | - | |
| 231 | - cpl = env->hflags & HF_CPL_MASK; | |
| 232 | - is_user = (cpl == 3); | |
| 233 | - | |
| 234 | -#ifdef DEBUG_MMU | |
| 235 | - printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n", | |
| 236 | - addr, is_write, is_user, env->eip); | |
| 237 | -#endif | |
| 238 | - | |
| 239 | - if (env->user_mode_only) { | |
| 240 | - /* user mode only emulation */ | |
| 241 | - error_code = 0; | |
| 242 | - goto do_fault; | |
| 243 | - } | |
| 244 | - | |
| 245 | - if (!(env->cr[0] & CR0_PG_MASK)) { | |
| 246 | - pte = addr; | |
| 247 | - virt_addr = addr & ~0xfff; | |
| 248 | - prot = PROT_READ | PROT_WRITE; | |
| 249 | - page_size = 4096; | |
| 250 | - goto do_mapping; | |
| 251 | - } | |
| 252 | - | |
| 253 | - /* page directory entry */ | |
| 254 | - pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)); | |
| 255 | - pde = ldl(pde_ptr); | |
| 256 | - if (!(pde & PG_PRESENT_MASK)) { | |
| 257 | - error_code = 0; | |
| 258 | - goto do_fault; | |
| 259 | - } | |
| 260 | - if (is_user) { | |
| 261 | - if (!(pde & PG_USER_MASK)) | |
| 262 | - goto do_fault_protect; | |
| 263 | - if (is_write && !(pde & PG_RW_MASK)) | |
| 264 | - goto do_fault_protect; | |
| 265 | - } else { | |
| 266 | - if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) && | |
| 267 | - is_write && !(pde & PG_RW_MASK)) | |
| 268 | - goto do_fault_protect; | |
| 269 | - } | |
| 270 | - /* if PSE bit is set, then we use a 4MB page */ | |
| 271 | - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { | |
| 272 | - is_dirty = is_write && !(pde & PG_DIRTY_MASK); | |
| 273 | - if (!(pde & PG_ACCESSED_MASK)) { | |
| 274 | - pde |= PG_ACCESSED_MASK; | |
| 275 | - if (is_dirty) | |
| 276 | - pde |= PG_DIRTY_MASK; | |
| 277 | - stl(pde_ptr, pde); | |
| 278 | - } | |
| 279 | - | |
| 280 | - pte = pde & ~0x003ff000; /* align to 4MB */ | |
| 281 | - page_size = 4096 * 1024; | |
| 282 | - virt_addr = addr & ~0x003fffff; | |
| 283 | - } else { | |
| 284 | - if (!(pde & PG_ACCESSED_MASK)) { | |
| 285 | - pde |= PG_ACCESSED_MASK; | |
| 286 | - stl(pde_ptr, pde); | |
| 287 | - } | |
| 288 | - | |
| 289 | - /* page directory entry */ | |
| 290 | - pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc)); | |
| 291 | - pte = ldl(pte_ptr); | |
| 292 | - if (!(pte & PG_PRESENT_MASK)) { | |
| 293 | - error_code = 0; | |
| 294 | - goto do_fault; | |
| 295 | - } | |
| 296 | - if (is_user) { | |
| 297 | - if (!(pte & PG_USER_MASK)) | |
| 298 | - goto do_fault_protect; | |
| 299 | - if (is_write && !(pte & PG_RW_MASK)) | |
| 300 | - goto do_fault_protect; | |
| 301 | - } else { | |
| 302 | - if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) && | |
| 303 | - is_write && !(pte & PG_RW_MASK)) | |
| 304 | - goto do_fault_protect; | |
| 305 | - } | |
| 306 | - is_dirty = is_write && !(pte & PG_DIRTY_MASK); | |
| 307 | - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { | |
| 308 | - pte |= PG_ACCESSED_MASK; | |
| 309 | - if (is_dirty) | |
| 310 | - pte |= PG_DIRTY_MASK; | |
| 311 | - stl(pte_ptr, pte); | |
| 312 | - } | |
| 313 | - page_size = 4096; | |
| 314 | - virt_addr = addr & ~0xfff; | |
| 315 | - } | |
| 316 | - /* the page can be put in the TLB */ | |
| 317 | - prot = PROT_READ; | |
| 318 | - if (is_user) { | |
| 319 | - if (pte & PG_RW_MASK) | |
| 320 | - prot |= PROT_WRITE; | |
| 321 | - } else { | |
| 322 | - if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) || | |
| 323 | - (pte & PG_RW_MASK)) | |
| 324 | - prot |= PROT_WRITE; | |
| 325 | - } | |
| 326 | - | |
| 327 | - do_mapping: | |
| 328 | - if (env->hflags & HF_SOFTMMU_MASK) { | |
| 329 | - unsigned long paddr, vaddr, address, addend, page_offset; | |
| 330 | - int index; | |
| 331 | - | |
| 332 | - /* software MMU case. Even if 4MB pages, we map only one 4KB | |
| 333 | - page in the cache to avoid filling it too fast */ | |
| 334 | - page_offset = (addr & ~0xfff) & (page_size - 1); | |
| 335 | - paddr = (pte & ~0xfff) + page_offset; | |
| 336 | - vaddr = virt_addr + page_offset; | |
| 337 | - index = (addr >> 12) & (CPU_TLB_SIZE - 1); | |
| 338 | - pd = physpage_find(paddr); | |
| 339 | - if (pd & 0xfff) { | |
| 340 | - /* IO memory case */ | |
| 341 | - address = vaddr | pd; | |
| 342 | - addend = paddr; | |
| 343 | - } else { | |
| 344 | - /* standard memory */ | |
| 345 | - address = vaddr; | |
| 346 | - addend = (unsigned long)phys_ram_base + pd; | |
| 347 | - } | |
| 348 | - addend -= vaddr; | |
| 349 | - env->tlb_read[is_user][index].address = address; | |
| 350 | - env->tlb_read[is_user][index].addend = addend; | |
| 351 | - if (prot & PROT_WRITE) { | |
| 352 | - env->tlb_write[is_user][index].address = address; | |
| 353 | - env->tlb_write[is_user][index].addend = addend; | |
| 354 | - } | |
| 355 | - } | |
| 356 | - ret = 0; | |
| 357 | - /* XXX: incorrect for 4MB pages */ | |
| 358 | - pd = physpage_find(pte & ~0xfff); | |
| 359 | - if ((pd & 0xfff) != 0) { | |
| 360 | - /* IO access: no mapping is done as it will be handled by the | |
| 361 | - soft MMU */ | |
| 362 | - if (!(env->hflags & HF_SOFTMMU_MASK)) | |
| 363 | - ret = 2; | |
| 364 | - } else { | |
| 365 | - void *map_addr; | |
| 366 | - map_addr = mmap((void *)virt_addr, page_size, prot, | |
| 367 | - MAP_SHARED | MAP_FIXED, phys_ram_fd, pd); | |
| 368 | - if (map_addr == MAP_FAILED) { | |
| 369 | - fprintf(stderr, | |
| 370 | - "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n", | |
| 371 | - pte & ~0xfff, virt_addr); | |
| 372 | - exit(1); | |
| 373 | - } | |
| 374 | -#ifdef DEBUG_MMU | |
| 375 | - printf("mmaping 0x%08x to virt 0x%08x pse=%d\n", | |
| 376 | - pte & ~0xfff, virt_addr, (page_size != 4096)); | |
| 377 | -#endif | |
| 378 | - page_set_flags(virt_addr, virt_addr + page_size, | |
| 379 | - PAGE_VALID | PAGE_EXEC | prot); | |
| 380 | - } | |
| 381 | - return ret; | |
| 382 | - do_fault_protect: | |
| 383 | - error_code = PG_ERROR_P_MASK; | |
| 384 | - do_fault: | |
| 385 | - env->cr[2] = addr; | |
| 386 | - env->error_code = (is_write << PG_ERROR_W_BIT) | error_code; | |
| 387 | - if (is_user) | |
| 388 | - env->error_code |= PG_ERROR_U_MASK; | |
| 389 | - return 1; | |
| 390 | -} |
op-arm-template.h deleted
100644 → 0
| 1 | -/* | |
| 2 | - * ARM micro operations (templates for various register related | |
| 3 | - * operations) | |
| 4 | - * | |
| 5 | - * Copyright (c) 2003 Fabrice Bellard | |
| 6 | - * | |
| 7 | - * This library is free software; you can redistribute it and/or | |
| 8 | - * modify it under the terms of the GNU Lesser General Public | |
| 9 | - * License as published by the Free Software Foundation; either | |
| 10 | - * version 2 of the License, or (at your option) any later version. | |
| 11 | - * | |
| 12 | - * This library is distributed in the hope that it will be useful, | |
| 13 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 14 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 15 | - * Lesser General Public License for more details. | |
| 16 | - * | |
| 17 | - * You should have received a copy of the GNU Lesser General Public | |
| 18 | - * License along with this library; if not, write to the Free Software | |
| 19 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 20 | - */ | |
| 21 | - | |
| 22 | -void OPPROTO glue(op_movl_T0_, REGNAME)(void) | |
| 23 | -{ | |
| 24 | - T0 = REG; | |
| 25 | -} | |
| 26 | - | |
| 27 | -void OPPROTO glue(op_movl_T1_, REGNAME)(void) | |
| 28 | -{ | |
| 29 | - T1 = REG; | |
| 30 | -} | |
| 31 | - | |
| 32 | -void OPPROTO glue(op_movl_T2_, REGNAME)(void) | |
| 33 | -{ | |
| 34 | - T2 = REG; | |
| 35 | -} | |
| 36 | - | |
| 37 | -void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) | |
| 38 | -{ | |
| 39 | - REG = T0; | |
| 40 | -} | |
| 41 | - | |
| 42 | -void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) | |
| 43 | -{ | |
| 44 | - REG = T1; | |
| 45 | -} | |
| 46 | - | |
| 47 | -#undef REG | |
| 48 | -#undef REGNAME |
op-arm.c deleted
100644 → 0
| 1 | -/* | |
| 2 | - * ARM micro operations | |
| 3 | - * | |
| 4 | - * Copyright (c) 2003 Fabrice Bellard | |
| 5 | - * | |
| 6 | - * This library is free software; you can redistribute it and/or | |
| 7 | - * modify it under the terms of the GNU Lesser General Public | |
| 8 | - * License as published by the Free Software Foundation; either | |
| 9 | - * version 2 of the License, or (at your option) any later version. | |
| 10 | - * | |
| 11 | - * This library is distributed in the hope that it will be useful, | |
| 12 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| 14 | - * Lesser General Public License for more details. | |
| 15 | - * | |
| 16 | - * You should have received a copy of the GNU Lesser General Public | |
| 17 | - * License along with this library; if not, write to the Free Software | |
| 18 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| 19 | - */ | |
| 20 | -#include "exec-arm.h" | |
| 21 | - | |
| 22 | -#define REGNAME r0 | |
| 23 | -#define REG (env->regs[0]) | |
| 24 | -#include "op-arm-template.h" | |
| 25 | - | |
| 26 | -#define REGNAME r1 | |
| 27 | -#define REG (env->regs[1]) | |
| 28 | -#include "op-arm-template.h" | |
| 29 | - | |
| 30 | -#define REGNAME r2 | |
| 31 | -#define REG (env->regs[2]) | |
| 32 | -#include "op-arm-template.h" | |
| 33 | - | |
| 34 | -#define REGNAME r3 | |
| 35 | -#define REG (env->regs[3]) | |
| 36 | -#include "op-arm-template.h" | |
| 37 | - | |
| 38 | -#define REGNAME r4 | |
| 39 | -#define REG (env->regs[4]) | |
| 40 | -#include "op-arm-template.h" | |
| 41 | - | |
| 42 | -#define REGNAME r5 | |
| 43 | -#define REG (env->regs[5]) | |
| 44 | -#include "op-arm-template.h" | |
| 45 | - | |
| 46 | -#define REGNAME r6 | |
| 47 | -#define REG (env->regs[6]) | |
| 48 | -#include "op-arm-template.h" | |
| 49 | - | |
| 50 | -#define REGNAME r7 | |
| 51 | -#define REG (env->regs[7]) | |
| 52 | -#include "op-arm-template.h" | |
| 53 | - | |
| 54 | -#define REGNAME r8 | |
| 55 | -#define REG (env->regs[8]) | |
| 56 | -#include "op-arm-template.h" | |
| 57 | - | |
| 58 | -#define REGNAME r9 | |
| 59 | -#define REG (env->regs[9]) | |
| 60 | -#include "op-arm-template.h" | |
| 61 | - | |
| 62 | -#define REGNAME r10 | |
| 63 | -#define REG (env->regs[10]) | |
| 64 | -#include "op-arm-template.h" | |
| 65 | - | |
| 66 | -#define REGNAME r11 | |
| 67 | -#define REG (env->regs[11]) | |
| 68 | -#include "op-arm-template.h" | |
| 69 | - | |
| 70 | -#define REGNAME r12 | |
| 71 | -#define REG (env->regs[12]) | |
| 72 | -#include "op-arm-template.h" | |
| 73 | - | |
| 74 | -#define REGNAME r13 | |
| 75 | -#define REG (env->regs[13]) | |
| 76 | -#include "op-arm-template.h" | |
| 77 | - | |
| 78 | -#define REGNAME r14 | |
| 79 | -#define REG (env->regs[14]) | |
| 80 | -#include "op-arm-template.h" | |
| 81 | - | |
| 82 | -#define REGNAME r15 | |
| 83 | -#define REG (env->regs[15]) | |
| 84 | -#include "op-arm-template.h" | |
| 85 | - | |
| 86 | -void OPPROTO op_movl_T0_0(void) | |
| 87 | -{ | |
| 88 | - T0 = 0; | |
| 89 | -} | |
| 90 | - | |
| 91 | -void OPPROTO op_movl_T0_im(void) | |
| 92 | -{ | |
| 93 | - T0 = PARAM1; | |
| 94 | -} | |
| 95 | - | |
| 96 | -void OPPROTO op_movl_T1_im(void) | |
| 97 | -{ | |
| 98 | - T1 = PARAM1; | |
| 99 | -} | |
| 100 | - | |
| 101 | -void OPPROTO op_movl_T2_im(void) | |
| 102 | -{ | |
| 103 | - T2 = PARAM1; | |
| 104 | -} | |
| 105 | - | |
| 106 | -void OPPROTO op_addl_T1_im(void) | |
| 107 | -{ | |
| 108 | - T1 += PARAM1; | |
| 109 | -} | |
| 110 | - | |
| 111 | -void OPPROTO op_addl_T1_T2(void) | |
| 112 | -{ | |
| 113 | - T1 += T2; | |
| 114 | -} | |
| 115 | - | |
| 116 | -void OPPROTO op_subl_T1_T2(void) | |
| 117 | -{ | |
| 118 | - T1 -= T2; | |
| 119 | -} | |
| 120 | - | |
| 121 | -void OPPROTO op_addl_T0_T1(void) | |
| 122 | -{ | |
| 123 | - T0 += T1; | |
| 124 | -} | |
| 125 | - | |
| 126 | -void OPPROTO op_addl_T0_T1_cc(void) | |
| 127 | -{ | |
| 128 | - unsigned int src1; | |
| 129 | - src1 = T0; | |
| 130 | - T0 += T1; | |
| 131 | - env->NZF = T0; | |
| 132 | - env->CF = T0 < src1; | |
| 133 | - env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); | |
| 134 | -} | |
| 135 | - | |
| 136 | -void OPPROTO op_adcl_T0_T1(void) | |
| 137 | -{ | |
| 138 | - T0 += T1 + env->CF; | |
| 139 | -} | |
| 140 | - | |
| 141 | -void OPPROTO op_adcl_T0_T1_cc(void) | |
| 142 | -{ | |
| 143 | - unsigned int src1; | |
| 144 | - src1 = T0; | |
| 145 | - if (!env->CF) { | |
| 146 | - T0 += T1; | |
| 147 | - env->CF = T0 < src1; | |
| 148 | - } else { | |
| 149 | - T0 += T1 + 1; | |
| 150 | - env->CF = T0 <= src1; | |
| 151 | - } | |
| 152 | - env->VF = (src1 ^ T1 ^ -1) & (src1 ^ T0); | |
| 153 | - env->NZF = T0; | |
| 154 | - FORCE_RET(); | |
| 155 | -} | |
| 156 | - | |
| 157 | -#define OPSUB(sub, sbc, res, T0, T1) \ | |
| 158 | - \ | |
| 159 | -void OPPROTO op_ ## sub ## l_T0_T1(void) \ | |
| 160 | -{ \ | |
| 161 | - res = T0 - T1; \ | |
| 162 | -} \ | |
| 163 | - \ | |
| 164 | -void OPPROTO op_ ## sub ## l_T0_T1_cc(void) \ | |
| 165 | -{ \ | |
| 166 | - unsigned int src1; \ | |
| 167 | - src1 = T0; \ | |
| 168 | - T0 -= T1; \ | |
| 169 | - env->NZF = T0; \ | |
| 170 | - env->CF = src1 >= T1; \ | |
| 171 | - env->VF = (src1 ^ T1) & (src1 ^ T0); \ | |
| 172 | - res = T0; \ | |
| 173 | -} \ | |
| 174 | - \ | |
| 175 | -void OPPROTO op_ ## sbc ## l_T0_T1(void) \ | |
| 176 | -{ \ | |
| 177 | - res = T0 - T1 + env->CF - 1; \ | |
| 178 | -} \ | |
| 179 | - \ | |
| 180 | -void OPPROTO op_ ## sbc ## l_T0_T1_cc(void) \ | |
| 181 | -{ \ | |
| 182 | - unsigned int src1; \ | |
| 183 | - src1 = T0; \ | |
| 184 | - if (!env->CF) { \ | |
| 185 | - T0 = T0 - T1 - 1; \ | |
| 186 | - env->CF = src1 >= T1; \ | |
| 187 | - } else { \ | |
| 188 | - T0 = T0 - T1; \ | |
| 189 | - env->CF = src1 > T1; \ | |
| 190 | - } \ | |
| 191 | - env->VF = (src1 ^ T1) & (src1 ^ T0); \ | |
| 192 | - env->NZF = T0; \ | |
| 193 | - res = T0; \ | |
| 194 | - FORCE_RET(); \ | |
| 195 | -} | |
| 196 | - | |
| 197 | -OPSUB(sub, sbc, T0, T0, T1) | |
| 198 | - | |
| 199 | -OPSUB(rsb, rsc, T0, T1, T0) | |
| 200 | - | |
| 201 | -void OPPROTO op_andl_T0_T1(void) | |
| 202 | -{ | |
| 203 | - T0 &= T1; | |
| 204 | -} | |
| 205 | - | |
| 206 | -void OPPROTO op_xorl_T0_T1(void) | |
| 207 | -{ | |
| 208 | - T0 ^= T1; | |
| 209 | -} | |
| 210 | - | |
| 211 | -void OPPROTO op_orl_T0_T1(void) | |
| 212 | -{ | |
| 213 | - T0 |= T1; | |
| 214 | -} | |
| 215 | - | |
| 216 | -void OPPROTO op_bicl_T0_T1(void) | |
| 217 | -{ | |
| 218 | - T0 &= ~T1; | |
| 219 | -} | |
| 220 | - | |
| 221 | -void OPPROTO op_notl_T1(void) | |
| 222 | -{ | |
| 223 | - T1 = ~T1; | |
| 224 | -} | |
| 225 | - | |
| 226 | -void OPPROTO op_logic_T0_cc(void) | |
| 227 | -{ | |
| 228 | - env->NZF = T0; | |
| 229 | -} | |
| 230 | - | |
| 231 | -void OPPROTO op_logic_T1_cc(void) | |
| 232 | -{ | |
| 233 | - env->NZF = T1; | |
| 234 | -} | |
| 235 | - | |
| 236 | -#define EIP (env->regs[15]) | |
| 237 | - | |
| 238 | -void OPPROTO op_test_eq(void) | |
| 239 | -{ | |
| 240 | - if (env->NZF == 0) | |
| 241 | - JUMP_TB(op_test_eq, PARAM1, 0, PARAM2); | |
| 242 | - FORCE_RET(); | |
| 243 | -} | |
| 244 | - | |
| 245 | -void OPPROTO op_test_ne(void) | |
| 246 | -{ | |
| 247 | - if (env->NZF != 0) | |
| 248 | - JUMP_TB(op_test_ne, PARAM1, 0, PARAM2); | |
| 249 | - FORCE_RET(); | |
| 250 | -} | |
| 251 | - | |
| 252 | -void OPPROTO op_test_cs(void) | |
| 253 | -{ | |
| 254 | - if (env->CF != 0) | |
| 255 | - JUMP_TB(op_test_cs, PARAM1, 0, PARAM2); | |
| 256 | - FORCE_RET(); | |
| 257 | -} | |
| 258 | - | |
| 259 | -void OPPROTO op_test_cc(void) | |
| 260 | -{ | |
| 261 | - if (env->CF == 0) | |
| 262 | - JUMP_TB(op_test_cc, PARAM1, 0, PARAM2); | |
| 263 | - FORCE_RET(); | |
| 264 | -} | |
| 265 | - | |
| 266 | -void OPPROTO op_test_mi(void) | |
| 267 | -{ | |
| 268 | - if ((env->NZF & 0x80000000) != 0) | |
| 269 | - JUMP_TB(op_test_mi, PARAM1, 0, PARAM2); | |
| 270 | - FORCE_RET(); | |
| 271 | -} | |
| 272 | - | |
| 273 | -void OPPROTO op_test_pl(void) | |
| 274 | -{ | |
| 275 | - if ((env->NZF & 0x80000000) == 0) | |
| 276 | - JUMP_TB(op_test_pl, PARAM1, 0, PARAM2); | |
| 277 | - FORCE_RET(); | |
| 278 | -} | |
| 279 | - | |
| 280 | -void OPPROTO op_test_vs(void) | |
| 281 | -{ | |
| 282 | - if ((env->VF & 0x80000000) != 0) | |
| 283 | - JUMP_TB(op_test_vs, PARAM1, 0, PARAM2); | |
| 284 | - FORCE_RET(); | |
| 285 | -} | |
| 286 | - | |
| 287 | -void OPPROTO op_test_vc(void) | |
| 288 | -{ | |
| 289 | - if ((env->VF & 0x80000000) == 0) | |
| 290 | - JUMP_TB(op_test_vc, PARAM1, 0, PARAM2); | |
| 291 | - FORCE_RET(); | |
| 292 | -} | |
| 293 | - | |
| 294 | -void OPPROTO op_test_hi(void) | |
| 295 | -{ | |
| 296 | - if (env->CF != 0 && env->NZF != 0) | |
| 297 | - JUMP_TB(op_test_hi, PARAM1, 0, PARAM2); | |
| 298 | - FORCE_RET(); | |
| 299 | -} | |
| 300 | - | |
| 301 | -void OPPROTO op_test_ls(void) | |
| 302 | -{ | |
| 303 | - if (env->CF == 0 || env->NZF == 0) | |
| 304 | - JUMP_TB(op_test_ls, PARAM1, 0, PARAM2); | |
| 305 | - FORCE_RET(); | |
| 306 | -} | |
| 307 | - | |
| 308 | -void OPPROTO op_test_ge(void) | |
| 309 | -{ | |
| 310 | - if (((env->VF ^ env->NZF) & 0x80000000) == 0) | |
| 311 | - JUMP_TB(op_test_ge, PARAM1, 0, PARAM2); | |
| 312 | - FORCE_RET(); | |
| 313 | -} | |
| 314 | - | |
| 315 | -void OPPROTO op_test_lt(void) | |
| 316 | -{ | |
| 317 | - if (((env->VF ^ env->NZF) & 0x80000000) != 0) | |
| 318 | - JUMP_TB(op_test_lt, PARAM1, 0, PARAM2); | |
| 319 | - FORCE_RET(); | |
| 320 | -} | |
| 321 | - | |
| 322 | -void OPPROTO op_test_gt(void) | |
| 323 | -{ | |
| 324 | - if (env->NZF != 0 && ((env->VF ^ env->NZF) & 0x80000000) == 0) | |
| 325 | - JUMP_TB(op_test_gt, PARAM1, 0, PARAM2); | |
| 326 | - FORCE_RET(); | |
| 327 | -} | |
| 328 | - | |
| 329 | -void OPPROTO op_test_le(void) | |
| 330 | -{ | |
| 331 | - if (env->NZF == 0 || ((env->VF ^ env->NZF) & 0x80000000) != 0) | |
| 332 | - JUMP_TB(op_test_le, PARAM1, 0, PARAM2); | |
| 333 | - FORCE_RET(); | |
| 334 | -} | |
| 335 | - | |
| 336 | -void OPPROTO op_jmp(void) | |
| 337 | -{ | |
| 338 | - JUMP_TB(op_jmp, PARAM1, 1, PARAM2); | |
| 339 | -} | |
| 340 | - | |
| 341 | -void OPPROTO op_exit_tb(void) | |
| 342 | -{ | |
| 343 | - EXIT_TB(); | |
| 344 | -} | |
| 345 | - | |
| 346 | -void OPPROTO op_movl_T0_psr(void) | |
| 347 | -{ | |
| 348 | - T0 = compute_cpsr(); | |
| 349 | -} | |
| 350 | - | |
| 351 | -/* NOTE: N = 1 and Z = 1 cannot be stored currently */ | |
| 352 | -void OPPROTO op_movl_psr_T0(void) | |
| 353 | -{ | |
| 354 | - unsigned int psr; | |
| 355 | - psr = T0; | |
| 356 | - env->CF = (psr >> 29) & 1; | |
| 357 | - env->NZF = (psr & 0xc0000000) ^ 0x40000000; | |
| 358 | - env->VF = (psr << 3) & 0x80000000; | |
| 359 | - /* for user mode we do not update other state info */ | |
| 360 | -} | |
| 361 | - | |
| 362 | -void OPPROTO op_mul_T0_T1(void) | |
| 363 | -{ | |
| 364 | - T0 = T0 * T1; | |
| 365 | -} | |
| 366 | - | |
| 367 | -/* 64 bit unsigned mul */ | |
| 368 | -void OPPROTO op_mull_T0_T1(void) | |
| 369 | -{ | |
| 370 | - uint64_t res; | |
| 371 | - res = T0 * T1; | |
| 372 | - T1 = res >> 32; | |
| 373 | - T0 = res; | |
| 374 | -} | |
| 375 | - | |
| 376 | -/* 64 bit signed mul */ | |
| 377 | -void OPPROTO op_imull_T0_T1(void) | |
| 378 | -{ | |
| 379 | - uint64_t res; | |
| 380 | - res = (int32_t)T0 * (int32_t)T1; | |
| 381 | - T1 = res >> 32; | |
| 382 | - T0 = res; | |
| 383 | -} | |
| 384 | - | |
| 385 | -void OPPROTO op_addq_T0_T1(void) | |
| 386 | -{ | |
| 387 | - uint64_t res; | |
| 388 | - res = ((uint64_t)T1 << 32) | T0; | |
| 389 | - res += ((uint64_t)(env->regs[PARAM2]) << 32) | (env->regs[PARAM1]); | |
| 390 | - T1 = res >> 32; | |
| 391 | - T0 = res; | |
| 392 | -} | |
| 393 | - | |
| 394 | -void OPPROTO op_logicq_cc(void) | |
| 395 | -{ | |
| 396 | - env->NZF = (T1 & 0x80000000) | ((T0 | T1) != 0); | |
| 397 | -} | |
| 398 | - | |
| 399 | -/* memory access */ | |
| 400 | - | |
| 401 | -void OPPROTO op_ldub_T0_T1(void) | |
| 402 | -{ | |
| 403 | - T0 = ldub((void *)T1); | |
| 404 | -} | |
| 405 | - | |
| 406 | -void OPPROTO op_ldsb_T0_T1(void) | |
| 407 | -{ | |
| 408 | - T0 = ldsb((void *)T1); | |
| 409 | -} | |
| 410 | - | |
| 411 | -void OPPROTO op_lduw_T0_T1(void) | |
| 412 | -{ | |
| 413 | - T0 = lduw((void *)T1); | |
| 414 | -} | |
| 415 | - | |
| 416 | -void OPPROTO op_ldsw_T0_T1(void) | |
| 417 | -{ | |
| 418 | - T0 = ldsw((void *)T1); | |
| 419 | -} | |
| 420 | - | |
| 421 | -void OPPROTO op_ldl_T0_T1(void) | |
| 422 | -{ | |
| 423 | - T0 = ldl((void *)T1); | |
| 424 | -} | |
| 425 | - | |
| 426 | -void OPPROTO op_stb_T0_T1(void) | |
| 427 | -{ | |
| 428 | - stb((void *)T1, T0); | |
| 429 | -} | |
| 430 | - | |
| 431 | -void OPPROTO op_stw_T0_T1(void) | |
| 432 | -{ | |
| 433 | - stw((void *)T1, T0); | |
| 434 | -} | |
| 435 | - | |
| 436 | -void OPPROTO op_stl_T0_T1(void) | |
| 437 | -{ | |
| 438 | - stl((void *)T1, T0); | |
| 439 | -} | |
| 440 | - | |
| 441 | -void OPPROTO op_swpb_T0_T1(void) | |
| 442 | -{ | |
| 443 | - int tmp; | |
| 444 | - | |
| 445 | - cpu_lock(); | |
| 446 | - tmp = ldub((void *)T1); | |
| 447 | - stb((void *)T1, T0); | |
| 448 | - T0 = tmp; | |
| 449 | - cpu_unlock(); | |
| 450 | -} | |
| 451 | - | |
| 452 | -void OPPROTO op_swpl_T0_T1(void) | |
| 453 | -{ | |
| 454 | - int tmp; | |
| 455 | - | |
| 456 | - cpu_lock(); | |
| 457 | - tmp = ldl((void *)T1); | |
| 458 | - stl((void *)T1, T0); | |
| 459 | - T0 = tmp; | |
| 460 | - cpu_unlock(); | |
| 461 | -} | |
| 462 | - | |
| 463 | -/* shifts */ | |
| 464 | - | |
| 465 | -/* T1 based */ | |
| 466 | -void OPPROTO op_shll_T1_im(void) | |
| 467 | -{ | |
| 468 | - T1 = T1 << PARAM1; | |
| 469 | -} | |
| 470 | - | |
| 471 | -void OPPROTO op_shrl_T1_im(void) | |
| 472 | -{ | |
| 473 | - T1 = (uint32_t)T1 >> PARAM1; | |
| 474 | -} | |
| 475 | - | |
| 476 | -void OPPROTO op_sarl_T1_im(void) | |
| 477 | -{ | |
| 478 | - T1 = (int32_t)T1 >> PARAM1; | |
| 479 | -} | |
| 480 | - | |
| 481 | -void OPPROTO op_rorl_T1_im(void) | |
| 482 | -{ | |
| 483 | - int shift; | |
| 484 | - shift = PARAM1; | |
| 485 | - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
| 486 | -} | |
| 487 | - | |
| 488 | -/* T1 based, set C flag */ | |
| 489 | -void OPPROTO op_shll_T1_im_cc(void) | |
| 490 | -{ | |
| 491 | - env->CF = (T1 >> (32 - PARAM1)) & 1; | |
| 492 | - T1 = T1 << PARAM1; | |
| 493 | -} | |
| 494 | - | |
| 495 | -void OPPROTO op_shrl_T1_im_cc(void) | |
| 496 | -{ | |
| 497 | - env->CF = (T1 >> (PARAM1 - 1)) & 1; | |
| 498 | - T1 = (uint32_t)T1 >> PARAM1; | |
| 499 | -} | |
| 500 | - | |
| 501 | -void OPPROTO op_sarl_T1_im_cc(void) | |
| 502 | -{ | |
| 503 | - env->CF = (T1 >> (PARAM1 - 1)) & 1; | |
| 504 | - T1 = (int32_t)T1 >> PARAM1; | |
| 505 | -} | |
| 506 | - | |
| 507 | -void OPPROTO op_rorl_T1_im_cc(void) | |
| 508 | -{ | |
| 509 | - int shift; | |
| 510 | - shift = PARAM1; | |
| 511 | - env->CF = (T1 >> (shift - 1)) & 1; | |
| 512 | - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
| 513 | -} | |
| 514 | - | |
| 515 | -/* T2 based */ | |
| 516 | -void OPPROTO op_shll_T2_im(void) | |
| 517 | -{ | |
| 518 | - T2 = T2 << PARAM1; | |
| 519 | -} | |
| 520 | - | |
| 521 | -void OPPROTO op_shrl_T2_im(void) | |
| 522 | -{ | |
| 523 | - T2 = (uint32_t)T2 >> PARAM1; | |
| 524 | -} | |
| 525 | - | |
| 526 | -void OPPROTO op_sarl_T2_im(void) | |
| 527 | -{ | |
| 528 | - T2 = (int32_t)T2 >> PARAM1; | |
| 529 | -} | |
| 530 | - | |
| 531 | -void OPPROTO op_rorl_T2_im(void) | |
| 532 | -{ | |
| 533 | - int shift; | |
| 534 | - shift = PARAM1; | |
| 535 | - T2 = ((uint32_t)T2 >> shift) | (T2 << (32 - shift)); | |
| 536 | -} | |
| 537 | - | |
| 538 | -/* T1 based, use T0 as shift count */ | |
| 539 | - | |
| 540 | -void OPPROTO op_shll_T1_T0(void) | |
| 541 | -{ | |
| 542 | - int shift; | |
| 543 | - shift = T0 & 0xff; | |
| 544 | - if (shift >= 32) | |
| 545 | - T1 = 0; | |
| 546 | - else | |
| 547 | - T1 = T1 << shift; | |
| 548 | - FORCE_RET(); | |
| 549 | -} | |
| 550 | - | |
| 551 | -void OPPROTO op_shrl_T1_T0(void) | |
| 552 | -{ | |
| 553 | - int shift; | |
| 554 | - shift = T0 & 0xff; | |
| 555 | - if (shift >= 32) | |
| 556 | - T1 = 0; | |
| 557 | - else | |
| 558 | - T1 = (uint32_t)T1 >> shift; | |
| 559 | - FORCE_RET(); | |
| 560 | -} | |
| 561 | - | |
| 562 | -void OPPROTO op_sarl_T1_T0(void) | |
| 563 | -{ | |
| 564 | - int shift; | |
| 565 | - shift = T0 & 0xff; | |
| 566 | - if (shift >= 32) | |
| 567 | - shift = 31; | |
| 568 | - T1 = (int32_t)T1 >> shift; | |
| 569 | -} | |
| 570 | - | |
| 571 | -void OPPROTO op_rorl_T1_T0(void) | |
| 572 | -{ | |
| 573 | - int shift; | |
| 574 | - shift = T0 & 0x1f; | |
| 575 | - if (shift) { | |
| 576 | - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
| 577 | - } | |
| 578 | - FORCE_RET(); | |
| 579 | -} | |
| 580 | - | |
| 581 | -/* T1 based, use T0 as shift count and compute CF */ | |
| 582 | - | |
| 583 | -void OPPROTO op_shll_T1_T0_cc(void) | |
| 584 | -{ | |
| 585 | - int shift; | |
| 586 | - shift = T0 & 0xff; | |
| 587 | - if (shift >= 32) { | |
| 588 | - if (shift == 32) | |
| 589 | - env->CF = T1 & 1; | |
| 590 | - else | |
| 591 | - env->CF = 0; | |
| 592 | - T1 = 0; | |
| 593 | - } else if (shift != 0) { | |
| 594 | - env->CF = (T1 >> (32 - shift)) & 1; | |
| 595 | - T1 = T1 << shift; | |
| 596 | - } | |
| 597 | - FORCE_RET(); | |
| 598 | -} | |
| 599 | - | |
| 600 | -void OPPROTO op_shrl_T1_T0_cc(void) | |
| 601 | -{ | |
| 602 | - int shift; | |
| 603 | - shift = T0 & 0xff; | |
| 604 | - if (shift >= 32) { | |
| 605 | - if (shift == 32) | |
| 606 | - env->CF = (T1 >> 31) & 1; | |
| 607 | - else | |
| 608 | - env->CF = 0; | |
| 609 | - T1 = 0; | |
| 610 | - } else if (shift != 0) { | |
| 611 | - env->CF = (T1 >> (shift - 1)) & 1; | |
| 612 | - T1 = (uint32_t)T1 >> shift; | |
| 613 | - } | |
| 614 | - FORCE_RET(); | |
| 615 | -} | |
| 616 | - | |
| 617 | -void OPPROTO op_sarl_T1_T0_cc(void) | |
| 618 | -{ | |
| 619 | - int shift; | |
| 620 | - shift = T0 & 0xff; | |
| 621 | - if (shift >= 32) { | |
| 622 | - env->CF = (T1 >> 31) & 1; | |
| 623 | - T1 = (int32_t)T1 >> 31; | |
| 624 | - } else { | |
| 625 | - env->CF = (T1 >> (shift - 1)) & 1; | |
| 626 | - T1 = (int32_t)T1 >> shift; | |
| 627 | - } | |
| 628 | - FORCE_RET(); | |
| 629 | -} | |
| 630 | - | |
| 631 | -void OPPROTO op_rorl_T1_T0_cc(void) | |
| 632 | -{ | |
| 633 | - int shift1, shift; | |
| 634 | - shift1 = T0 & 0xff; | |
| 635 | - shift = shift1 & 0x1f; | |
| 636 | - if (shift == 0) { | |
| 637 | - if (shift1 != 0) | |
| 638 | - env->CF = (T1 >> 31) & 1; | |
| 639 | - } else { | |
| 640 | - env->CF = (T1 >> (shift - 1)) & 1; | |
| 641 | - T1 = ((uint32_t)T1 >> shift) | (T1 << (32 - shift)); | |
| 642 | - } | |
| 643 | - FORCE_RET(); | |
| 644 | -} | |
| 645 | - | |
| 646 | -/* exceptions */ | |
| 647 | - | |
| 648 | -void OPPROTO op_swi(void) | |
| 649 | -{ | |
| 650 | - env->exception_index = EXCP_SWI; | |
| 651 | - cpu_loop_exit(); | |
| 652 | -} | |
| 653 | - | |
| 654 | -void OPPROTO op_undef_insn(void) | |
| 655 | -{ | |
| 656 | - env->exception_index = EXCP_UDEF; | |
| 657 | - cpu_loop_exit(); | |
| 658 | -} | |
| 659 | - | |
| 660 | -/* thread support */ | |
| 661 | - | |
| 662 | -spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; | |
| 663 | - | |
| 664 | -void cpu_lock(void) | |
| 665 | -{ | |
| 666 | - spin_lock(&global_cpu_lock); | |
| 667 | -} | |
| 668 | - | |
| 669 | -void cpu_unlock(void) | |
| 670 | -{ | |
| 671 | - spin_unlock(&global_cpu_lock); | |
| 672 | -} | |
| 673 | - |