real mode support (now boots from BOCHS BIOS and LGPL'ed VGA BIOS)
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 26 Jul 2003 17:59:00 +0000 (17:59 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 26 Jul 2003 17:59:00 +0000 (17:59 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@333 c046a42c-6fe2-441c-8c8c-71466251a162

helper-i386.c
op-i386.c
translate-i386.c

index 72b75a5..3f63704 100644 (file)
@@ -788,6 +788,37 @@ static inline void load_seg_vm(int seg, int selector)
     sc->limit = 0xffff;
 }
 
+/* real mode iret */
+void helper_iret_real(int shift)
+{
+    uint32_t sp, new_cs, new_eip, new_eflags, new_esp;
+    uint8_t *ssp;
+    int eflags_mask;
+    
+    sp = env->regs[R_ESP] & 0xffff;
+    ssp = env->segs[R_SS].base + sp;
+    if (shift == 1) {
+        /* 32 bits */
+        new_eflags = ldl(ssp + 8);
+        new_cs = ldl(ssp + 4) & 0xffff;
+        new_eip = ldl(ssp) & 0xffff;
+    } else {
+        /* 16 bits */
+        new_eflags = lduw(ssp + 4);
+        new_cs = lduw(ssp + 2);
+        new_eip = lduw(ssp);
+    }
+    new_esp = sp + (6 << shift);
+    env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | 
+        (new_esp & 0xffff);
+    load_seg_vm(R_CS, new_cs);
+    env->eip = new_eip;
+    eflags_mask = FL_UPDATE_CPL0_MASK;
+    if (shift == 0)
+        eflags_mask &= 0xffff;
+    load_eflags(new_eflags, eflags_mask);
+}
+
 /* protected mode iret */
 void helper_iret_protected(int shift)
 {
index 661d45b..ff8cb44 100644 (file)
--- a/op-i386.c
+++ b/op-i386.c
@@ -953,6 +953,11 @@ void OPPROTO op_ljmp_T0_T1(void)
     jmp_seg(T0 & 0xffff, T1);
 }
 
+void OPPROTO op_iret_real(void)
+{
+    helper_iret_real(PARAM1);
+}
+
 void OPPROTO op_iret_protected(void)
 {
     helper_iret_protected(PARAM1);
index 1c051f9..d5cdee5 100644 (file)
@@ -52,6 +52,7 @@ typedef struct DisasContext {
                    static state change (stop translation) */
     /* current block context */
     uint8_t *cs_base; /* base of CS segment */
+    int pe;     /* protected mode */
     int code32; /* 32 bit code segment */
     int ss32;   /* 32 bit stack segment */
     int cc_op;  /* current CC operation */
@@ -989,7 +990,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
         if (base >= 0) {
             /* for correct popl handling with esp */
             if (base == 4 && s->popl_esp_hack)
-                disp += 4;
+                disp += s->popl_esp_hack;
             gen_op_movl_A0_reg[base]();
             if (disp != 0)
                 gen_op_addl_A0_im(disp);
@@ -1272,7 +1273,7 @@ static void gen_setcc(DisasContext *s, int b)
 /* move T0 to seg_reg and compute if the CPU state may change */
 static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip)
 {
-    if (!s->vm86)
+    if (s->pe && !s->vm86)
         gen_op_movl_seg_T0(seg_reg, cur_eip);
     else
         gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]));
@@ -1855,7 +1856,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
             gen_op_ld_T1_A0[ot]();
             gen_op_addl_A0_im(1 << (ot - OT_WORD + 1));
             gen_op_lduw_T0_A0();
-            if (!s->vm86) {
+            if (s->pe && !s->vm86) {
                 /* we compute EIP to handle the exception case */
                 gen_op_jmp_im(pc_start - s->cs_base);
                 gen_op_ljmp_T0_T1();
@@ -2036,7 +2037,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         ot = dflag ? OT_LONG : OT_WORD;
         modrm = ldub(s->pc++);
         gen_pop_T0(s);
-        s->popl_esp_hack = 1;
+        s->popl_esp_hack = 2 << dflag;
         gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
         s->popl_esp_hack = 0;
         gen_pop_update(s);
@@ -2082,6 +2083,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         gen_pop_T0(s);
         gen_movl_seg_T0(s, b >> 3, pc_start - s->cs_base);
         gen_pop_update(s);
+        /* XXX: if reg == SS, inhibit interrupts/trace */
         break;
     case 0x1a1: /* pop fs */
     case 0x1a9: /* pop gs */
@@ -2134,21 +2136,24 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         gen_op_mov_reg_T0[ot][reg]();
         break;
     case 0x8e: /* mov seg, Gv */
-        ot = dflag ? OT_LONG : OT_WORD;
         modrm = ldub(s->pc++);
         reg = (modrm >> 3) & 7;
-        gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
         if (reg >= 6 || reg == R_CS)
             goto illegal_op;
+        gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
         gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
+        /* XXX: if reg == SS, inhibit interrupts/trace */
         break;
     case 0x8c: /* mov Gv, seg */
-        ot = dflag ? OT_LONG : OT_WORD;
         modrm = ldub(s->pc++);
         reg = (modrm >> 3) & 7;
+        mod = (modrm >> 6) & 3;
         if (reg >= 6)
             goto illegal_op;
         gen_op_movl_T0_seg(reg);
+        ot = OT_WORD;
+        if (mod == 3 && dflag)
+            ot = OT_LONG;
         gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
         break;
 
@@ -2938,7 +2943,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         break;
     case 0x6c: /* insS */
     case 0x6d:
-        if (s->cpl > s->iopl || s->vm86) {
+        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
             /* NOTE: even for (E)CX = 0 the exception is raised */
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
@@ -2955,7 +2960,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         break;
     case 0x6e: /* outsS */
     case 0x6f:
-        if (s->cpl > s->iopl || s->vm86) {
+        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
             /* NOTE: even for (E)CX = 0 the exception is raised */
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
@@ -2975,7 +2980,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         /* port I/O */
     case 0xe4:
     case 0xe5:
-        if (s->cpl > s->iopl || s->vm86) {
+        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if ((b & 1) == 0)
@@ -2990,7 +2995,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         break;
     case 0xe6:
     case 0xe7:
-        if (s->cpl > s->iopl || s->vm86) {
+        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if ((b & 1) == 0)
@@ -3005,7 +3010,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         break;
     case 0xec:
     case 0xed:
-        if (s->cpl > s->iopl || s->vm86) {
+        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if ((b & 1) == 0)
@@ -3019,7 +3024,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         break;
     case 0xee:
     case 0xef:
-        if (s->cpl > s->iopl || s->vm86) {
+        if (s->pe && (s->cpl > s->iopl || s->vm86)) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if ((b & 1) == 0)
@@ -3076,7 +3081,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         val = 0;
         goto do_lret;
     case 0xcf: /* iret */
-        if (s->vm86 && s->iopl != 3) {
+        if (!s->pe) {
+            /* real mode */
+            gen_op_iret_real(s->dflag);
+            s->cc_op = CC_OP_EFLAGS;
+        } else if (s->vm86 && s->iopl != 3) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             if (s->cc_op != CC_OP_DYNAMIC)
@@ -3142,7 +3151,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
             
             /* change cs and pc */
             gen_op_movl_T0_im(selector);
-            if (!s->vm86) {
+            if (s->pe && !s->vm86) {
                 /* we compute EIP to handle the exception case */
                 gen_op_jmp_im(pc_start - s->cs_base);
                 gen_op_movl_T1_im(offset);
@@ -3442,6 +3451,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
                 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
             }
         }
+        /* XXX: interruptions are enabled only the first insn after sti */
         break;
     case 0x62: /* bound */
         ot = dflag ? OT_LONG : OT_WORD;
@@ -3628,7 +3638,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
         break;
     case 0x102: /* lar */
     case 0x103: /* lsl */
-        if (s->vm86)
+        if (!s->pe || s->vm86)
             goto illegal_op;
         ot = dflag ? OT_LONG : OT_WORD;
         modrm = ldub(s->pc++);
@@ -4106,19 +4116,26 @@ static inline int gen_intermediate_code_internal(CPUState *env,
     cs_base = (uint8_t *)tb->cs_base;
     flags = tb->flags;
        
+    dc->pe = env->cr[0] & CR0_PE_MASK;
     dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1;
     dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1;
     dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1;
     dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7;
     dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1;
-    dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3;
+    /* CPL is implicit if real mode or vm86 mode */
+    if (!dc->pe)
+        dc->cpl = 0;
+    else if (dc->vm86)
+        dc->cpl = 3;
+    else
+        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;
     dc->tb = tb;
     dc->popl_esp_hack = 0;
-    
+
     gen_opc_ptr = gen_opc_buf;
     gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
     gen_opparam_ptr = gen_opparam_buf;
@@ -4270,13 +4287,14 @@ void cpu_x86_close(CPUX86State *env)
 
 /* called when cr3 or PG bit are modified */
 static int last_pg_state = -1;
+static int last_pe_state = 0;
 int phys_ram_size;
 int phys_ram_fd;
 uint8_t *phys_ram_base;
 
 void cpu_x86_update_cr0(CPUX86State *env)
 {
-    int pg_state;
+    int pg_state, pe_state;
     void *map_addr;
 
 #ifdef DEBUG_MMU
@@ -4304,6 +4322,11 @@ void cpu_x86_update_cr0(CPUX86State *env)
         }
         last_pg_state = pg_state;
     }
+    pe_state = env->cr[0] & CR0_PE_MASK;
+    if (last_pe_state != pe_state) {
+        tb_flush();
+        last_pe_state = pe_state;
+    }
 }
 
 void cpu_x86_update_cr3(CPUX86State *env)