VirtualBox

source: vbox/trunk/src/recompiler/target-i386/translate-copy.c@ 11982

Last change on this file since 11982 was 11982, checked in by vboxsync, 16 years ago

All: license header changes for 2.0 (OSE headers, add Sun GPL/LGPL disclaimer)

  • Property svn:eol-style set to native
File size: 34.2 KB
Line 
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
21/*
22 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
23 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
24 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
25 * a choice of LGPL license versions is made available with the language indicating
26 * that LGPLv2 or any later version may be used, or where a choice of which version
27 * of the LGPL is applied is otherwise unspecified.
28 */
29#include "config.h"
30
31#include <stdarg.h>
32#include <stdlib.h>
33#include <stdio.h>
34#include <string.h>
35#include <inttypes.h>
36#include <assert.h>
37
38#include "cpu.h"
39#include "exec-all.h"
40#include "disas.h"
41
42#ifdef USE_CODE_COPY
43
44#include <signal.h>
45#include <sys/mman.h>
46#include <sys/ucontext.h>
47
48extern char exec_loop;
49
50/* operand size */
51enum {
52 OT_BYTE = 0,
53 OT_WORD,
54 OT_LONG,
55 OT_QUAD,
56};
57
58#define PREFIX_REPZ 0x01
59#define PREFIX_REPNZ 0x02
60#define PREFIX_LOCK 0x04
61#define PREFIX_DATA 0x08
62#define PREFIX_ADR 0x10
63
64typedef struct DisasContext {
65 /* current insn context */
66 int override; /* -1 if no override */
67 int prefix;
68 int aflag, dflag;
69 target_ulong pc; /* pc = eip + cs_base */
70 int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
71 static state change (stop translation) */
72 /* code output */
73 uint8_t *gen_code_ptr;
74 uint8_t *gen_code_start;
75
76 /* current block context */
77 target_ulong cs_base; /* base of CS segment */
78 int pe; /* protected mode */
79 int code32; /* 32 bit code segment */
80 int f_st; /* currently unused */
81 int vm86; /* vm86 mode */
82 int cpl;
83 int iopl;
84 int flags;
85 struct TranslationBlock *tb;
86} DisasContext;
87
88#define CPU_FIELD_OFFSET(field) offsetof(CPUState, field)
89
90#define CPU_SEG 0x64 /* fs override */
91
92static inline void gb(DisasContext *s, uint32_t val)
93{
94 *s->gen_code_ptr++ = val;
95}
96
97static inline void gw(DisasContext *s, uint32_t val)
98{
99 *s->gen_code_ptr++ = val;
100 *s->gen_code_ptr++ = val >> 8;
101}
102
103static inline void gl(DisasContext *s, uint32_t val)
104{
105 *s->gen_code_ptr++ = val;
106 *s->gen_code_ptr++ = val >> 8;
107 *s->gen_code_ptr++ = val >> 16;
108 *s->gen_code_ptr++ = val >> 24;
109}
110
111static inline void gjmp(DisasContext *s, long val)
112{
113 gb(s, 0xe9); /* jmp */
114 gl(s, val - (long)(s->gen_code_ptr + 4));
115}
116
117static inline void gen_movl_addr_im(DisasContext *s,
118 uint32_t addr, uint32_t val)
119{
120 gb(s, CPU_SEG); /* seg movl im, addr */
121 gb(s, 0xc7);
122 gb(s, 0x05);
123 gl(s, addr);
124 gl(s, val);
125}
126
127static inline void gen_movw_addr_im(DisasContext *s,
128 uint32_t addr, uint32_t val)
129{
130 gb(s, CPU_SEG); /* seg movl im, addr */
131 gb(s, 0x66);
132 gb(s, 0xc7);
133 gb(s, 0x05);
134 gl(s, addr);
135 gw(s, val);
136}
137
138
139static void gen_jmp(DisasContext *s, uint32_t target_eip)
140{
141 TranslationBlock *tb = s->tb;
142
143 gb(s, 0xe9); /* jmp */
144 tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start;
145 gl(s, 0);
146
147 tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start;
148 gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip);
149 gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb);
150 gjmp(s, (long)&exec_loop);
151
152 s->is_jmp = 1;
153}
154
155static void gen_jcc(DisasContext *s, int op,
156 uint32_t target_eip, uint32_t next_eip)
157{
158 TranslationBlock *tb = s->tb;
159
160 gb(s, 0x0f); /* jcc */
161 gb(s, 0x80 + op);
162 tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start;
163 gl(s, 0);
164 gb(s, 0xe9); /* jmp */
165 tb->tb_jmp_offset[1] = s->gen_code_ptr - s->gen_code_start;
166 gl(s, 0);
167
168 tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start;
169 gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip);
170 gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb);
171 gjmp(s, (long)&exec_loop);
172
173 tb->tb_next_offset[1] = s->gen_code_ptr - s->gen_code_start;
174 gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), next_eip);
175 gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb | 1);
176 gjmp(s, (long)&exec_loop);
177
178 s->is_jmp = 1;
179}
180
181static void gen_eob(DisasContext *s)
182{
183 gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), 0);
184 gjmp(s, (long)&exec_loop);
185
186 s->is_jmp = 1;
187}
188
189static inline void gen_lea_modrm(DisasContext *s, int modrm)
190{
191 int havesib;
192 int base, disp;
193 int index;
194 int scale;
195 int mod, rm, code;
196
197 mod = (modrm >> 6) & 3;
198 rm = modrm & 7;
199
200 if (s->aflag) {
201
202 havesib = 0;
203 base = rm;
204 index = 0;
205 scale = 0;
206
207 if (base == 4) {
208 havesib = 1;
209 code = ldub_code(s->pc++);
210 scale = (code >> 6) & 3;
211 index = (code >> 3) & 7;
212 base = code & 7;
213 }
214
215 switch (mod) {
216 case 0:
217 if (base == 5) {
218 base = -1;
219 disp = ldl_code(s->pc);
220 s->pc += 4;
221 } else {
222 disp = 0;
223 }
224 break;
225 case 1:
226 disp = (int8_t)ldub_code(s->pc++);
227 break;
228 default:
229 case 2:
230 disp = ldl_code(s->pc);
231 s->pc += 4;
232 break;
233 }
234
235 } else {
236 switch (mod) {
237 case 0:
238 if (rm == 6) {
239 disp = lduw_code(s->pc);
240 s->pc += 2;
241 } else {
242 disp = 0;
243 }
244 break;
245 case 1:
246 disp = (int8_t)ldub_code(s->pc++);
247 break;
248 default:
249 case 2:
250 disp = lduw_code(s->pc);
251 s->pc += 2;
252 break;
253 }
254 }
255}
256
257static inline void parse_modrm(DisasContext *s, int modrm)
258{
259 if ((modrm & 0xc0) != 0xc0)
260 gen_lea_modrm(s, modrm);
261}
262
263static inline uint32_t insn_get(DisasContext *s, int ot)
264{
265 uint32_t ret;
266
267 switch(ot) {
268 case OT_BYTE:
269 ret = ldub_code(s->pc);
270 s->pc++;
271 break;
272 case OT_WORD:
273 ret = lduw_code(s->pc);
274 s->pc += 2;
275 break;
276 default:
277 case OT_LONG:
278 ret = ldl_code(s->pc);
279 s->pc += 4;
280 break;
281 }
282 return ret;
283}
284
285/* convert one instruction. s->is_jmp is set if the translation must
286 be stopped. */
287static int disas_insn(DisasContext *s)
288{
289 target_ulong pc_start, pc_tmp, pc_start_insn;
290 int b, prefixes, aflag, dflag, next_eip, val;
291 int ot;
292 int modrm, mod, op, rm;
293
294 pc_start = s->pc;
295 prefixes = 0;
296 aflag = s->code32;
297 dflag = s->code32;
298 s->override = -1;
299 next_byte:
300 b = ldub_code(s->pc);
301 s->pc++;
302 /* check prefixes */
303 switch (b) {
304 case 0xf3:
305 prefixes |= PREFIX_REPZ;
306 goto next_byte;
307 case 0xf2:
308 prefixes |= PREFIX_REPNZ;
309 goto next_byte;
310 case 0xf0:
311 prefixes |= PREFIX_LOCK;
312 goto next_byte;
313 case 0x2e:
314 s->override = R_CS;
315 goto next_byte;
316 case 0x36:
317 s->override = R_SS;
318 goto next_byte;
319 case 0x3e:
320 s->override = R_DS;
321 goto next_byte;
322 case 0x26:
323 s->override = R_ES;
324 goto next_byte;
325 case 0x64:
326 s->override = R_FS;
327 goto next_byte;
328 case 0x65:
329 s->override = R_GS;
330 goto next_byte;
331 case 0x66:
332 prefixes |= PREFIX_DATA;
333 goto next_byte;
334 case 0x67:
335 prefixes |= PREFIX_ADR;
336 goto next_byte;
337 }
338
339 if (prefixes & PREFIX_DATA)
340 dflag ^= 1;
341 if (prefixes & PREFIX_ADR)
342 aflag ^= 1;
343
344 s->prefix = prefixes;
345 s->aflag = aflag;
346 s->dflag = dflag;
347
348 /* lock generation */
349 if (prefixes & PREFIX_LOCK)
350 goto unsupported_op;
351 if (s->override == R_FS || s->override == R_GS || s->override == R_CS)
352 goto unsupported_op;
353
354 pc_start_insn = s->pc - 1;
355 /* now check op code */
356 reswitch:
357 switch(b) {
358 case 0x0f:
359 /**************************/
360 /* extended op code */
361 b = ldub_code(s->pc++) | 0x100;
362 goto reswitch;
363
364 /**************************/
365 /* arith & logic */
366 case 0x00 ... 0x05:
367 case 0x08 ... 0x0d:
368 case 0x10 ... 0x15:
369 case 0x18 ... 0x1d:
370 case 0x20 ... 0x25:
371 case 0x28 ... 0x2d:
372 case 0x30 ... 0x35:
373 case 0x38 ... 0x3d:
374 {
375 int f;
376 f = (b >> 1) & 3;
377
378 if ((b & 1) == 0)
379 ot = OT_BYTE;
380 else
381 ot = dflag ? OT_LONG : OT_WORD;
382
383 switch(f) {
384 case 0: /* OP Ev, Gv */
385 modrm = ldub_code(s->pc++);
386 parse_modrm(s, modrm);
387 break;
388 case 1: /* OP Gv, Ev */
389 modrm = ldub_code(s->pc++);
390 parse_modrm(s, modrm);
391 break;
392 case 2: /* OP A, Iv */
393 insn_get(s, ot);
394 break;
395 }
396 }
397 break;
398
399 case 0x80: /* GRP1 */
400 case 0x81:
401 case 0x82:
402 case 0x83:
403 {
404 if ((b & 1) == 0)
405 ot = OT_BYTE;
406 else
407 ot = dflag ? OT_LONG : OT_WORD;
408
409 modrm = ldub_code(s->pc++);
410 parse_modrm(s, modrm);
411
412 switch(b) {
413 default:
414 case 0x80:
415 case 0x81:
416 case 0x82:
417 insn_get(s, ot);
418 break;
419 case 0x83:
420 insn_get(s, OT_BYTE);
421 break;
422 }
423 }
424 break;
425
426 /**************************/
427 /* inc, dec, and other misc arith */
428 case 0x40 ... 0x47: /* inc Gv */
429 break;
430 case 0x48 ... 0x4f: /* dec Gv */
431 break;
432 case 0xf6: /* GRP3 */
433 case 0xf7:
434 if ((b & 1) == 0)
435 ot = OT_BYTE;
436 else
437 ot = dflag ? OT_LONG : OT_WORD;
438
439 modrm = ldub_code(s->pc++);
440 op = (modrm >> 3) & 7;
441 parse_modrm(s, modrm);
442
443 switch(op) {
444 case 0: /* test */
445 insn_get(s, ot);
446 break;
447 case 2: /* not */
448 break;
449 case 3: /* neg */
450 break;
451 case 4: /* mul */
452 break;
453 case 5: /* imul */
454 break;
455 case 6: /* div */
456 break;
457 case 7: /* idiv */
458 break;
459 default:
460 goto illegal_op;
461 }
462 break;
463
464 case 0xfe: /* GRP4 */
465 case 0xff: /* GRP5 */
466 if ((b & 1) == 0)
467 ot = OT_BYTE;
468 else
469 ot = dflag ? OT_LONG : OT_WORD;
470
471 modrm = ldub_code(s->pc++);
472 mod = (modrm >> 6) & 3;
473 op = (modrm >> 3) & 7;
474 if (op >= 2 && b == 0xfe) {
475 goto illegal_op;
476 }
477 pc_tmp = s->pc;
478 parse_modrm(s, modrm);
479
480 switch(op) {
481 case 0: /* inc Ev */
482 break;
483 case 1: /* dec Ev */
484 break;
485 case 2: /* call Ev */
486 /* XXX: optimize and handle MEM exceptions specifically
487 fs movl %eax, regs[0]
488 movl Ev, %eax
489 pushl next_eip
490 fs movl %eax, eip
491 */
492 goto unsupported_op;
493 case 3: /* lcall Ev */
494 goto unsupported_op;
495 case 4: /* jmp Ev */
496 /* XXX: optimize and handle MEM exceptions specifically
497 fs movl %eax, regs[0]
498 movl Ev, %eax
499 fs movl %eax, eip
500 */
501 goto unsupported_op;
502 case 5: /* ljmp Ev */
503 goto unsupported_op;
504 case 6: /* push Ev */
505 break;
506 default:
507 goto illegal_op;
508 }
509 break;
510 case 0xa8: /* test eAX, Iv */
511 case 0xa9:
512 if ((b & 1) == 0)
513 ot = OT_BYTE;
514 else
515 ot = dflag ? OT_LONG : OT_WORD;
516 insn_get(s, ot);
517 break;
518
519 case 0x98: /* CWDE/CBW */
520 break;
521 case 0x99: /* CDQ/CWD */
522 break;
523 case 0x1af: /* imul Gv, Ev */
524 case 0x69: /* imul Gv, Ev, I */
525 case 0x6b:
526 ot = dflag ? OT_LONG : OT_WORD;
527 modrm = ldub_code(s->pc++);
528 parse_modrm(s, modrm);
529 if (b == 0x69) {
530 insn_get(s, ot);
531 } else if (b == 0x6b) {
532 insn_get(s, OT_BYTE);
533 } else {
534 }
535 break;
536
537 case 0x84: /* test Ev, Gv */
538 case 0x85:
539
540 case 0x1c0:
541 case 0x1c1: /* xadd Ev, Gv */
542
543 case 0x1b0:
544 case 0x1b1: /* cmpxchg Ev, Gv */
545
546 case 0x8f: /* pop Ev */
547
548 case 0x88:
549 case 0x89: /* mov Gv, Ev */
550
551 case 0x8a:
552 case 0x8b: /* mov Ev, Gv */
553
554 case 0x1b6: /* movzbS Gv, Eb */
555 case 0x1b7: /* movzwS Gv, Eb */
556 case 0x1be: /* movsbS Gv, Eb */
557 case 0x1bf: /* movswS Gv, Eb */
558
559 case 0x86:
560 case 0x87: /* xchg Ev, Gv */
561
562 case 0xd0:
563 case 0xd1: /* shift Ev,1 */
564
565 case 0xd2:
566 case 0xd3: /* shift Ev,cl */
567
568 case 0x1a5: /* shld cl */
569 case 0x1ad: /* shrd cl */
570
571 case 0x190 ... 0x19f: /* setcc Gv */
572
573 /* XXX: emulate cmov if not available ? */
574 case 0x140 ... 0x14f: /* cmov Gv, Ev */
575
576 case 0x1a3: /* bt Gv, Ev */
577 case 0x1ab: /* bts */
578 case 0x1b3: /* btr */
579 case 0x1bb: /* btc */
580
581 case 0x1bc: /* bsf */
582 case 0x1bd: /* bsr */
583
584 modrm = ldub_code(s->pc++);
585 parse_modrm(s, modrm);
586 break;
587
588 case 0x1c7: /* cmpxchg8b */
589 modrm = ldub_code(s->pc++);
590 mod = (modrm >> 6) & 3;
591 if (mod == 3)
592 goto illegal_op;
593 parse_modrm(s, modrm);
594 break;
595
596 /**************************/
597 /* push/pop */
598 case 0x50 ... 0x57: /* push */
599 case 0x58 ... 0x5f: /* pop */
600 case 0x60: /* pusha */
601 case 0x61: /* popa */
602 break;
603
604 case 0x68: /* push Iv */
605 case 0x6a:
606 ot = dflag ? OT_LONG : OT_WORD;
607 if (b == 0x68)
608 insn_get(s, ot);
609 else
610 insn_get(s, OT_BYTE);
611 break;
612 case 0xc8: /* enter */
613 lduw_code(s->pc);
614 s->pc += 2;
615 ldub_code(s->pc++);
616 break;
617 case 0xc9: /* leave */
618 break;
619
620 case 0x06: /* push es */
621 case 0x0e: /* push cs */
622 case 0x16: /* push ss */
623 case 0x1e: /* push ds */
624 /* XXX: optimize:
625 push segs[n].selector
626 */
627 goto unsupported_op;
628 case 0x1a0: /* push fs */
629 case 0x1a8: /* push gs */
630 goto unsupported_op;
631 case 0x07: /* pop es */
632 case 0x17: /* pop ss */
633 case 0x1f: /* pop ds */
634 goto unsupported_op;
635 case 0x1a1: /* pop fs */
636 case 0x1a9: /* pop gs */
637 goto unsupported_op;
638 case 0x8e: /* mov seg, Gv */
639 /* XXX: optimize:
640 fs movl r, regs[]
641 movl segs[].selector, r
642 mov r, Gv
643 fs movl regs[], r
644 */
645 goto unsupported_op;
646 case 0x8c: /* mov Gv, seg */
647 goto unsupported_op;
648 case 0xc4: /* les Gv */
649 op = R_ES;
650 goto do_lxx;
651 case 0xc5: /* lds Gv */
652 op = R_DS;
653 goto do_lxx;
654 case 0x1b2: /* lss Gv */
655 op = R_SS;
656 goto do_lxx;
657 case 0x1b4: /* lfs Gv */
658 op = R_FS;
659 goto do_lxx;
660 case 0x1b5: /* lgs Gv */
661 op = R_GS;
662 do_lxx:
663 goto unsupported_op;
664 /************************/
665 /* floats */
666 case 0xd8 ... 0xdf:
667#if 1
668 /* currently not stable enough */
669 goto unsupported_op;
670#else
671 if (s->flags & (HF_EM_MASK | HF_TS_MASK))
672 goto unsupported_op;
673#endif
674#if 0
675 /* for testing FPU context switch */
676 {
677 static int count;
678 count = (count + 1) % 3;
679 if (count != 0)
680 goto unsupported_op;
681 }
682#endif
683 modrm = ldub_code(s->pc++);
684 mod = (modrm >> 6) & 3;
685 rm = modrm & 7;
686 op = ((b & 7) << 3) | ((modrm >> 3) & 7);
687 if (mod != 3) {
688 /* memory op */
689 parse_modrm(s, modrm);
690 switch(op) {
691 case 0x00 ... 0x07: /* fxxxs */
692 case 0x10 ... 0x17: /* fixxxl */
693 case 0x20 ... 0x27: /* fxxxl */
694 case 0x30 ... 0x37: /* fixxx */
695 break;
696 case 0x08: /* flds */
697 case 0x0a: /* fsts */
698 case 0x0b: /* fstps */
699 case 0x18: /* fildl */
700 case 0x1a: /* fistl */
701 case 0x1b: /* fistpl */
702 case 0x28: /* fldl */
703 case 0x2a: /* fstl */
704 case 0x2b: /* fstpl */
705 case 0x38: /* filds */
706 case 0x3a: /* fists */
707 case 0x3b: /* fistps */
708 case 0x0c: /* fldenv mem */
709 case 0x0d: /* fldcw mem */
710 case 0x0e: /* fnstenv mem */
711 case 0x0f: /* fnstcw mem */
712 case 0x1d: /* fldt mem */
713 case 0x1f: /* fstpt mem */
714 case 0x2c: /* frstor mem */
715 case 0x2e: /* fnsave mem */
716 case 0x2f: /* fnstsw mem */
717 case 0x3c: /* fbld */
718 case 0x3e: /* fbstp */
719 case 0x3d: /* fildll */
720 case 0x3f: /* fistpll */
721 break;
722 default:
723 goto illegal_op;
724 }
725 } else {
726 /* register float ops */
727 switch(op) {
728 case 0x08: /* fld sti */
729 case 0x09: /* fxchg sti */
730 break;
731 case 0x0a: /* grp d9/2 */
732 switch(rm) {
733 case 0: /* fnop */
734 break;
735 default:
736 goto illegal_op;
737 }
738 break;
739 case 0x0c: /* grp d9/4 */
740 switch(rm) {
741 case 0: /* fchs */
742 case 1: /* fabs */
743 case 4: /* ftst */
744 case 5: /* fxam */
745 break;
746 default:
747 goto illegal_op;
748 }
749 break;
750 case 0x0d: /* grp d9/5 */
751 switch(rm) {
752 case 0:
753 case 1:
754 case 2:
755 case 3:
756 case 4:
757 case 5:
758 case 6:
759 break;
760 default:
761 goto illegal_op;
762 }
763 break;
764 case 0x0e: /* grp d9/6 */
765 break;
766 case 0x0f: /* grp d9/7 */
767 break;
768 case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
769 case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
770 case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
771 break;
772 case 0x02: /* fcom */
773 break;
774 case 0x03: /* fcomp */
775 break;
776 case 0x15: /* da/5 */
777 switch(rm) {
778 case 1: /* fucompp */
779 break;
780 default:
781 goto illegal_op;
782 }
783 break;
784 case 0x1c:
785 switch(rm) {
786 case 0: /* feni (287 only, just do nop here) */
787 case 1: /* fdisi (287 only, just do nop here) */
788 goto unsupported_op;
789 case 2: /* fclex */
790 case 3: /* fninit */
791 case 4: /* fsetpm (287 only, just do nop here) */
792 break;
793 default:
794 goto illegal_op;
795 }
796 break;
797 case 0x1d: /* fucomi */
798 break;
799 case 0x1e: /* fcomi */
800 break;
801 case 0x28: /* ffree sti */
802 break;
803 case 0x2a: /* fst sti */
804 break;
805 case 0x2b: /* fstp sti */
806 break;
807 case 0x2c: /* fucom st(i) */
808 break;
809 case 0x2d: /* fucomp st(i) */
810 break;
811 case 0x33: /* de/3 */
812 switch(rm) {
813 case 1: /* fcompp */
814 break;
815 default:
816 goto illegal_op;
817 }
818 break;
819 case 0x3c: /* df/4 */
820 switch(rm) {
821 case 0:
822 break;
823 default:
824 goto illegal_op;
825 }
826 break;
827 case 0x3d: /* fucomip */
828 break;
829 case 0x3e: /* fcomip */
830 break;
831 case 0x10 ... 0x13: /* fcmovxx */
832 case 0x18 ... 0x1b:
833 break;
834 default:
835 goto illegal_op;
836 }
837 }
838 s->tb->cflags |= CF_TB_FP_USED;
839 break;
840
841 /**************************/
842 /* mov */
843 case 0xc6:
844 case 0xc7: /* mov Ev, Iv */
845 if ((b & 1) == 0)
846 ot = OT_BYTE;
847 else
848 ot = dflag ? OT_LONG : OT_WORD;
849 modrm = ldub_code(s->pc++);
850 parse_modrm(s, modrm);
851 insn_get(s, ot);
852 break;
853
854 case 0x8d: /* lea */
855 ot = dflag ? OT_LONG : OT_WORD;
856 modrm = ldub_code(s->pc++);
857 mod = (modrm >> 6) & 3;
858 if (mod == 3)
859 goto illegal_op;
860 parse_modrm(s, modrm);
861 break;
862
863 case 0xa0: /* mov EAX, Ov */
864 case 0xa1:
865 case 0xa2: /* mov Ov, EAX */
866 case 0xa3:
867 if ((b & 1) == 0)
868 ot = OT_BYTE;
869 else
870 ot = dflag ? OT_LONG : OT_WORD;
871 if (s->aflag)
872 insn_get(s, OT_LONG);
873 else
874 insn_get(s, OT_WORD);
875 break;
876 case 0xd7: /* xlat */
877 break;
878 case 0xb0 ... 0xb7: /* mov R, Ib */
879 insn_get(s, OT_BYTE);
880 break;
881 case 0xb8 ... 0xbf: /* mov R, Iv */
882 ot = dflag ? OT_LONG : OT_WORD;
883 insn_get(s, ot);
884 break;
885
886 case 0x91 ... 0x97: /* xchg R, EAX */
887 break;
888
889 /************************/
890 /* shifts */
891 case 0xc0:
892 case 0xc1: /* shift Ev,imm */
893
894 case 0x1a4: /* shld imm */
895 case 0x1ac: /* shrd imm */
896 modrm = ldub_code(s->pc++);
897 parse_modrm(s, modrm);
898 ldub_code(s->pc++);
899 break;
900
901 /************************/
902 /* string ops */
903
904 case 0xa4: /* movsS */
905 case 0xa5:
906 break;
907
908 case 0xaa: /* stosS */
909 case 0xab:
910 break;
911
912 case 0xac: /* lodsS */
913 case 0xad:
914 break;
915
916 case 0xae: /* scasS */
917 case 0xaf:
918 break;
919
920 case 0xa6: /* cmpsS */
921 case 0xa7:
922 break;
923
924 case 0x6c: /* insS */
925 case 0x6d:
926 goto unsupported_op;
927
928 case 0x6e: /* outsS */
929 case 0x6f:
930 goto unsupported_op;
931
932 /************************/
933 /* port I/O */
934 case 0xe4:
935 case 0xe5:
936 goto unsupported_op;
937
938 case 0xe6:
939 case 0xe7:
940 goto unsupported_op;
941
942 case 0xec:
943 case 0xed:
944 goto unsupported_op;
945
946 case 0xee:
947 case 0xef:
948 goto unsupported_op;
949
950 /************************/
951 /* control */
952#if 0
953 case 0xc2: /* ret im */
954 val = ldsw_code(s->pc);
955 s->pc += 2;
956 gen_pop_T0(s);
957 gen_stack_update(s, val + (2 << s->dflag));
958 if (s->dflag == 0)
959 gen_op_andl_T0_ffff();
960 gen_op_jmp_T0();
961 gen_eob(s);
962 break;
963#endif
964
965 case 0xc3: /* ret */
966 gb(s, CPU_SEG);
967 if (!s->dflag)
968 gb(s, 0x66); /* d16 */
969 gb(s, 0x8f); /* pop addr */
970 gb(s, 0x05);
971 gl(s, CPU_FIELD_OFFSET(eip));
972 if (!s->dflag) {
973 /* reset high bits of EIP */
974 gen_movw_addr_im(s, CPU_FIELD_OFFSET(eip) + 2, 0);
975 }
976 gen_eob(s);
977 goto no_copy;
978 case 0xca: /* lret im */
979 case 0xcb: /* lret */
980 case 0xcf: /* iret */
981 case 0x9a: /* lcall im */
982 case 0xea: /* ljmp im */
983 goto unsupported_op;
984
985 case 0xe8: /* call im */
986 ot = dflag ? OT_LONG : OT_WORD;
987 val = insn_get(s, ot);
988 next_eip = s->pc - s->cs_base;
989 val += next_eip;
990 if (s->dflag) {
991 gb(s, 0x68); /* pushl imm */
992 gl(s, next_eip);
993 } else {
994 gb(s, 0x66); /* pushw imm */
995 gb(s, 0x68);
996 gw(s, next_eip);
997 val &= 0xffff;
998 }
999 gen_jmp(s, val);
1000 goto no_copy;
1001 case 0xe9: /* jmp */
1002 ot = dflag ? OT_LONG : OT_WORD;
1003 val = insn_get(s, ot);
1004 val += s->pc - s->cs_base;
1005 if (s->dflag == 0)
1006 val = val & 0xffff;
1007 gen_jmp(s, val);
1008 goto no_copy;
1009 case 0xeb: /* jmp Jb */
1010 val = (int8_t)insn_get(s, OT_BYTE);
1011 val += s->pc - s->cs_base;
1012 if (s->dflag == 0)
1013 val = val & 0xffff;
1014 gen_jmp(s, val);
1015 goto no_copy;
1016 case 0x70 ... 0x7f: /* jcc Jb */
1017 val = (int8_t)insn_get(s, OT_BYTE);
1018 goto do_jcc;
1019 case 0x180 ... 0x18f: /* jcc Jv */
1020 if (dflag) {
1021 val = insn_get(s, OT_LONG);
1022 } else {
1023 val = (int16_t)insn_get(s, OT_WORD);
1024 }
1025 do_jcc:
1026 next_eip = s->pc - s->cs_base;
1027 val += next_eip;
1028 if (s->dflag == 0)
1029 val &= 0xffff;
1030 gen_jcc(s, b & 0xf, val, next_eip);
1031 goto no_copy;
1032
1033 /************************/
1034 /* flags */
1035 case 0x9c: /* pushf */
1036 /* XXX: put specific code ? */
1037 goto unsupported_op;
1038 case 0x9d: /* popf */
1039 goto unsupported_op;
1040
1041 case 0x9e: /* sahf */
1042 case 0x9f: /* lahf */
1043 case 0xf5: /* cmc */
1044 case 0xf8: /* clc */
1045 case 0xf9: /* stc */
1046 case 0xfc: /* cld */
1047 case 0xfd: /* std */
1048 break;
1049
1050 /************************/
1051 /* bit operations */
1052 case 0x1ba: /* bt/bts/btr/btc Gv, im */
1053 ot = dflag ? OT_LONG : OT_WORD;
1054 modrm = ldub_code(s->pc++);
1055 op = (modrm >> 3) & 7;
1056 parse_modrm(s, modrm);
1057 /* load shift */
1058 ldub_code(s->pc++);
1059 if (op < 4)
1060 goto illegal_op;
1061 break;
1062 /************************/
1063 /* bcd */
1064 case 0x27: /* daa */
1065 break;
1066 case 0x2f: /* das */
1067 break;
1068 case 0x37: /* aaa */
1069 break;
1070 case 0x3f: /* aas */
1071 break;
1072 case 0xd4: /* aam */
1073 ldub_code(s->pc++);
1074 break;
1075 case 0xd5: /* aad */
1076 ldub_code(s->pc++);
1077 break;
1078 /************************/
1079 /* misc */
1080 case 0x90: /* nop */
1081 break;
1082 case 0x9b: /* fwait */
1083 if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
1084 (HF_MP_MASK | HF_TS_MASK)) {
1085 goto unsupported_op;
1086 }
1087 break;
1088 case 0xcc: /* int3 */
1089 goto unsupported_op;
1090 case 0xcd: /* int N */
1091 goto unsupported_op;
1092 case 0xce: /* into */
1093 goto unsupported_op;
1094 case 0xf1: /* icebp (undocumented, exits to external debugger) */
1095 goto unsupported_op;
1096 case 0xfa: /* cli */
1097 goto unsupported_op;
1098 case 0xfb: /* sti */
1099 goto unsupported_op;
1100 case 0x62: /* bound */
1101 modrm = ldub_code(s->pc++);
1102 mod = (modrm >> 6) & 3;
1103 if (mod == 3)
1104 goto illegal_op;
1105 parse_modrm(s, modrm);
1106 break;
1107 case 0x1c8 ... 0x1cf: /* bswap reg */
1108 break;
1109 case 0xd6: /* salc */
1110 break;
1111 case 0xe0: /* loopnz */
1112 case 0xe1: /* loopz */
1113 case 0xe2: /* loop */
1114 case 0xe3: /* jecxz */
1115 goto unsupported_op;
1116
1117 case 0x130: /* wrmsr */
1118 case 0x132: /* rdmsr */
1119 goto unsupported_op;
1120 case 0x131: /* rdtsc */
1121 goto unsupported_op;
1122 case 0x1a2: /* cpuid */
1123 goto unsupported_op;
1124 case 0xf4: /* hlt */
1125 goto unsupported_op;
1126 case 0x100:
1127 goto unsupported_op;
1128 case 0x101:
1129 goto unsupported_op;
1130 case 0x108: /* invd */
1131 case 0x109: /* wbinvd */
1132 goto unsupported_op;
1133 case 0x63: /* arpl */
1134 goto unsupported_op;
1135 case 0x102: /* lar */
1136 case 0x103: /* lsl */
1137 goto unsupported_op;
1138 case 0x118:
1139 goto unsupported_op;
1140 case 0x120: /* mov reg, crN */
1141 case 0x122: /* mov crN, reg */
1142 goto unsupported_op;
1143 case 0x121: /* mov reg, drN */
1144 case 0x123: /* mov drN, reg */
1145 goto unsupported_op;
1146 case 0x106: /* clts */
1147 goto unsupported_op;
1148 default:
1149 goto illegal_op;
1150 }
1151
1152 /* just copy the code */
1153
1154 /* no override yet */
1155 if (!s->dflag)
1156 gb(s, 0x66);
1157 if (!s->aflag)
1158 gb(s, 0x67);
1159 if (prefixes & PREFIX_REPZ)
1160 gb(s, 0xf3);
1161 else if (prefixes & PREFIX_REPNZ)
1162 gb(s, 0xf2);
1163 {
1164 int len, i;
1165 len = s->pc - pc_start_insn;
1166 for(i = 0; i < len; i++) {
1167 *s->gen_code_ptr++ = ldub_code(pc_start_insn + i);
1168 }
1169 }
1170 no_copy:
1171 return 0;
1172 illegal_op:
1173 unsupported_op:
1174 /* fall back to slower code gen necessary */
1175 s->pc = pc_start;
1176 return -1;
1177}
1178
1179#define GEN_CODE_MAX_SIZE 8192
1180#define GEN_CODE_MAX_INSN_SIZE 512
1181
1182static inline int gen_intermediate_code_internal(CPUState *env,
1183 TranslationBlock *tb,
1184 uint8_t *gen_code_ptr,
1185 int *gen_code_size_ptr,
1186 int search_pc,
1187 uint8_t *tc_ptr)
1188{
1189 DisasContext dc1, *dc = &dc1;
1190 target_ulong pc_insn, pc_start, cs_base;
1191 uint8_t *gen_code_end;
1192 int flags, ret;
1193
1194 if (env->nb_breakpoints > 0 ||
1195 env->singlestep_enabled)
1196 return -1;
1197 flags = tb->flags;
1198 if (flags & (HF_TF_MASK | HF_ADDSEG_MASK |
1199 HF_SOFTMMU_MASK | HF_INHIBIT_IRQ_MASK))
1200 return -1;
1201 if (!(flags & HF_SS32_MASK))
1202 return -1;
1203 if (tb->cflags & CF_SINGLE_INSN)
1204 return -1;
1205 gen_code_end = gen_code_ptr +
1206 GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE;
1207 dc->gen_code_ptr = gen_code_ptr;
1208 dc->gen_code_start = gen_code_ptr;
1209
1210 /* generate intermediate code */
1211 pc_start = tb->pc;
1212 cs_base = tb->cs_base;
1213 dc->pc = pc_start;
1214 dc->cs_base = cs_base;
1215 dc->pe = (flags >> HF_PE_SHIFT) & 1;
1216 dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
1217 dc->f_st = 0;
1218 dc->vm86 = (flags >> VM_SHIFT) & 1;
1219 dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
1220 dc->iopl = (flags >> IOPL_SHIFT) & 3;
1221 dc->tb = tb;
1222 dc->flags = flags;
1223
1224 dc->is_jmp = 0;
1225
1226 for(;;) {
1227 pc_insn = dc->pc;
1228 ret = disas_insn(dc);
1229 if (ret < 0) {
1230 /* unsupported insn */
1231 if (dc->pc == pc_start) {
1232 /* if first instruction, signal that no copying was done */
1233 return -1;
1234 } else {
1235 gen_jmp(dc, dc->pc - dc->cs_base);
1236 dc->is_jmp = 1;
1237 }
1238 }
1239 if (search_pc) {
1240 /* search pc mode */
1241 if (tc_ptr < dc->gen_code_ptr) {
1242 env->eip = pc_insn - cs_base;
1243 return 0;
1244 }
1245 }
1246 /* stop translation if indicated */
1247 if (dc->is_jmp)
1248 break;
1249 /* if too long translation, stop generation */
1250 if (dc->gen_code_ptr >= gen_code_end ||
1251 (dc->pc - pc_start) >= (TARGET_PAGE_SIZE - 32)) {
1252 gen_jmp(dc, dc->pc - dc->cs_base);
1253 break;
1254 }
1255 }
1256
1257#ifdef DEBUG_DISAS
1258 if (loglevel & CPU_LOG_TB_IN_ASM) {
1259 fprintf(logfile, "----------------\n");
1260 fprintf(logfile, "IN: COPY: %s fpu=%d\n",
1261 lookup_symbol(pc_start),
1262 tb->cflags & CF_TB_FP_USED ? 1 : 0);
1263 target_disas(logfile, pc_start, dc->pc - pc_start, !dc->code32);
1264 fprintf(logfile, "\n");
1265 }
1266#endif
1267
1268 if (!search_pc) {
1269 *gen_code_size_ptr = dc->gen_code_ptr - dc->gen_code_start;
1270 tb->size = dc->pc - pc_start;
1271 tb->cflags |= CF_CODE_COPY;
1272 return 0;
1273 } else {
1274 return -1;
1275 }
1276}
1277
1278/* generate code by just copying data. Return -1 if cannot generate
1279 any code. Return 0 if code was generated */
1280int cpu_gen_code_copy(CPUState *env, TranslationBlock *tb,
1281 int max_code_size, int *gen_code_size_ptr)
1282{
1283 /* generate machine code */
1284 tb->tb_next_offset[0] = 0xffff;
1285 tb->tb_next_offset[1] = 0xffff;
1286#ifdef USE_DIRECT_JUMP
1287 /* the following two entries are optional (only used for string ops) */
1288 tb->tb_jmp_offset[2] = 0xffff;
1289 tb->tb_jmp_offset[3] = 0xffff;
1290#endif
1291 return gen_intermediate_code_internal(env, tb,
1292 tb->tc_ptr, gen_code_size_ptr,
1293 0, NULL);
1294}
1295
1296static uint8_t dummy_gen_code_buf[GEN_CODE_MAX_SIZE];
1297
1298int cpu_restore_state_copy(TranslationBlock *tb,
1299 CPUState *env, unsigned long searched_pc,
1300 void *puc)
1301{
1302 struct ucontext *uc = puc;
1303 int ret, eflags;
1304
1305 /* find opc index corresponding to search_pc */
1306 if (searched_pc < (unsigned long)tb->tc_ptr)
1307 return -1;
1308 searched_pc = searched_pc - (long)tb->tc_ptr + (long)dummy_gen_code_buf;
1309 ret = gen_intermediate_code_internal(env, tb,
1310 dummy_gen_code_buf, NULL,
1311 1, (uint8_t *)searched_pc);
1312 if (ret < 0)
1313 return ret;
1314 /* restore all the CPU state from the CPU context from the
1315 signal. The FPU context stays in the host CPU. */
1316
1317 env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX];
1318 env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX];
1319 env->regs[R_EDX] = uc->uc_mcontext.gregs[REG_EDX];
1320 env->regs[R_EBX] = uc->uc_mcontext.gregs[REG_EBX];
1321 env->regs[R_ESP] = uc->uc_mcontext.gregs[REG_ESP];
1322 env->regs[R_EBP] = uc->uc_mcontext.gregs[REG_EBP];
1323 env->regs[R_ESI] = uc->uc_mcontext.gregs[REG_ESI];
1324 env->regs[R_EDI] = uc->uc_mcontext.gregs[REG_EDI];
1325 eflags = uc->uc_mcontext.gregs[REG_EFL];
1326 env->df = 1 - (2 * ((eflags >> 10) & 1));
1327 env->cc_src = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
1328 env->cc_op = CC_OP_EFLAGS;
1329 return 0;
1330}
1331
1332#endif /* USE_CODE_COPY */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette