]> git.proxmox.com Git - qemu.git/blobdiff - translate-i386.c
added getrusage
[qemu.git] / translate-i386.c
index ba36bedf9e7c8d9de5cb9fe464ff61072aefcc76..32e188bbb7731e507098853e09e6bba222d61169 100644 (file)
 #define IN_OP_I386
 #include "cpu-i386.h"
 
-#ifndef offsetof
-#define offsetof(type, field) ((size_t) &((type *)0)->field)
-#endif
-
 /* XXX: move that elsewhere */
 static uint16_t *gen_opc_ptr;
 static uint32_t *gen_opparam_ptr;
@@ -132,6 +128,7 @@ typedef struct DisasContext {
     int vm86;   /* vm86 mode */
     int cpl;
     int iopl;
+    int tf;     /* TF cpu flag */
 } DisasContext;
 
 /* i386 arith/logic operations */
@@ -1366,6 +1363,15 @@ static void gen_enter(DisasContext *s, int esp_addend, int level)
     gen_op_mov_reg_T1[ot][R_ESP]();
 }
 
+static void gen_exception(DisasContext *s, int trapno, unsigned int cur_eip)
+{
+    if (s->cc_op != CC_OP_DYNAMIC)
+        gen_op_set_cc_op(s->cc_op);
+    gen_op_jmp_im(cur_eip);
+    gen_op_raise_exception(trapno);
+    s->is_jmp = 1;
+}
+
 /* return the next pc address. Return -1 if no insn found. *is_jmp_ptr
    is set to true if the instruction sets the PC (last instruction of
    a basic block) */
@@ -2770,8 +2776,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0x6d:
         if (s->cpl > s->iopl || s->vm86) {
             /* NOTE: even for (E)CX = 0 the exception is raised */
-            gen_op_gpf(pc_start - s->cs_base);
-            s->is_jmp = 1;
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if ((b & 1) == 0)
                 ot = OT_BYTE;
@@ -2788,8 +2793,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0x6f:
         if (s->cpl > s->iopl || s->vm86) {
             /* NOTE: even for (E)CX = 0 the exception is raised */
-            gen_op_gpf(pc_start - s->cs_base);
-            s->is_jmp = 1;
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if ((b & 1) == 0)
                 ot = OT_BYTE;
@@ -2808,8 +2812,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0xe4:
     case 0xe5:
         if (s->cpl > s->iopl || s->vm86) {
-            gen_op_gpf(pc_start - s->cs_base);
-            s->is_jmp = 1;
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if ((b & 1) == 0)
                 ot = OT_BYTE;
@@ -2824,8 +2827,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0xe6:
     case 0xe7:
         if (s->cpl > s->iopl || s->vm86) {
-            gen_op_gpf(pc_start - s->cs_base);
-            s->is_jmp = 1;
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if ((b & 1) == 0)
                 ot = OT_BYTE;
@@ -2840,8 +2842,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0xec:
     case 0xed:
         if (s->cpl > s->iopl || s->vm86) {
-            gen_op_gpf(pc_start - s->cs_base);
-            s->is_jmp = 1;
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if ((b & 1) == 0)
                 ot = OT_BYTE;
@@ -2855,8 +2856,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0xee:
     case 0xef:
         if (s->cpl > s->iopl || s->vm86) {
-            gen_op_gpf(pc_start - s->cs_base);
-            s->is_jmp = 1;
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if ((b & 1) == 0)
                 ot = OT_BYTE;
@@ -2928,8 +2928,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         break;
     case 0xcf: /* iret */
         if (s->vm86 && s->iopl != 3) {
-            gen_op_gpf(pc_start - s->cs_base);
-            s->is_jmp = 1;
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             /* XXX: not restartable */
             /* pop offset */
@@ -3066,8 +3065,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         /* flags */
     case 0x9c: /* pushf */
         if (s->vm86 && s->iopl != 3) {
-            gen_op_gpf(pc_start - s->cs_base);
-            s->is_jmp = 1;
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if (s->cc_op != CC_OP_DYNAMIC)
                 gen_op_set_cc_op(s->cc_op);
@@ -3077,8 +3075,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         break;
     case 0x9d: /* popf */
         if (s->vm86 && s->iopl != 3) {
-            gen_op_gpf(pc_start - s->cs_base);
-            s->is_jmp = 1;
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             gen_pop_T0(s);
             if (s->dflag) {
@@ -3088,6 +3085,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
             }
             gen_pop_update(s);
             s->cc_op = CC_OP_EFLAGS;
+            s->is_jmp = 2; /* abort translation because TF flag may change */
         }
         break;
     case 0x9e: /* sahf */
@@ -3248,33 +3246,32 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
     case 0x90: /* nop */
         break;
     case 0xcc: /* int3 */
-        gen_op_int3((long)pc_start);
-        s->is_jmp = 1;
+        gen_exception(s, EXCP03_INT3, s->pc - s->cs_base);
         break;
     case 0xcd: /* int N */
         val = ldub(s->pc++);
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
         gen_op_int_im(val, pc_start - s->cs_base);
         s->is_jmp = 1;
         break;
     case 0xce: /* into */
         if (s->cc_op != CC_OP_DYNAMIC)
             gen_op_set_cc_op(s->cc_op);
-        gen_op_into();
+        gen_op_into(s->pc - s->cs_base);
         break;
     case 0xfa: /* cli */
         if (!s->vm86) {
             if (s->cpl <= s->iopl) {
                 gen_op_cli();
             } else {
-                gen_op_gpf(pc_start - s->cs_base);
-                s->is_jmp = 1;
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
             }
         } else {
             if (s->iopl == 3) {
                 gen_op_cli();
             } else {
-                gen_op_gpf(pc_start - s->cs_base);
-                s->is_jmp = 1;
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
             }
         }
         break;
@@ -3283,15 +3280,13 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
             if (s->cpl <= s->iopl) {
                 gen_op_sti();
             } else {
-                gen_op_gpf(pc_start - s->cs_base);
-                s->is_jmp = 1;
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
             }
         } else {
             if (s->iopl == 3) {
                 gen_op_sti();
             } else {
-                gen_op_gpf(pc_start - s->cs_base);
-                s->is_jmp = 1;
+                gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
             }
         }
         break;
@@ -3343,8 +3338,25 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         break;
     case 0xf4: /* hlt */
         /* XXX: if cpl == 0, then should do something else */
-        gen_op_gpf(pc_start - s->cs_base);
-        s->is_jmp = 1;
+        gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
+        break;
+    case 0x102: /* lar */
+    case 0x103: /* lsl */
+        if (s->vm86)
+            goto illegal_op;
+        ot = dflag ? OT_LONG : OT_WORD;
+        modrm = ldub(s->pc++);
+        reg = (modrm >> 3) & 7;
+        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
+        gen_op_mov_TN_reg[ot][1][reg]();
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        if (b == 0x102)
+            gen_op_lar();
+        else
+            gen_op_lsl();
+        s->cc_op = CC_OP_EFLAGS;
+        gen_op_mov_reg_T1[ot][reg]();
         break;
     default:
         goto illegal_op;
@@ -3453,7 +3465,6 @@ static uint16_t opc_read_flags[NB_OPS] = {
     [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z,
 
     [INDEX_op_movl_T0_eflags] = CC_OSZAPC,
-    [INDEX_op_movl_T0_eflags_vm] = CC_OSZAPC,
     [INDEX_op_cmc] = CC_C,
     [INDEX_op_salc] = CC_C,
 
@@ -3504,9 +3515,7 @@ static uint16_t opc_write_flags[NB_OPS] = {
 
     [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C,
     [INDEX_op_movw_eflags_T0] = CC_OSZAPC,
-    [INDEX_op_movw_eflags_T0_vm] = CC_OSZAPC,
     [INDEX_op_movl_eflags_T0] = CC_OSZAPC,
-    [INDEX_op_movl_eflags_T0_vm] = CC_OSZAPC,
     [INDEX_op_clc] = CC_C,
     [INDEX_op_stc] = CC_C,
     [INDEX_op_cmc] = CC_C,
@@ -3585,6 +3594,8 @@ static uint16_t opc_write_flags[NB_OPS] = {
     [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
 
     [INDEX_op_cmpxchg8b] = CC_Z,
+    [INDEX_op_lar] = CC_Z,
+    [INDEX_op_lsl] = CC_Z,
 };
 
 /* simpler form of an operation if no flags need to be generated */
@@ -3681,7 +3692,8 @@ static void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
     for(;;) {
         c = *opc_ptr++;
         n = op_nb_args[c];
-        fprintf(logfile, "0x%04x: %s", opc_ptr - opc_buf - 1, op_str[c]);
+        fprintf(logfile, "0x%04x: %s", 
+                (int)(opc_ptr - opc_buf - 1), op_str[c]);
         for(i = 0; i < n; i++) {
             fprintf(logfile, " 0x%x", opparam_ptr[i]);
         }
@@ -3706,10 +3718,19 @@ static uint16_t gen_opc_buf[OPC_BUF_SIZE];
 static uint32_t gen_opparam_buf[OPPARAM_BUF_SIZE];
 
 /* return non zero if the very first instruction is invalid so that
-   the virtual CPU can trigger an exception. */
+   the virtual CPU can trigger an exception. 
+
+   '*code_size_ptr' contains the target code size including the
+   instruction which triggered an exception, except in case of invalid
+   illegal opcode. It must never exceed one target page. 
+   
+   '*gen_code_size_ptr' contains the size of the generated code (host
+   code).
+*/
 int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, 
                      int *gen_code_size_ptr,
-                     uint8_t *pc_start,  uint8_t *cs_base, int flags)
+                     uint8_t *pc_start,  uint8_t *cs_base, int flags,
+                     int *code_size_ptr)
 {
     DisasContext dc1, *dc = &dc1;
     uint8_t *pc_ptr;
@@ -3726,6 +3747,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
     dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1;
     dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3;
     dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3;
+    dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1;
     dc->cc_op = CC_OP_DYNAMIC;
     dc->cs_base = cs_base;
 
@@ -3747,7 +3769,12 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
                 break;
         }
         pc_ptr = (void *)ret;
-    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end);
+        /* if single step mode, we generate only one instruction and
+           generate an exception */
+        if (dc->tf)
+            break;
+    } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end && 
+             (pc_ptr - pc_start) < (TARGET_PAGE_SIZE - 32));
     /* we must store the eflags state if it is not already done */
     if (dc->cc_op != CC_OP_DYNAMIC)
         gen_op_set_cc_op(dc->cc_op);
@@ -3755,6 +3782,10 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
         /* we add an additionnal jmp to update the simulated PC */
         gen_op_jmp_im(ret - (unsigned long)dc->cs_base);
     }
+    if (dc->tf) {
+        gen_op_raise_exception(EXCP01_SSTP);
+    }
+
     *gen_opc_ptr = INDEX_op_end;
 
 #ifdef DEBUG_DISAS
@@ -3786,7 +3817,7 @@ int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
     gen_code_size = dyngen_code(gen_code_buf, gen_opc_buf, gen_opparam_buf);
     flush_icache_range((unsigned long)gen_code_buf, (unsigned long)(gen_code_buf + gen_code_size));
     *gen_code_size_ptr = gen_code_size;
-
+    *code_size_ptr = pc_ptr - pc_start;
 #ifdef DEBUG_DISAS
     if (loglevel) {
         fprintf(logfile, "OUT: [size=%d]\n", *gen_code_size_ptr);
@@ -3821,6 +3852,7 @@ CPUX86State *cpu_x86_init(void)
     if (!inited) {
         inited = 1;
         optimize_flags_init();
+        page_init();
     }
     return env;
 }