Commit 58fe2f10f0e9ddd63bc6004776ef6e874101e9c5

Authored by bellard
1 parent 3a1d9b8b

experimental code copy support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@623 c046a42c-6fe2-441c-8c8c-71466251a162
exec-all.h
... ... @@ -79,7 +79,13 @@ void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
79 79 int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
80 80 int max_code_size, int *gen_code_size_ptr);
81 81 int cpu_restore_state(struct TranslationBlock *tb,
82   - CPUState *env, unsigned long searched_pc);
  82 + CPUState *env, unsigned long searched_pc,
  83 + void *puc);
  84 +int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb,
  85 + int max_code_size, int *gen_code_size_ptr);
  86 +int cpu_restore_state_copy(struct TranslationBlock *tb,
  87 + CPUState *env, unsigned long searched_pc,
  88 + void *puc);
83 89 void cpu_exec_init(void);
84 90 int page_unprotect(unsigned long address);
85 91 void tb_invalidate_page_range(target_ulong start, target_ulong end);
... ... @@ -145,6 +151,9 @@ typedef struct TranslationBlock {
145 151 unsigned int flags; /* flags defining in which context the code was generated */
146 152 uint16_t size; /* size of target code for this block (1 <=
147 153 size <= TARGET_PAGE_SIZE) */
  154 + uint16_t cflags; /* compile flags */
  155 +#define CF_CODE_COPY 0x0001 /* block was generated in code copy mode */
  156 +
148 157 uint8_t *tc_ptr; /* pointer to the translated code */
149 158 struct TranslationBlock *hash_next; /* next matching tb for virtual address */
150 159 /* next matching tb for physical address. */
... ... @@ -552,4 +561,3 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
552 561 return addr + env->tlb_read[is_user][index].addend - (unsigned long)phys_ram_base;
553 562 }
554 563 #endif
555   -
... ...
linux-user/signal.c
... ... @@ -378,7 +378,11 @@ static void host_signal_handler(int host_signum, siginfo_t *info,
378 378  
379 379 /* the CPU emulator uses some host signals to detect exceptions,
380 380 we we forward to it some signals */
381   - if (host_signum == SIGSEGV || host_signum == SIGBUS) {
  381 + if (host_signum == SIGSEGV || host_signum == SIGBUS
  382 +#if defined(TARGET_I386) && defined(USE_CODE_COPY)
  383 + || host_signum == SIGFPE
  384 +#endif
  385 + ) {
382 386 if (cpu_signal_handler(host_signum, info, puc))
383 387 return;
384 388 }
... ...
target-i386/cpu.h
... ... @@ -24,6 +24,10 @@
24 24  
25 25 #include "cpu-defs.h"
26 26  
  27 +#if defined(__i386__) && !defined(CONFIG_SOFTMMU)
  28 +#define USE_CODE_COPY
  29 +#endif
  30 +
27 31 #define R_EAX 0
28 32 #define R_ECX 1
29 33 #define R_EDX 2
... ... @@ -121,6 +125,7 @@
121 125 #define HF_SS32_MASK (1 << HF_SS32_SHIFT)
122 126 #define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT)
123 127 #define HF_PE_MASK (1 << HF_PE_SHIFT)
  128 +#define HF_TF_MASK (1 << HF_TF_SHIFT)
124 129  
125 130 #define CR0_PE_MASK (1 << 0)
126 131 #define CR0_TS_MASK (1 << 3)
... ... @@ -297,6 +302,10 @@ typedef struct CPUX86State {
297 302 uint32_t sysenter_cs;
298 303 uint32_t sysenter_esp;
299 304 uint32_t sysenter_eip;
  305 +
  306 + /* temporary data for USE_CODE_COPY mode */
  307 + uint32_t tmp0;
  308 + uint32_t saved_esp;
300 309  
301 310 /* exception/interrupt handling */
302 311 jmp_buf jmp_env;
... ...
target-i386/helper.c
... ... @@ -869,7 +869,7 @@ void do_interrupt(int intno, int is_int, int error_code,
869 869 {
870 870 extern FILE *stdout;
871 871 static int count;
872   - if (env->cr[0] & CR0_PE_MASK) {
  872 + if (env->cr[0] & CR0_PE_MASK) {
873 873 fprintf(stdout, "%d: v=%02x e=%04x i=%d CPL=%d CS:EIP=%04x:%08x SS:ESP=%04x:%08x",
874 874 count, intno, error_code, is_int,
875 875 env->hflags & HF_CPL_MASK,
... ... @@ -2489,7 +2489,7 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr)
2489 2489 if (tb) {
2490 2490 /* the PC is inside the translated code. It means that we have
2491 2491 a virtual CPU fault */
2492   - cpu_restore_state(tb, env, pc);
  2492 + cpu_restore_state(tb, env, pc, NULL);
2493 2493 }
2494 2494 }
2495 2495 raise_exception_err(EXCP0E_PAGE, env->error_code);
... ...
target-i386/translate-copy.c 0 โ†’ 100644
  1 +/*
  2 + * i386 on i386 translation
  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 +#include <sys/ucontext.h>
  29 +
  30 +#include "cpu.h"
  31 +#include "exec-all.h"
  32 +#include "disas.h"
  33 +
  34 +extern char exec_loop;
  35 +
  36 +/* operand size */
  37 +enum {
  38 + OT_BYTE = 0,
  39 + OT_WORD,
  40 + OT_LONG,
  41 + OT_QUAD,
  42 +};
  43 +
  44 +#define PREFIX_REPZ 0x01
  45 +#define PREFIX_REPNZ 0x02
  46 +#define PREFIX_LOCK 0x04
  47 +#define PREFIX_DATA 0x08
  48 +#define PREFIX_ADR 0x10
  49 +
  50 +typedef struct DisasContext {
  51 + /* current insn context */
  52 + int override; /* -1 if no override */
  53 + int prefix;
  54 + int aflag, dflag;
  55 + uint8_t *pc; /* pc = eip + cs_base */
  56 + int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
  57 + static state change (stop translation) */
  58 + /* code output */
  59 + uint8_t *gen_code_ptr;
  60 + uint8_t *gen_code_start;
  61 +
  62 + /* current block context */
  63 + uint8_t *cs_base; /* base of CS segment */
  64 + int pe; /* protected mode */
  65 + int code32; /* 32 bit code segment */
  66 + int f_st; /* currently unused */
  67 + int vm86; /* vm86 mode */
  68 + int cpl;
  69 + int iopl;
  70 + struct TranslationBlock *tb;
  71 +} DisasContext;
  72 +
  73 +#define CPU_FIELD_OFFSET(field) offsetof(CPUState, field)
  74 +
  75 +#define CPU_SEG 0x64 /* fs override */
  76 +
  77 +static inline void gb(DisasContext *s, uint32_t val)
  78 +{
  79 + *s->gen_code_ptr++ = val;
  80 +}
  81 +
  82 +static inline void gw(DisasContext *s, uint32_t val)
  83 +{
  84 + *s->gen_code_ptr++ = val;
  85 + *s->gen_code_ptr++ = val >> 8;
  86 +}
  87 +
  88 +static inline void gl(DisasContext *s, uint32_t val)
  89 +{
  90 + *s->gen_code_ptr++ = val;
  91 + *s->gen_code_ptr++ = val >> 8;
  92 + *s->gen_code_ptr++ = val >> 16;
  93 + *s->gen_code_ptr++ = val >> 24;
  94 +}
  95 +
  96 +static inline void gjmp(DisasContext *s, long val)
  97 +{
  98 + gb(s, 0xe9); /* jmp */
  99 + gl(s, val - (long)(s->gen_code_ptr + 4));
  100 +}
  101 +
  102 +static inline void gen_movl_addr_im(DisasContext *s,
  103 + uint32_t addr, uint32_t val)
  104 +{
  105 + gb(s, CPU_SEG); /* seg movl im, addr */
  106 + gb(s, 0xc7);
  107 + gb(s, 0x05);
  108 + gl(s, addr);
  109 + gl(s, val);
  110 +}
  111 +
  112 +static inline void gen_movw_addr_im(DisasContext *s,
  113 + uint32_t addr, uint32_t val)
  114 +{
  115 + gb(s, CPU_SEG); /* seg movl im, addr */
  116 + gb(s, 0x66);
  117 + gb(s, 0xc7);
  118 + gb(s, 0x05);
  119 + gl(s, addr);
  120 + gw(s, val);
  121 +}
  122 +
  123 +
  124 +static void gen_jmp(DisasContext *s, uint32_t target_eip)
  125 +{
  126 + TranslationBlock *tb = s->tb;
  127 +
  128 + gb(s, 0xe9); /* jmp */
  129 + tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start;
  130 + gl(s, 0);
  131 +
  132 + tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start;
  133 + gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip);
  134 + gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb);
  135 + gjmp(s, (long)&exec_loop);
  136 +
  137 + s->is_jmp = 1;
  138 +}
  139 +
  140 +static void gen_jcc(DisasContext *s, int op,
  141 + uint32_t target_eip, uint32_t next_eip)
  142 +{
  143 + TranslationBlock *tb = s->tb;
  144 +
  145 + gb(s, 0x0f); /* jcc */
  146 + gb(s, 0x80 + op);
  147 + tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start;
  148 + gl(s, 0);
  149 + gb(s, 0xe9); /* jmp */
  150 + tb->tb_jmp_offset[1] = s->gen_code_ptr - s->gen_code_start;
  151 + gl(s, 0);
  152 +
  153 + tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start;
  154 + gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip);
  155 + gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb);
  156 + gjmp(s, (long)&exec_loop);
  157 +
  158 + tb->tb_next_offset[1] = s->gen_code_ptr - s->gen_code_start;
  159 + gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), next_eip);
  160 + gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb | 1);
  161 + gjmp(s, (long)&exec_loop);
  162 +
  163 + s->is_jmp = 1;
  164 +}
  165 +
  166 +static void gen_eob(DisasContext *s)
  167 +{
  168 + gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), 0);
  169 + gjmp(s, (long)&exec_loop);
  170 +
  171 + s->is_jmp = 1;
  172 +}
  173 +
  174 +static inline void gen_lea_modrm(DisasContext *s, int modrm)
  175 +{
  176 + int havesib;
  177 + int base, disp;
  178 + int index;
  179 + int scale;
  180 + int mod, rm, code;
  181 +
  182 + mod = (modrm >> 6) & 3;
  183 + rm = modrm & 7;
  184 +
  185 + if (s->aflag) {
  186 +
  187 + havesib = 0;
  188 + base = rm;
  189 + index = 0;
  190 + scale = 0;
  191 +
  192 + if (base == 4) {
  193 + havesib = 1;
  194 + code = ldub_code(s->pc++);
  195 + scale = (code >> 6) & 3;
  196 + index = (code >> 3) & 7;
  197 + base = code & 7;
  198 + }
  199 +
  200 + switch (mod) {
  201 + case 0:
  202 + if (base == 5) {
  203 + base = -1;
  204 + disp = ldl_code(s->pc);
  205 + s->pc += 4;
  206 + } else {
  207 + disp = 0;
  208 + }
  209 + break;
  210 + case 1:
  211 + disp = (int8_t)ldub_code(s->pc++);
  212 + break;
  213 + default:
  214 + case 2:
  215 + disp = ldl_code(s->pc);
  216 + s->pc += 4;
  217 + break;
  218 + }
  219 +
  220 + } else {
  221 + switch (mod) {
  222 + case 0:
  223 + if (rm == 6) {
  224 + disp = lduw_code(s->pc);
  225 + s->pc += 2;
  226 + } else {
  227 + disp = 0;
  228 + }
  229 + break;
  230 + case 1:
  231 + disp = (int8_t)ldub_code(s->pc++);
  232 + break;
  233 + default:
  234 + case 2:
  235 + disp = lduw_code(s->pc);
  236 + s->pc += 2;
  237 + break;
  238 + }
  239 + }
  240 +}
  241 +
  242 +static inline void parse_modrm(DisasContext *s, int modrm)
  243 +{
  244 + if ((modrm & 0xc0) != 0xc0)
  245 + gen_lea_modrm(s, modrm);
  246 +}
  247 +
  248 +static inline uint32_t insn_get(DisasContext *s, int ot)
  249 +{
  250 + uint32_t ret;
  251 +
  252 + switch(ot) {
  253 + case OT_BYTE:
  254 + ret = ldub_code(s->pc);
  255 + s->pc++;
  256 + break;
  257 + case OT_WORD:
  258 + ret = lduw_code(s->pc);
  259 + s->pc += 2;
  260 + break;
  261 + default:
  262 + case OT_LONG:
  263 + ret = ldl_code(s->pc);
  264 + s->pc += 4;
  265 + break;
  266 + }
  267 + return ret;
  268 +}
  269 +
  270 +/* convert one instruction. s->is_jmp is set if the translation must
  271 + be stopped. */
  272 +static int disas_insn(DisasContext *s)
  273 +{
  274 + uint8_t *pc_start, *pc_tmp, *pc_start_insn;
  275 + int b, prefixes, aflag, dflag, next_eip, val;
  276 + int ot;
  277 + int modrm, mod, op;
  278 +
  279 + pc_start = s->pc;
  280 + prefixes = 0;
  281 + aflag = s->code32;
  282 + dflag = s->code32;
  283 + s->override = -1;
  284 + next_byte:
  285 + b = ldub_code(s->pc);
  286 + s->pc++;
  287 + /* check prefixes */
  288 + switch (b) {
  289 + case 0xf3:
  290 + prefixes |= PREFIX_REPZ;
  291 + goto next_byte;
  292 + case 0xf2:
  293 + prefixes |= PREFIX_REPNZ;
  294 + goto next_byte;
  295 + case 0xf0:
  296 + prefixes |= PREFIX_LOCK;
  297 + goto next_byte;
  298 + case 0x2e:
  299 + s->override = R_CS;
  300 + goto next_byte;
  301 + case 0x36:
  302 + s->override = R_SS;
  303 + goto next_byte;
  304 + case 0x3e:
  305 + s->override = R_DS;
  306 + goto next_byte;
  307 + case 0x26:
  308 + s->override = R_ES;
  309 + goto next_byte;
  310 + case 0x64:
  311 + s->override = R_FS;
  312 + goto next_byte;
  313 + case 0x65:
  314 + s->override = R_GS;
  315 + goto next_byte;
  316 + case 0x66:
  317 + prefixes |= PREFIX_DATA;
  318 + goto next_byte;
  319 + case 0x67:
  320 + prefixes |= PREFIX_ADR;
  321 + goto next_byte;
  322 + }
  323 +
  324 + if (prefixes & PREFIX_DATA)
  325 + dflag ^= 1;
  326 + if (prefixes & PREFIX_ADR)
  327 + aflag ^= 1;
  328 +
  329 + s->prefix = prefixes;
  330 + s->aflag = aflag;
  331 + s->dflag = dflag;
  332 +
  333 + /* lock generation */
  334 + if (prefixes & PREFIX_LOCK)
  335 + goto unsupported_op;
  336 + if (s->override == R_FS || s->override == R_GS || s->override == R_CS)
  337 + goto unsupported_op;
  338 +
  339 + pc_start_insn = s->pc - 1;
  340 + /* now check op code */
  341 + reswitch:
  342 + switch(b) {
  343 + case 0x0f:
  344 + /**************************/
  345 + /* extended op code */
  346 + b = ldub_code(s->pc++) | 0x100;
  347 + goto reswitch;
  348 +
  349 + /**************************/
  350 + /* arith & logic */
  351 + case 0x00 ... 0x05:
  352 + case 0x08 ... 0x0d:
  353 + case 0x10 ... 0x15:
  354 + case 0x18 ... 0x1d:
  355 + case 0x20 ... 0x25:
  356 + case 0x28 ... 0x2d:
  357 + case 0x30 ... 0x35:
  358 + case 0x38 ... 0x3d:
  359 + {
  360 + int f;
  361 + f = (b >> 1) & 3;
  362 +
  363 + if ((b & 1) == 0)
  364 + ot = OT_BYTE;
  365 + else
  366 + ot = dflag ? OT_LONG : OT_WORD;
  367 +
  368 + switch(f) {
  369 + case 0: /* OP Ev, Gv */
  370 + modrm = ldub_code(s->pc++);
  371 + parse_modrm(s, modrm);
  372 + break;
  373 + case 1: /* OP Gv, Ev */
  374 + modrm = ldub_code(s->pc++);
  375 + parse_modrm(s, modrm);
  376 + break;
  377 + case 2: /* OP A, Iv */
  378 + insn_get(s, ot);
  379 + break;
  380 + }
  381 + }
  382 + break;
  383 +
  384 + case 0x80: /* GRP1 */
  385 + case 0x81:
  386 + case 0x83:
  387 + {
  388 + if ((b & 1) == 0)
  389 + ot = OT_BYTE;
  390 + else
  391 + ot = dflag ? OT_LONG : OT_WORD;
  392 +
  393 + modrm = ldub_code(s->pc++);
  394 + parse_modrm(s, modrm);
  395 +
  396 + switch(b) {
  397 + default:
  398 + case 0x80:
  399 + case 0x81:
  400 + insn_get(s, ot);
  401 + break;
  402 + case 0x83:
  403 + insn_get(s, OT_BYTE);
  404 + break;
  405 + }
  406 + }
  407 + break;
  408 +
  409 + /**************************/
  410 + /* inc, dec, and other misc arith */
  411 + case 0x40 ... 0x47: /* inc Gv */
  412 + break;
  413 + case 0x48 ... 0x4f: /* dec Gv */
  414 + break;
  415 + case 0xf6: /* GRP3 */
  416 + case 0xf7:
  417 + if ((b & 1) == 0)
  418 + ot = OT_BYTE;
  419 + else
  420 + ot = dflag ? OT_LONG : OT_WORD;
  421 +
  422 + modrm = ldub_code(s->pc++);
  423 + op = (modrm >> 3) & 7;
  424 + parse_modrm(s, modrm);
  425 +
  426 + switch(op) {
  427 + case 0: /* test */
  428 + insn_get(s, ot);
  429 + break;
  430 + case 2: /* not */
  431 + break;
  432 + case 3: /* neg */
  433 + break;
  434 + case 4: /* mul */
  435 + break;
  436 + case 5: /* imul */
  437 + break;
  438 + case 6: /* div */
  439 + break;
  440 + case 7: /* idiv */
  441 + break;
  442 + default:
  443 + goto illegal_op;
  444 + }
  445 + break;
  446 +
  447 + case 0xfe: /* GRP4 */
  448 + case 0xff: /* GRP5 */
  449 + if ((b & 1) == 0)
  450 + ot = OT_BYTE;
  451 + else
  452 + ot = dflag ? OT_LONG : OT_WORD;
  453 +
  454 + modrm = ldub_code(s->pc++);
  455 + mod = (modrm >> 6) & 3;
  456 + op = (modrm >> 3) & 7;
  457 + if (op >= 2 && b == 0xfe) {
  458 + goto illegal_op;
  459 + }
  460 + pc_tmp = s->pc;
  461 + parse_modrm(s, modrm);
  462 +
  463 + switch(op) {
  464 + case 0: /* inc Ev */
  465 + break;
  466 + case 1: /* dec Ev */
  467 + break;
  468 + case 2: /* call Ev */
  469 + /* XXX: optimize and handle MEM exceptions specifically
  470 + fs movl %eax, regs[0]
  471 + movl Ev, %eax
  472 + pushl next_eip
  473 + fs movl %eax, eip
  474 + */
  475 + goto unsupported_op;
  476 + case 3: /* lcall Ev */
  477 + goto unsupported_op;
  478 + case 4: /* jmp Ev */
  479 + /* XXX: optimize and handle MEM exceptions specifically
  480 + fs movl %eax, regs[0]
  481 + movl Ev, %eax
  482 + fs movl %eax, eip
  483 + */
  484 + goto unsupported_op;
  485 + case 5: /* ljmp Ev */
  486 + goto unsupported_op;
  487 + case 6: /* push Ev */
  488 + break;
  489 + default:
  490 + goto illegal_op;
  491 + }
  492 + break;
  493 + case 0xa8: /* test eAX, Iv */
  494 + case 0xa9:
  495 + if ((b & 1) == 0)
  496 + ot = OT_BYTE;
  497 + else
  498 + ot = dflag ? OT_LONG : OT_WORD;
  499 + insn_get(s, ot);
  500 + break;
  501 +
  502 + case 0x98: /* CWDE/CBW */
  503 + break;
  504 + case 0x99: /* CDQ/CWD */
  505 + break;
  506 + case 0x1af: /* imul Gv, Ev */
  507 + case 0x69: /* imul Gv, Ev, I */
  508 + case 0x6b:
  509 + ot = dflag ? OT_LONG : OT_WORD;
  510 + modrm = ldub_code(s->pc++);
  511 + parse_modrm(s, modrm);
  512 + if (b == 0x69) {
  513 + insn_get(s, ot);
  514 + } else if (b == 0x6b) {
  515 + insn_get(s, OT_BYTE);
  516 + } else {
  517 + }
  518 + break;
  519 +
  520 + case 0x84: /* test Ev, Gv */
  521 + case 0x85:
  522 +
  523 + case 0x1c0:
  524 + case 0x1c1: /* xadd Ev, Gv */
  525 +
  526 + case 0x1b0:
  527 + case 0x1b1: /* cmpxchg Ev, Gv */
  528 +
  529 + case 0x8f: /* pop Ev */
  530 +
  531 + case 0x88:
  532 + case 0x89: /* mov Gv, Ev */
  533 +
  534 + case 0x8a:
  535 + case 0x8b: /* mov Ev, Gv */
  536 +
  537 + case 0x1b6: /* movzbS Gv, Eb */
  538 + case 0x1b7: /* movzwS Gv, Eb */
  539 + case 0x1be: /* movsbS Gv, Eb */
  540 + case 0x1bf: /* movswS Gv, Eb */
  541 +
  542 + case 0x86:
  543 + case 0x87: /* xchg Ev, Gv */
  544 +
  545 + case 0xd0:
  546 + case 0xd1: /* shift Ev,1 */
  547 +
  548 + case 0xd2:
  549 + case 0xd3: /* shift Ev,cl */
  550 +
  551 + case 0x1a5: /* shld cl */
  552 + case 0x1ad: /* shrd cl */
  553 +
  554 + case 0x190 ... 0x19f: /* setcc Gv */
  555 +
  556 + /* XXX: emulate cmov if not available ? */
  557 + case 0x140 ... 0x14f: /* cmov Gv, Ev */
  558 +
  559 + case 0x1a3: /* bt Gv, Ev */
  560 + case 0x1ab: /* bts */
  561 + case 0x1b3: /* btr */
  562 + case 0x1bb: /* btc */
  563 +
  564 + case 0x1bc: /* bsf */
  565 + case 0x1bd: /* bsr */
  566 +
  567 + modrm = ldub_code(s->pc++);
  568 + parse_modrm(s, modrm);
  569 + break;
  570 +
  571 + case 0x1c7: /* cmpxchg8b */
  572 + modrm = ldub_code(s->pc++);
  573 + mod = (modrm >> 6) & 3;
  574 + if (mod == 3)
  575 + goto illegal_op;
  576 + parse_modrm(s, modrm);
  577 + break;
  578 +
  579 + /**************************/
  580 + /* push/pop */
  581 + case 0x50 ... 0x57: /* push */
  582 + case 0x58 ... 0x5f: /* pop */
  583 + case 0x60: /* pusha */
  584 + case 0x61: /* popa */
  585 + break;
  586 +
  587 + case 0x68: /* push Iv */
  588 + case 0x6a:
  589 + ot = dflag ? OT_LONG : OT_WORD;
  590 + if (b == 0x68)
  591 + insn_get(s, ot);
  592 + else
  593 + insn_get(s, OT_BYTE);
  594 + break;
  595 + case 0xc8: /* enter */
  596 + lduw_code(s->pc);
  597 + s->pc += 2;
  598 + ldub_code(s->pc++);
  599 + break;
  600 + case 0xc9: /* leave */
  601 + break;
  602 +
  603 + case 0x06: /* push es */
  604 + case 0x0e: /* push cs */
  605 + case 0x16: /* push ss */
  606 + case 0x1e: /* push ds */
  607 + /* XXX: optimize:
  608 + push segs[n].selector
  609 + */
  610 + goto unsupported_op;
  611 + case 0x1a0: /* push fs */
  612 + case 0x1a8: /* push gs */
  613 + goto unsupported_op;
  614 + case 0x07: /* pop es */
  615 + case 0x17: /* pop ss */
  616 + case 0x1f: /* pop ds */
  617 + goto unsupported_op;
  618 + case 0x1a1: /* pop fs */
  619 + case 0x1a9: /* pop gs */
  620 + goto unsupported_op;
  621 + case 0x8e: /* mov seg, Gv */
  622 + /* XXX: optimize:
  623 + fs movl r, regs[]
  624 + movl segs[].selector, r
  625 + mov r, Gv
  626 + fs movl regs[], r
  627 + */
  628 + goto unsupported_op;
  629 + case 0x8c: /* mov Gv, seg */
  630 + goto unsupported_op;
  631 + case 0xc4: /* les Gv */
  632 + op = R_ES;
  633 + goto do_lxx;
  634 + case 0xc5: /* lds Gv */
  635 + op = R_DS;
  636 + goto do_lxx;
  637 + case 0x1b2: /* lss Gv */
  638 + op = R_SS;
  639 + goto do_lxx;
  640 + case 0x1b4: /* lfs Gv */
  641 + op = R_FS;
  642 + goto do_lxx;
  643 + case 0x1b5: /* lgs Gv */
  644 + op = R_GS;
  645 + do_lxx:
  646 + goto unsupported_op;
  647 +#if 0
  648 + /************************/
  649 + /* floats */
  650 + case 0xd8 ... 0xdf:
  651 + modrm = ldub_code(s->pc++);
  652 + mod = (modrm >> 6) & 3;
  653 + rm = modrm & 7;
  654 + op = ((b & 7) << 3) | ((modrm >> 3) & 7);
  655 + if (mod != 3) {
  656 + /* memory op */
  657 + gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
  658 + switch(op) {
  659 + case 0x00 ... 0x07: /* fxxxs */
  660 + case 0x10 ... 0x17: /* fixxxl */
  661 + case 0x20 ... 0x27: /* fxxxl */
  662 + case 0x30 ... 0x37: /* fixxx */
  663 + {
  664 + int op1;
  665 + op1 = op & 7;
  666 +
  667 + switch(op >> 4) {
  668 + case 0:
  669 + gen_op_flds_FT0_A0();
  670 + break;
  671 + case 1:
  672 + gen_op_fildl_FT0_A0();
  673 + break;
  674 + case 2:
  675 + gen_op_fldl_FT0_A0();
  676 + break;
  677 + case 3:
  678 + default:
  679 + gen_op_fild_FT0_A0();
  680 + break;
  681 + }
  682 +
  683 + gen_op_fp_arith_ST0_FT0[op1]();
  684 + if (op1 == 3) {
  685 + /* fcomp needs pop */
  686 + gen_op_fpop();
  687 + }
  688 + }
  689 + break;
  690 + case 0x08: /* flds */
  691 + case 0x0a: /* fsts */
  692 + case 0x0b: /* fstps */
  693 + case 0x18: /* fildl */
  694 + case 0x1a: /* fistl */
  695 + case 0x1b: /* fistpl */
  696 + case 0x28: /* fldl */
  697 + case 0x2a: /* fstl */
  698 + case 0x2b: /* fstpl */
  699 + case 0x38: /* filds */
  700 + case 0x3a: /* fists */
  701 + case 0x3b: /* fistps */
  702 +
  703 + switch(op & 7) {
  704 + case 0:
  705 + switch(op >> 4) {
  706 + case 0:
  707 + gen_op_flds_ST0_A0();
  708 + break;
  709 + case 1:
  710 + gen_op_fildl_ST0_A0();
  711 + break;
  712 + case 2:
  713 + gen_op_fldl_ST0_A0();
  714 + break;
  715 + case 3:
  716 + default:
  717 + gen_op_fild_ST0_A0();
  718 + break;
  719 + }
  720 + break;
  721 + default:
  722 + switch(op >> 4) {
  723 + case 0:
  724 + gen_op_fsts_ST0_A0();
  725 + break;
  726 + case 1:
  727 + gen_op_fistl_ST0_A0();
  728 + break;
  729 + case 2:
  730 + gen_op_fstl_ST0_A0();
  731 + break;
  732 + case 3:
  733 + default:
  734 + gen_op_fist_ST0_A0();
  735 + break;
  736 + }
  737 + if ((op & 7) == 3)
  738 + gen_op_fpop();
  739 + break;
  740 + }
  741 + break;
  742 + case 0x0c: /* fldenv mem */
  743 + gen_op_fldenv_A0(s->dflag);
  744 + break;
  745 + case 0x0d: /* fldcw mem */
  746 + gen_op_fldcw_A0();
  747 + break;
  748 + case 0x0e: /* fnstenv mem */
  749 + gen_op_fnstenv_A0(s->dflag);
  750 + break;
  751 + case 0x0f: /* fnstcw mem */
  752 + gen_op_fnstcw_A0();
  753 + break;
  754 + case 0x1d: /* fldt mem */
  755 + gen_op_fldt_ST0_A0();
  756 + break;
  757 + case 0x1f: /* fstpt mem */
  758 + gen_op_fstt_ST0_A0();
  759 + gen_op_fpop();
  760 + break;
  761 + case 0x2c: /* frstor mem */
  762 + gen_op_frstor_A0(s->dflag);
  763 + break;
  764 + case 0x2e: /* fnsave mem */
  765 + gen_op_fnsave_A0(s->dflag);
  766 + break;
  767 + case 0x2f: /* fnstsw mem */
  768 + gen_op_fnstsw_A0();
  769 + break;
  770 + case 0x3c: /* fbld */
  771 + gen_op_fbld_ST0_A0();
  772 + break;
  773 + case 0x3e: /* fbstp */
  774 + gen_op_fbst_ST0_A0();
  775 + gen_op_fpop();
  776 + break;
  777 + case 0x3d: /* fildll */
  778 + gen_op_fildll_ST0_A0();
  779 + break;
  780 + case 0x3f: /* fistpll */
  781 + gen_op_fistll_ST0_A0();
  782 + gen_op_fpop();
  783 + break;
  784 + default:
  785 + goto illegal_op;
  786 + }
  787 + } else {
  788 + /* register float ops */
  789 + opreg = rm;
  790 +
  791 + switch(op) {
  792 + case 0x08: /* fld sti */
  793 + gen_op_fpush();
  794 + gen_op_fmov_ST0_STN((opreg + 1) & 7);
  795 + break;
  796 + case 0x09: /* fxchg sti */
  797 + gen_op_fxchg_ST0_STN(opreg);
  798 + break;
  799 + case 0x0a: /* grp d9/2 */
  800 + switch(rm) {
  801 + case 0: /* fnop */
  802 + break;
  803 + default:
  804 + goto illegal_op;
  805 + }
  806 + break;
  807 + case 0x0c: /* grp d9/4 */
  808 + switch(rm) {
  809 + case 0: /* fchs */
  810 + gen_op_fchs_ST0();
  811 + break;
  812 + case 1: /* fabs */
  813 + gen_op_fabs_ST0();
  814 + break;
  815 + case 4: /* ftst */
  816 + gen_op_fldz_FT0();
  817 + gen_op_fcom_ST0_FT0();
  818 + break;
  819 + case 5: /* fxam */
  820 + gen_op_fxam_ST0();
  821 + break;
  822 + default:
  823 + goto illegal_op;
  824 + }
  825 + break;
  826 + case 0x0d: /* grp d9/5 */
  827 + {
  828 + switch(rm) {
  829 + case 0:
  830 + gen_op_fpush();
  831 + gen_op_fld1_ST0();
  832 + break;
  833 + case 1:
  834 + gen_op_fpush();
  835 + gen_op_fldl2t_ST0();
  836 + break;
  837 + case 2:
  838 + gen_op_fpush();
  839 + gen_op_fldl2e_ST0();
  840 + break;
  841 + case 3:
  842 + gen_op_fpush();
  843 + gen_op_fldpi_ST0();
  844 + break;
  845 + case 4:
  846 + gen_op_fpush();
  847 + gen_op_fldlg2_ST0();
  848 + break;
  849 + case 5:
  850 + gen_op_fpush();
  851 + gen_op_fldln2_ST0();
  852 + break;
  853 + case 6:
  854 + gen_op_fpush();
  855 + gen_op_fldz_ST0();
  856 + break;
  857 + default:
  858 + goto illegal_op;
  859 + }
  860 + }
  861 + break;
  862 + case 0x0e: /* grp d9/6 */
  863 + switch(rm) {
  864 + case 0: /* f2xm1 */
  865 + gen_op_f2xm1();
  866 + break;
  867 + case 1: /* fyl2x */
  868 + gen_op_fyl2x();
  869 + break;
  870 + case 2: /* fptan */
  871 + gen_op_fptan();
  872 + break;
  873 + case 3: /* fpatan */
  874 + gen_op_fpatan();
  875 + break;
  876 + case 4: /* fxtract */
  877 + gen_op_fxtract();
  878 + break;
  879 + case 5: /* fprem1 */
  880 + gen_op_fprem1();
  881 + break;
  882 + case 6: /* fdecstp */
  883 + gen_op_fdecstp();
  884 + break;
  885 + default:
  886 + case 7: /* fincstp */
  887 + gen_op_fincstp();
  888 + break;
  889 + }
  890 + break;
  891 + case 0x0f: /* grp d9/7 */
  892 + switch(rm) {
  893 + case 0: /* fprem */
  894 + gen_op_fprem();
  895 + break;
  896 + case 1: /* fyl2xp1 */
  897 + gen_op_fyl2xp1();
  898 + break;
  899 + case 2: /* fsqrt */
  900 + gen_op_fsqrt();
  901 + break;
  902 + case 3: /* fsincos */
  903 + gen_op_fsincos();
  904 + break;
  905 + case 5: /* fscale */
  906 + gen_op_fscale();
  907 + break;
  908 + case 4: /* frndint */
  909 + gen_op_frndint();
  910 + break;
  911 + case 6: /* fsin */
  912 + gen_op_fsin();
  913 + break;
  914 + default:
  915 + case 7: /* fcos */
  916 + gen_op_fcos();
  917 + break;
  918 + }
  919 + break;
  920 + case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
  921 + case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
  922 + case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
  923 + {
  924 + int op1;
  925 +
  926 + op1 = op & 7;
  927 + if (op >= 0x20) {
  928 + gen_op_fp_arith_STN_ST0[op1](opreg);
  929 + if (op >= 0x30)
  930 + gen_op_fpop();
  931 + } else {
  932 + gen_op_fmov_FT0_STN(opreg);
  933 + gen_op_fp_arith_ST0_FT0[op1]();
  934 + }
  935 + }
  936 + break;
  937 + case 0x02: /* fcom */
  938 + gen_op_fmov_FT0_STN(opreg);
  939 + gen_op_fcom_ST0_FT0();
  940 + break;
  941 + case 0x03: /* fcomp */
  942 + gen_op_fmov_FT0_STN(opreg);
  943 + gen_op_fcom_ST0_FT0();
  944 + gen_op_fpop();
  945 + break;
  946 + case 0x15: /* da/5 */
  947 + switch(rm) {
  948 + case 1: /* fucompp */
  949 + gen_op_fmov_FT0_STN(1);
  950 + gen_op_fucom_ST0_FT0();
  951 + gen_op_fpop();
  952 + gen_op_fpop();
  953 + break;
  954 + default:
  955 + goto illegal_op;
  956 + }
  957 + break;
  958 + case 0x1c:
  959 + switch(rm) {
  960 + case 0: /* feni (287 only, just do nop here) */
  961 + break;
  962 + case 1: /* fdisi (287 only, just do nop here) */
  963 + break;
  964 + case 2: /* fclex */
  965 + gen_op_fclex();
  966 + break;
  967 + case 3: /* fninit */
  968 + gen_op_fninit();
  969 + break;
  970 + case 4: /* fsetpm (287 only, just do nop here) */
  971 + break;
  972 + default:
  973 + goto illegal_op;
  974 + }
  975 + break;
  976 + case 0x1d: /* fucomi */
  977 + if (s->cc_op != CC_OP_DYNAMIC)
  978 + gen_op_set_cc_op(s->cc_op);
  979 + gen_op_fmov_FT0_STN(opreg);
  980 + gen_op_fucomi_ST0_FT0();
  981 + s->cc_op = CC_OP_EFLAGS;
  982 + break;
  983 + case 0x1e: /* fcomi */
  984 + if (s->cc_op != CC_OP_DYNAMIC)
  985 + gen_op_set_cc_op(s->cc_op);
  986 + gen_op_fmov_FT0_STN(opreg);
  987 + gen_op_fcomi_ST0_FT0();
  988 + s->cc_op = CC_OP_EFLAGS;
  989 + break;
  990 + case 0x2a: /* fst sti */
  991 + gen_op_fmov_STN_ST0(opreg);
  992 + break;
  993 + case 0x2b: /* fstp sti */
  994 + gen_op_fmov_STN_ST0(opreg);
  995 + gen_op_fpop();
  996 + break;
  997 + case 0x2c: /* fucom st(i) */
  998 + gen_op_fmov_FT0_STN(opreg);
  999 + gen_op_fucom_ST0_FT0();
  1000 + break;
  1001 + case 0x2d: /* fucomp st(i) */
  1002 + gen_op_fmov_FT0_STN(opreg);
  1003 + gen_op_fucom_ST0_FT0();
  1004 + gen_op_fpop();
  1005 + break;
  1006 + case 0x33: /* de/3 */
  1007 + switch(rm) {
  1008 + case 1: /* fcompp */
  1009 + gen_op_fmov_FT0_STN(1);
  1010 + gen_op_fcom_ST0_FT0();
  1011 + gen_op_fpop();
  1012 + gen_op_fpop();
  1013 + break;
  1014 + default:
  1015 + goto illegal_op;
  1016 + }
  1017 + break;
  1018 + case 0x3c: /* df/4 */
  1019 + switch(rm) {
  1020 + case 0:
  1021 + gen_op_fnstsw_EAX();
  1022 + break;
  1023 + default:
  1024 + goto illegal_op;
  1025 + }
  1026 + break;
  1027 + case 0x3d: /* fucomip */
  1028 + if (s->cc_op != CC_OP_DYNAMIC)
  1029 + gen_op_set_cc_op(s->cc_op);
  1030 + gen_op_fmov_FT0_STN(opreg);
  1031 + gen_op_fucomi_ST0_FT0();
  1032 + gen_op_fpop();
  1033 + s->cc_op = CC_OP_EFLAGS;
  1034 + break;
  1035 + case 0x3e: /* fcomip */
  1036 + if (s->cc_op != CC_OP_DYNAMIC)
  1037 + gen_op_set_cc_op(s->cc_op);
  1038 + gen_op_fmov_FT0_STN(opreg);
  1039 + gen_op_fcomi_ST0_FT0();
  1040 + gen_op_fpop();
  1041 + s->cc_op = CC_OP_EFLAGS;
  1042 + break;
  1043 + case 0x10 ... 0x13: /* fcmovxx */
  1044 + case 0x18 ... 0x1b:
  1045 + {
  1046 + int op1;
  1047 + const static uint8_t fcmov_cc[8] = {
  1048 + (JCC_B << 1),
  1049 + (JCC_Z << 1),
  1050 + (JCC_BE << 1),
  1051 + (JCC_P << 1),
  1052 + };
  1053 + op1 = fcmov_cc[op & 3] | ((op >> 3) & 1);
  1054 + gen_setcc(s, op1);
  1055 + gen_op_fcmov_ST0_STN_T0(opreg);
  1056 + }
  1057 + break;
  1058 + default:
  1059 + goto illegal_op;
  1060 + }
  1061 + }
  1062 + break;
  1063 +#endif
  1064 + /**************************/
  1065 + /* mov */
  1066 + case 0xc6:
  1067 + case 0xc7: /* mov Ev, Iv */
  1068 + if ((b & 1) == 0)
  1069 + ot = OT_BYTE;
  1070 + else
  1071 + ot = dflag ? OT_LONG : OT_WORD;
  1072 + modrm = ldub_code(s->pc++);
  1073 + parse_modrm(s, modrm);
  1074 + insn_get(s, ot);
  1075 + break;
  1076 +
  1077 + case 0x8d: /* lea */
  1078 + ot = dflag ? OT_LONG : OT_WORD;
  1079 + modrm = ldub_code(s->pc++);
  1080 + mod = (modrm >> 6) & 3;
  1081 + if (mod == 3)
  1082 + goto illegal_op;
  1083 + parse_modrm(s, modrm);
  1084 + break;
  1085 +
  1086 + case 0xa0: /* mov EAX, Ov */
  1087 + case 0xa1:
  1088 + case 0xa2: /* mov Ov, EAX */
  1089 + case 0xa3:
  1090 + if ((b & 1) == 0)
  1091 + ot = OT_BYTE;
  1092 + else
  1093 + ot = dflag ? OT_LONG : OT_WORD;
  1094 + if (s->aflag)
  1095 + insn_get(s, OT_LONG);
  1096 + else
  1097 + insn_get(s, OT_WORD);
  1098 + break;
  1099 + case 0xd7: /* xlat */
  1100 + break;
  1101 + case 0xb0 ... 0xb7: /* mov R, Ib */
  1102 + insn_get(s, OT_BYTE);
  1103 + break;
  1104 + case 0xb8 ... 0xbf: /* mov R, Iv */
  1105 + ot = dflag ? OT_LONG : OT_WORD;
  1106 + insn_get(s, ot);
  1107 + break;
  1108 +
  1109 + case 0x91 ... 0x97: /* xchg R, EAX */
  1110 + break;
  1111 +
  1112 + /************************/
  1113 + /* shifts */
  1114 + case 0xc0:
  1115 + case 0xc1: /* shift Ev,imm */
  1116 +
  1117 + case 0x1a4: /* shld imm */
  1118 + case 0x1ac: /* shrd imm */
  1119 + modrm = ldub_code(s->pc++);
  1120 + parse_modrm(s, modrm);
  1121 + ldub_code(s->pc++);
  1122 + break;
  1123 +
  1124 + /************************/
  1125 + /* string ops */
  1126 +
  1127 + case 0xa4: /* movsS */
  1128 + case 0xa5:
  1129 + break;
  1130 +
  1131 + case 0xaa: /* stosS */
  1132 + case 0xab:
  1133 + break;
  1134 +
  1135 + case 0xac: /* lodsS */
  1136 + case 0xad:
  1137 + break;
  1138 +
  1139 + case 0xae: /* scasS */
  1140 + case 0xaf:
  1141 + break;
  1142 +
  1143 + case 0xa6: /* cmpsS */
  1144 + case 0xa7:
  1145 + break;
  1146 +
  1147 + case 0x6c: /* insS */
  1148 + case 0x6d:
  1149 + goto unsupported_op;
  1150 +
  1151 + case 0x6e: /* outsS */
  1152 + case 0x6f:
  1153 + goto unsupported_op;
  1154 +
  1155 + /************************/
  1156 + /* port I/O */
  1157 + case 0xe4:
  1158 + case 0xe5:
  1159 + goto unsupported_op;
  1160 +
  1161 + case 0xe6:
  1162 + case 0xe7:
  1163 + goto unsupported_op;
  1164 +
  1165 + case 0xec:
  1166 + case 0xed:
  1167 + goto unsupported_op;
  1168 +
  1169 + case 0xee:
  1170 + case 0xef:
  1171 + goto unsupported_op;
  1172 +
  1173 + /************************/
  1174 + /* control */
  1175 +#if 0
  1176 + case 0xc2: /* ret im */
  1177 + val = ldsw_code(s->pc);
  1178 + s->pc += 2;
  1179 + gen_pop_T0(s);
  1180 + gen_stack_update(s, val + (2 << s->dflag));
  1181 + if (s->dflag == 0)
  1182 + gen_op_andl_T0_ffff();
  1183 + gen_op_jmp_T0();
  1184 + gen_eob(s);
  1185 + break;
  1186 +#endif
  1187 +
  1188 + case 0xc3: /* ret */
  1189 + gb(s, CPU_SEG);
  1190 + if (!s->dflag)
  1191 + gb(s, 0x66); /* d16 */
  1192 + gb(s, 0x8f); /* pop addr */
  1193 + gb(s, 0x05);
  1194 + gl(s, CPU_FIELD_OFFSET(eip));
  1195 + if (!s->dflag) {
  1196 + /* reset high bits of EIP */
  1197 + gen_movw_addr_im(s, CPU_FIELD_OFFSET(eip) + 2, 0);
  1198 + }
  1199 + gen_eob(s);
  1200 + goto no_copy;
  1201 + case 0xca: /* lret im */
  1202 + case 0xcb: /* lret */
  1203 + case 0xcf: /* iret */
  1204 + case 0x9a: /* lcall im */
  1205 + case 0xea: /* ljmp im */
  1206 + goto unsupported_op;
  1207 +
  1208 + case 0xe8: /* call im */
  1209 + ot = dflag ? OT_LONG : OT_WORD;
  1210 + val = insn_get(s, ot);
  1211 + next_eip = s->pc - s->cs_base;
  1212 + val += next_eip;
  1213 + if (s->dflag) {
  1214 + gb(s, 0x68); /* pushl imm */
  1215 + gl(s, next_eip);
  1216 + } else {
  1217 + gb(s, 0x66); /* pushw imm */
  1218 + gb(s, 0x68);
  1219 + gw(s, next_eip);
  1220 + val &= 0xffff;
  1221 + }
  1222 + gen_jmp(s, val);
  1223 + goto no_copy;
  1224 + case 0xe9: /* jmp */
  1225 + ot = dflag ? OT_LONG : OT_WORD;
  1226 + val = insn_get(s, ot);
  1227 + val += s->pc - s->cs_base;
  1228 + if (s->dflag == 0)
  1229 + val = val & 0xffff;
  1230 + gen_jmp(s, val);
  1231 + goto no_copy;
  1232 + case 0xeb: /* jmp Jb */
  1233 + val = (int8_t)insn_get(s, OT_BYTE);
  1234 + val += s->pc - s->cs_base;
  1235 + if (s->dflag == 0)
  1236 + val = val & 0xffff;
  1237 + gen_jmp(s, val);
  1238 + goto no_copy;
  1239 + case 0x70 ... 0x7f: /* jcc Jb */
  1240 + val = (int8_t)insn_get(s, OT_BYTE);
  1241 + goto do_jcc;
  1242 + case 0x180 ... 0x18f: /* jcc Jv */
  1243 + if (dflag) {
  1244 + val = insn_get(s, OT_LONG);
  1245 + } else {
  1246 + val = (int16_t)insn_get(s, OT_WORD);
  1247 + }
  1248 + do_jcc:
  1249 + next_eip = s->pc - s->cs_base;
  1250 + val += next_eip;
  1251 + if (s->dflag == 0)
  1252 + val &= 0xffff;
  1253 + gen_jcc(s, b & 0xf, val, next_eip);
  1254 + goto no_copy;
  1255 +
  1256 + /************************/
  1257 + /* flags */
  1258 + case 0x9c: /* pushf */
  1259 + /* XXX: put specific code ? */
  1260 + goto unsupported_op;
  1261 + case 0x9d: /* popf */
  1262 + goto unsupported_op;
  1263 +
  1264 + case 0x9e: /* sahf */
  1265 + case 0x9f: /* lahf */
  1266 + case 0xf5: /* cmc */
  1267 + case 0xf8: /* clc */
  1268 + case 0xf9: /* stc */
  1269 + case 0xfc: /* cld */
  1270 + case 0xfd: /* std */
  1271 + break;
  1272 +
  1273 + /************************/
  1274 + /* bit operations */
  1275 + case 0x1ba: /* bt/bts/btr/btc Gv, im */
  1276 + ot = dflag ? OT_LONG : OT_WORD;
  1277 + modrm = ldub_code(s->pc++);
  1278 + op = (modrm >> 3) & 7;
  1279 + parse_modrm(s, modrm);
  1280 + /* load shift */
  1281 + ldub_code(s->pc++);
  1282 + if (op < 4)
  1283 + goto illegal_op;
  1284 + break;
  1285 + /************************/
  1286 + /* bcd */
  1287 + case 0x27: /* daa */
  1288 + break;
  1289 + case 0x2f: /* das */
  1290 + break;
  1291 + case 0x37: /* aaa */
  1292 + break;
  1293 + case 0x3f: /* aas */
  1294 + break;
  1295 + case 0xd4: /* aam */
  1296 + ldub_code(s->pc++);
  1297 + break;
  1298 + case 0xd5: /* aad */
  1299 + ldub_code(s->pc++);
  1300 + break;
  1301 + /************************/
  1302 + /* misc */
  1303 + case 0x90: /* nop */
  1304 + break;
  1305 + case 0x9b: /* fwait */
  1306 + break;
  1307 + case 0xcc: /* int3 */
  1308 + goto unsupported_op;
  1309 + case 0xcd: /* int N */
  1310 + goto unsupported_op;
  1311 + case 0xce: /* into */
  1312 + goto unsupported_op;
  1313 + case 0xf1: /* icebp (undocumented, exits to external debugger) */
  1314 + goto unsupported_op;
  1315 + case 0xfa: /* cli */
  1316 + goto unsupported_op;
  1317 + case 0xfb: /* sti */
  1318 + goto unsupported_op;
  1319 + case 0x62: /* bound */
  1320 + modrm = ldub_code(s->pc++);
  1321 + mod = (modrm >> 6) & 3;
  1322 + if (mod == 3)
  1323 + goto illegal_op;
  1324 + parse_modrm(s, modrm);
  1325 + break;
  1326 + case 0x1c8 ... 0x1cf: /* bswap reg */
  1327 + break;
  1328 + case 0xd6: /* salc */
  1329 + break;
  1330 + case 0xe0: /* loopnz */
  1331 + case 0xe1: /* loopz */
  1332 + case 0xe2: /* loop */
  1333 + case 0xe3: /* jecxz */
  1334 + goto unsupported_op;
  1335 +
  1336 + case 0x130: /* wrmsr */
  1337 + case 0x132: /* rdmsr */
  1338 + goto unsupported_op;
  1339 + case 0x131: /* rdtsc */
  1340 + goto unsupported_op;
  1341 + case 0x1a2: /* cpuid */
  1342 + goto unsupported_op;
  1343 + case 0xf4: /* hlt */
  1344 + goto unsupported_op;
  1345 + case 0x100:
  1346 + goto unsupported_op;
  1347 + case 0x101:
  1348 + goto unsupported_op;
  1349 + case 0x108: /* invd */
  1350 + case 0x109: /* wbinvd */
  1351 + goto unsupported_op;
  1352 + case 0x63: /* arpl */
  1353 + goto unsupported_op;
  1354 + case 0x102: /* lar */
  1355 + case 0x103: /* lsl */
  1356 + goto unsupported_op;
  1357 + case 0x118:
  1358 + goto unsupported_op;
  1359 + case 0x120: /* mov reg, crN */
  1360 + case 0x122: /* mov crN, reg */
  1361 + goto unsupported_op;
  1362 + case 0x121: /* mov reg, drN */
  1363 + case 0x123: /* mov drN, reg */
  1364 + goto unsupported_op;
  1365 + case 0x106: /* clts */
  1366 + goto unsupported_op;
  1367 + default:
  1368 + goto illegal_op;
  1369 + }
  1370 +
  1371 + /* just copy the code */
  1372 +
  1373 + /* no override yet */
  1374 + if (!s->dflag)
  1375 + gb(s, 0x66);
  1376 + if (!s->aflag)
  1377 + gb(s, 0x67);
  1378 + if (prefixes & PREFIX_REPZ)
  1379 + gb(s, 0xf3);
  1380 + else if (prefixes & PREFIX_REPNZ)
  1381 + gb(s, 0xf2);
  1382 + {
  1383 + int len, i;
  1384 + len = s->pc - pc_start_insn;
  1385 + for(i = 0; i < len; i++) {
  1386 + *s->gen_code_ptr++ = ldub_code(pc_start_insn + i);
  1387 + }
  1388 + }
  1389 + no_copy:
  1390 + return 0;
  1391 + illegal_op:
  1392 + unsupported_op:
  1393 + /* fall back to slower code gen necessary */
  1394 + s->pc = pc_start;
  1395 + return -1;
  1396 +}
  1397 +
  1398 +#define GEN_CODE_MAX_SIZE 8192
  1399 +#define GEN_CODE_MAX_INSN_SIZE 512
  1400 +
  1401 +static inline int gen_intermediate_code_internal(CPUState *env,
  1402 + TranslationBlock *tb,
  1403 + uint8_t *gen_code_ptr,
  1404 + int *gen_code_size_ptr,
  1405 + int search_pc,
  1406 + uint8_t *tc_ptr)
  1407 +{
  1408 + DisasContext dc1, *dc = &dc1;
  1409 + uint8_t *pc_insn, *pc_start, *gen_code_end;
  1410 + int flags, ret;
  1411 + uint8_t *cs_base;
  1412 +
  1413 + if (env->nb_breakpoints > 0 ||
  1414 + env->singlestep_enabled)
  1415 + return -1;
  1416 + flags = tb->flags;
  1417 + if (flags & (HF_TF_MASK | HF_ADDSEG_MASK |
  1418 + HF_SOFTMMU_MASK | HF_INHIBIT_IRQ_MASK))
  1419 + return -1;
  1420 + if (!(flags & HF_SS32_MASK))
  1421 + return -1;
  1422 + gen_code_end = gen_code_ptr +
  1423 + GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE;
  1424 + dc->gen_code_ptr = gen_code_ptr;
  1425 + dc->gen_code_start = gen_code_ptr;
  1426 +
  1427 + /* generate intermediate code */
  1428 + pc_start = (uint8_t *)tb->pc;
  1429 + cs_base = (uint8_t *)tb->cs_base;
  1430 + dc->pc = pc_start;
  1431 + dc->cs_base = cs_base;
  1432 + dc->pe = (flags >> HF_PE_SHIFT) & 1;
  1433 + dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
  1434 + dc->f_st = 0;
  1435 + dc->vm86 = (flags >> VM_SHIFT) & 1;
  1436 + dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
  1437 + dc->iopl = (flags >> IOPL_SHIFT) & 3;
  1438 + dc->tb = tb;
  1439 +
  1440 + dc->is_jmp = 0;
  1441 +
  1442 + for(;;) {
  1443 + pc_insn = dc->pc;
  1444 + ret = disas_insn(dc);
  1445 + if (ret < 0) {
  1446 + /* unsupported insn */
  1447 + if (dc->pc == pc_start) {
  1448 + /* if first instruction, signal that no copying was done */
  1449 + return -1;
  1450 + } else {
  1451 + gen_jmp(dc, dc->pc - dc->cs_base);
  1452 + dc->is_jmp = 1;
  1453 + }
  1454 + }
  1455 + if (search_pc) {
  1456 + /* search pc mode */
  1457 + if (tc_ptr < dc->gen_code_ptr) {
  1458 + env->eip = pc_insn - cs_base;
  1459 + return 0;
  1460 + }
  1461 + }
  1462 + /* stop translation if indicated */
  1463 + if (dc->is_jmp)
  1464 + break;
  1465 + /* if too long translation, stop generation */
  1466 + if (dc->gen_code_ptr >= gen_code_end ||
  1467 + (dc->pc - pc_start) >= (TARGET_PAGE_SIZE - 32)) {
  1468 + gen_jmp(dc, dc->pc - dc->cs_base);
  1469 + break;
  1470 + }
  1471 + }
  1472 +
  1473 +#ifdef DEBUG_DISAS
  1474 + if (loglevel) {
  1475 + fprintf(logfile, "----------------\n");
  1476 + fprintf(logfile, "IN: COPY: %s\n", lookup_symbol(pc_start));
  1477 + disas(logfile, pc_start, dc->pc - pc_start, 0, !dc->code32);
  1478 + fprintf(logfile, "\n");
  1479 + }
  1480 +#endif
  1481 +
  1482 + if (!search_pc) {
  1483 + *gen_code_size_ptr = dc->gen_code_ptr - dc->gen_code_start;
  1484 + tb->size = dc->pc - pc_start;
  1485 + tb->cflags = CF_CODE_COPY;
  1486 + return 0;
  1487 + } else {
  1488 + return -1;
  1489 + }
  1490 +}
  1491 +
  1492 +/* generate code by just copying data. Return -1 if cannot generate
  1493 + any code. Return 0 if code was generated */
  1494 +int cpu_gen_code_copy(CPUState *env, TranslationBlock *tb,
  1495 + int max_code_size, int *gen_code_size_ptr)
  1496 +{
  1497 + /* generate machine code */
  1498 + tb->tb_next_offset[0] = 0xffff;
  1499 + tb->tb_next_offset[1] = 0xffff;
  1500 +#ifdef USE_DIRECT_JUMP
  1501 + /* the following two entries are optional (only used for string ops) */
  1502 + tb->tb_jmp_offset[2] = 0xffff;
  1503 + tb->tb_jmp_offset[3] = 0xffff;
  1504 +#endif
  1505 + return gen_intermediate_code_internal(env, tb,
  1506 + tb->tc_ptr, gen_code_size_ptr,
  1507 + 0, NULL);
  1508 +}
  1509 +
  1510 +static uint8_t dummy_gen_code_buf[GEN_CODE_MAX_SIZE];
  1511 +
  1512 +int cpu_restore_state_copy(TranslationBlock *tb,
  1513 + CPUState *env, unsigned long searched_pc,
  1514 + void *puc)
  1515 +{
  1516 + struct ucontext *uc = puc;
  1517 + int ret, eflags;
  1518 +
  1519 + /* find opc index corresponding to search_pc */
  1520 + if (searched_pc < (unsigned long)tb->tc_ptr)
  1521 + return -1;
  1522 + searched_pc = searched_pc - (long)tb->tc_ptr + (long)dummy_gen_code_buf;
  1523 + ret = gen_intermediate_code_internal(env, tb,
  1524 + dummy_gen_code_buf, NULL,
  1525 + 1, (uint8_t *)searched_pc);
  1526 + if (ret < 0)
  1527 + return ret;
  1528 + /* restore all the CPU state from the CPU context from the
  1529 + signal */
  1530 +
  1531 + env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX];
  1532 + env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX];
  1533 + env->regs[R_EDX] = uc->uc_mcontext.gregs[REG_EDX];
  1534 + env->regs[R_EBX] = uc->uc_mcontext.gregs[REG_EBX];
  1535 + env->regs[R_ESP] = uc->uc_mcontext.gregs[REG_ESP];
  1536 + env->regs[R_EBP] = uc->uc_mcontext.gregs[REG_EBP];
  1537 + env->regs[R_ESI] = uc->uc_mcontext.gregs[REG_ESI];
  1538 + env->regs[R_EDI] = uc->uc_mcontext.gregs[REG_EDI];
  1539 + eflags = uc->uc_mcontext.gregs[REG_EFL];
  1540 + env->df = 1 - (2 * ((eflags >> 10) & 1));
  1541 + env->cc_src = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
  1542 + env->cc_op = CC_OP_EFLAGS;
  1543 + return 0;
  1544 +}
... ...
translate-all.c
... ... @@ -48,6 +48,8 @@ uint8_t gen_opc_instr_start[OPC_BUF_SIZE];
48 48 uint8_t gen_opc_cc_op[OPC_BUF_SIZE];
49 49 #endif
50 50  
  51 +int code_copy_enabled = 1;
  52 +
51 53 #ifdef DEBUG_DISAS
52 54 static const char *op_str[] = {
53 55 #define DEF(s, n, copy_size) #s,
... ... @@ -98,30 +100,38 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb,
98 100 uint8_t *gen_code_buf;
99 101 int gen_code_size;
100 102  
101   - if (gen_intermediate_code(env, tb) < 0)
102   - return -1;
  103 +#ifdef USE_CODE_COPY
  104 + if (code_copy_enabled &&
  105 + cpu_gen_code_copy(env, tb, max_code_size, &gen_code_size) == 0) {
  106 + /* nothing more to do */
  107 + } else
  108 +#endif
  109 + {
  110 + if (gen_intermediate_code(env, tb) < 0)
  111 + return -1;
103 112  
104   - /* generate machine code */
105   - tb->tb_next_offset[0] = 0xffff;
106   - tb->tb_next_offset[1] = 0xffff;
107   - gen_code_buf = tb->tc_ptr;
  113 + /* generate machine code */
  114 + tb->tb_next_offset[0] = 0xffff;
  115 + tb->tb_next_offset[1] = 0xffff;
  116 + gen_code_buf = tb->tc_ptr;
108 117 #ifdef USE_DIRECT_JUMP
109   - /* the following two entries are optional (only used for string ops) */
110   - tb->tb_jmp_offset[2] = 0xffff;
111   - tb->tb_jmp_offset[3] = 0xffff;
  118 + /* the following two entries are optional (only used for string ops) */
  119 + tb->tb_jmp_offset[2] = 0xffff;
  120 + tb->tb_jmp_offset[3] = 0xffff;
112 121 #endif
113   - gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
  122 + gen_code_size = dyngen_code(gen_code_buf, tb->tb_next_offset,
114 123 #ifdef USE_DIRECT_JUMP
115   - tb->tb_jmp_offset,
  124 + tb->tb_jmp_offset,
116 125 #else
117   - NULL,
  126 + NULL,
118 127 #endif
119   - gen_opc_buf, gen_opparam_buf);
  128 + gen_opc_buf, gen_opparam_buf);
  129 + }
120 130 *gen_code_size_ptr = gen_code_size;
121 131 #ifdef DEBUG_DISAS
122   - if (loglevel && 0) {
  132 + if (loglevel) {
123 133 fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
124   - disas(logfile, gen_code_buf, *gen_code_size_ptr, 1, 0);
  134 + disas(logfile, tb->tc_ptr, *gen_code_size_ptr, 1, 0);
125 135 fprintf(logfile, "\n");
126 136 fflush(logfile);
127 137 }
... ... @@ -138,12 +148,18 @@ static const unsigned short opc_copy_size[] = {
138 148 /* The cpu state corresponding to 'searched_pc' is restored.
139 149 */
140 150 int cpu_restore_state(TranslationBlock *tb,
141   - CPUState *env, unsigned long searched_pc)
  151 + CPUState *env, unsigned long searched_pc,
  152 + void *puc)
142 153 {
143 154 int j, c;
144 155 unsigned long tc_ptr;
145 156 uint16_t *opc_ptr;
146 157  
  158 +#ifdef USE_CODE_COPY
  159 + if (tb->cflags & CF_CODE_COPY) {
  160 + return cpu_restore_state_copy(tb, env, searched_pc, puc);
  161 + }
  162 +#endif
147 163 if (gen_intermediate_code_pc(env, tb) < 0)
148 164 return -1;
149 165  
... ... @@ -190,6 +206,7 @@ int cpu_restore_state(TranslationBlock *tb,
190 206 #elif defined(TARGET_ARM)
191 207 env->regs[15] = gen_opc_pc[j];
192 208 #elif defined(TARGET_SPARC)
  209 + /* XXX: restore npc too */
193 210 env->pc = gen_opc_pc[j];
194 211 #elif defined(TARGET_PPC)
195 212 {
... ...