Commit 8f186479e26e8207520c062248642153826d5cde
1 parent
4c3a88a2
real mode support (now boots from BOCHS BIOS and LGPL'ed VGA BIOS)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@333 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
78 additions
and
19 deletions
helper-i386.c
| ... | ... | @@ -788,6 +788,37 @@ static inline void load_seg_vm(int seg, int selector) |
| 788 | 788 | sc->limit = 0xffff; |
| 789 | 789 | } |
| 790 | 790 | |
| 791 | +/* real mode iret */ | |
| 792 | +void helper_iret_real(int shift) | |
| 793 | +{ | |
| 794 | + uint32_t sp, new_cs, new_eip, new_eflags, new_esp; | |
| 795 | + uint8_t *ssp; | |
| 796 | + int eflags_mask; | |
| 797 | + | |
| 798 | + sp = env->regs[R_ESP] & 0xffff; | |
| 799 | + ssp = env->segs[R_SS].base + sp; | |
| 800 | + if (shift == 1) { | |
| 801 | + /* 32 bits */ | |
| 802 | + new_eflags = ldl(ssp + 8); | |
| 803 | + new_cs = ldl(ssp + 4) & 0xffff; | |
| 804 | + new_eip = ldl(ssp) & 0xffff; | |
| 805 | + } else { | |
| 806 | + /* 16 bits */ | |
| 807 | + new_eflags = lduw(ssp + 4); | |
| 808 | + new_cs = lduw(ssp + 2); | |
| 809 | + new_eip = lduw(ssp); | |
| 810 | + } | |
| 811 | + new_esp = sp + (6 << shift); | |
| 812 | + env->regs[R_ESP] = (env->regs[R_ESP] & 0xffff0000) | | |
| 813 | + (new_esp & 0xffff); | |
| 814 | + load_seg_vm(R_CS, new_cs); | |
| 815 | + env->eip = new_eip; | |
| 816 | + eflags_mask = FL_UPDATE_CPL0_MASK; | |
| 817 | + if (shift == 0) | |
| 818 | + eflags_mask &= 0xffff; | |
| 819 | + load_eflags(new_eflags, eflags_mask); | |
| 820 | +} | |
| 821 | + | |
| 791 | 822 | /* protected mode iret */ |
| 792 | 823 | void helper_iret_protected(int shift) |
| 793 | 824 | { | ... | ... |
op-i386.c
| ... | ... | @@ -953,6 +953,11 @@ void OPPROTO op_ljmp_T0_T1(void) |
| 953 | 953 | jmp_seg(T0 & 0xffff, T1); |
| 954 | 954 | } |
| 955 | 955 | |
| 956 | +void OPPROTO op_iret_real(void) | |
| 957 | +{ | |
| 958 | + helper_iret_real(PARAM1); | |
| 959 | +} | |
| 960 | + | |
| 956 | 961 | void OPPROTO op_iret_protected(void) |
| 957 | 962 | { |
| 958 | 963 | helper_iret_protected(PARAM1); | ... | ... |
translate-i386.c
| ... | ... | @@ -52,6 +52,7 @@ typedef struct DisasContext { |
| 52 | 52 | static state change (stop translation) */ |
| 53 | 53 | /* current block context */ |
| 54 | 54 | uint8_t *cs_base; /* base of CS segment */ |
| 55 | + int pe; /* protected mode */ | |
| 55 | 56 | int code32; /* 32 bit code segment */ |
| 56 | 57 | int ss32; /* 32 bit stack segment */ |
| 57 | 58 | int cc_op; /* current CC operation */ |
| ... | ... | @@ -989,7 +990,7 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ |
| 989 | 990 | if (base >= 0) { |
| 990 | 991 | /* for correct popl handling with esp */ |
| 991 | 992 | if (base == 4 && s->popl_esp_hack) |
| 992 | - disp += 4; | |
| 993 | + disp += s->popl_esp_hack; | |
| 993 | 994 | gen_op_movl_A0_reg[base](); |
| 994 | 995 | if (disp != 0) |
| 995 | 996 | gen_op_addl_A0_im(disp); |
| ... | ... | @@ -1272,7 +1273,7 @@ static void gen_setcc(DisasContext *s, int b) |
| 1272 | 1273 | /* move T0 to seg_reg and compute if the CPU state may change */ |
| 1273 | 1274 | static void gen_movl_seg_T0(DisasContext *s, int seg_reg, unsigned int cur_eip) |
| 1274 | 1275 | { |
| 1275 | - if (!s->vm86) | |
| 1276 | + if (s->pe && !s->vm86) | |
| 1276 | 1277 | gen_op_movl_seg_T0(seg_reg, cur_eip); |
| 1277 | 1278 | else |
| 1278 | 1279 | gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg])); |
| ... | ... | @@ -1855,7 +1856,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 1855 | 1856 | gen_op_ld_T1_A0[ot](); |
| 1856 | 1857 | gen_op_addl_A0_im(1 << (ot - OT_WORD + 1)); |
| 1857 | 1858 | gen_op_lduw_T0_A0(); |
| 1858 | - if (!s->vm86) { | |
| 1859 | + if (s->pe && !s->vm86) { | |
| 1859 | 1860 | /* we compute EIP to handle the exception case */ |
| 1860 | 1861 | gen_op_jmp_im(pc_start - s->cs_base); |
| 1861 | 1862 | gen_op_ljmp_T0_T1(); |
| ... | ... | @@ -2036,7 +2037,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2036 | 2037 | ot = dflag ? OT_LONG : OT_WORD; |
| 2037 | 2038 | modrm = ldub(s->pc++); |
| 2038 | 2039 | gen_pop_T0(s); |
| 2039 | - s->popl_esp_hack = 1; | |
| 2040 | + s->popl_esp_hack = 2 << dflag; | |
| 2040 | 2041 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
| 2041 | 2042 | s->popl_esp_hack = 0; |
| 2042 | 2043 | gen_pop_update(s); |
| ... | ... | @@ -2082,6 +2083,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2082 | 2083 | gen_pop_T0(s); |
| 2083 | 2084 | gen_movl_seg_T0(s, b >> 3, pc_start - s->cs_base); |
| 2084 | 2085 | gen_pop_update(s); |
| 2086 | + /* XXX: if reg == SS, inhibit interrupts/trace */ | |
| 2085 | 2087 | break; |
| 2086 | 2088 | case 0x1a1: /* pop fs */ |
| 2087 | 2089 | case 0x1a9: /* pop gs */ |
| ... | ... | @@ -2134,21 +2136,24 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2134 | 2136 | gen_op_mov_reg_T0[ot][reg](); |
| 2135 | 2137 | break; |
| 2136 | 2138 | case 0x8e: /* mov seg, Gv */ |
| 2137 | - ot = dflag ? OT_LONG : OT_WORD; | |
| 2138 | 2139 | modrm = ldub(s->pc++); |
| 2139 | 2140 | reg = (modrm >> 3) & 7; |
| 2140 | - gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0); | |
| 2141 | 2141 | if (reg >= 6 || reg == R_CS) |
| 2142 | 2142 | goto illegal_op; |
| 2143 | + gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0); | |
| 2143 | 2144 | gen_movl_seg_T0(s, reg, pc_start - s->cs_base); |
| 2145 | + /* XXX: if reg == SS, inhibit interrupts/trace */ | |
| 2144 | 2146 | break; |
| 2145 | 2147 | case 0x8c: /* mov Gv, seg */ |
| 2146 | - ot = dflag ? OT_LONG : OT_WORD; | |
| 2147 | 2148 | modrm = ldub(s->pc++); |
| 2148 | 2149 | reg = (modrm >> 3) & 7; |
| 2150 | + mod = (modrm >> 6) & 3; | |
| 2149 | 2151 | if (reg >= 6) |
| 2150 | 2152 | goto illegal_op; |
| 2151 | 2153 | gen_op_movl_T0_seg(reg); |
| 2154 | + ot = OT_WORD; | |
| 2155 | + if (mod == 3 && dflag) | |
| 2156 | + ot = OT_LONG; | |
| 2152 | 2157 | gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); |
| 2153 | 2158 | break; |
| 2154 | 2159 | |
| ... | ... | @@ -2938,7 +2943,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2938 | 2943 | break; |
| 2939 | 2944 | case 0x6c: /* insS */ |
| 2940 | 2945 | case 0x6d: |
| 2941 | - if (s->cpl > s->iopl || s->vm86) { | |
| 2946 | + if (s->pe && (s->cpl > s->iopl || s->vm86)) { | |
| 2942 | 2947 | /* NOTE: even for (E)CX = 0 the exception is raised */ |
| 2943 | 2948 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
| 2944 | 2949 | } else { |
| ... | ... | @@ -2955,7 +2960,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2955 | 2960 | break; |
| 2956 | 2961 | case 0x6e: /* outsS */ |
| 2957 | 2962 | case 0x6f: |
| 2958 | - if (s->cpl > s->iopl || s->vm86) { | |
| 2963 | + if (s->pe && (s->cpl > s->iopl || s->vm86)) { | |
| 2959 | 2964 | /* NOTE: even for (E)CX = 0 the exception is raised */ |
| 2960 | 2965 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
| 2961 | 2966 | } else { |
| ... | ... | @@ -2975,7 +2980,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2975 | 2980 | /* port I/O */ |
| 2976 | 2981 | case 0xe4: |
| 2977 | 2982 | case 0xe5: |
| 2978 | - if (s->cpl > s->iopl || s->vm86) { | |
| 2983 | + if (s->pe && (s->cpl > s->iopl || s->vm86)) { | |
| 2979 | 2984 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
| 2980 | 2985 | } else { |
| 2981 | 2986 | if ((b & 1) == 0) |
| ... | ... | @@ -2990,7 +2995,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 2990 | 2995 | break; |
| 2991 | 2996 | case 0xe6: |
| 2992 | 2997 | case 0xe7: |
| 2993 | - if (s->cpl > s->iopl || s->vm86) { | |
| 2998 | + if (s->pe && (s->cpl > s->iopl || s->vm86)) { | |
| 2994 | 2999 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
| 2995 | 3000 | } else { |
| 2996 | 3001 | if ((b & 1) == 0) |
| ... | ... | @@ -3005,7 +3010,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 3005 | 3010 | break; |
| 3006 | 3011 | case 0xec: |
| 3007 | 3012 | case 0xed: |
| 3008 | - if (s->cpl > s->iopl || s->vm86) { | |
| 3013 | + if (s->pe && (s->cpl > s->iopl || s->vm86)) { | |
| 3009 | 3014 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
| 3010 | 3015 | } else { |
| 3011 | 3016 | if ((b & 1) == 0) |
| ... | ... | @@ -3019,7 +3024,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 3019 | 3024 | break; |
| 3020 | 3025 | case 0xee: |
| 3021 | 3026 | case 0xef: |
| 3022 | - if (s->cpl > s->iopl || s->vm86) { | |
| 3027 | + if (s->pe && (s->cpl > s->iopl || s->vm86)) { | |
| 3023 | 3028 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
| 3024 | 3029 | } else { |
| 3025 | 3030 | if ((b & 1) == 0) |
| ... | ... | @@ -3076,7 +3081,11 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 3076 | 3081 | val = 0; |
| 3077 | 3082 | goto do_lret; |
| 3078 | 3083 | case 0xcf: /* iret */ |
| 3079 | - if (s->vm86 && s->iopl != 3) { | |
| 3084 | + if (!s->pe) { | |
| 3085 | + /* real mode */ | |
| 3086 | + gen_op_iret_real(s->dflag); | |
| 3087 | + s->cc_op = CC_OP_EFLAGS; | |
| 3088 | + } else if (s->vm86 && s->iopl != 3) { | |
| 3080 | 3089 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
| 3081 | 3090 | } else { |
| 3082 | 3091 | if (s->cc_op != CC_OP_DYNAMIC) |
| ... | ... | @@ -3142,7 +3151,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 3142 | 3151 | |
| 3143 | 3152 | /* change cs and pc */ |
| 3144 | 3153 | gen_op_movl_T0_im(selector); |
| 3145 | - if (!s->vm86) { | |
| 3154 | + if (s->pe && !s->vm86) { | |
| 3146 | 3155 | /* we compute EIP to handle the exception case */ |
| 3147 | 3156 | gen_op_jmp_im(pc_start - s->cs_base); |
| 3148 | 3157 | gen_op_movl_T1_im(offset); |
| ... | ... | @@ -3442,6 +3451,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 3442 | 3451 | gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); |
| 3443 | 3452 | } |
| 3444 | 3453 | } |
| 3454 | + /* XXX: interruptions are enabled only the first insn after sti */ | |
| 3445 | 3455 | break; |
| 3446 | 3456 | case 0x62: /* bound */ |
| 3447 | 3457 | ot = dflag ? OT_LONG : OT_WORD; |
| ... | ... | @@ -3628,7 +3638,7 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) |
| 3628 | 3638 | break; |
| 3629 | 3639 | case 0x102: /* lar */ |
| 3630 | 3640 | case 0x103: /* lsl */ |
| 3631 | - if (s->vm86) | |
| 3641 | + if (!s->pe || s->vm86) | |
| 3632 | 3642 | goto illegal_op; |
| 3633 | 3643 | ot = dflag ? OT_LONG : OT_WORD; |
| 3634 | 3644 | modrm = ldub(s->pc++); |
| ... | ... | @@ -4106,19 +4116,26 @@ static inline int gen_intermediate_code_internal(CPUState *env, |
| 4106 | 4116 | cs_base = (uint8_t *)tb->cs_base; |
| 4107 | 4117 | flags = tb->flags; |
| 4108 | 4118 | |
| 4119 | + dc->pe = env->cr[0] & CR0_PE_MASK; | |
| 4109 | 4120 | dc->code32 = (flags >> GEN_FLAG_CODE32_SHIFT) & 1; |
| 4110 | 4121 | dc->ss32 = (flags >> GEN_FLAG_SS32_SHIFT) & 1; |
| 4111 | 4122 | dc->addseg = (flags >> GEN_FLAG_ADDSEG_SHIFT) & 1; |
| 4112 | 4123 | dc->f_st = (flags >> GEN_FLAG_ST_SHIFT) & 7; |
| 4113 | 4124 | dc->vm86 = (flags >> GEN_FLAG_VM_SHIFT) & 1; |
| 4114 | - dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3; | |
| 4125 | + /* CPL is implicit if real mode or vm86 mode */ | |
| 4126 | + if (!dc->pe) | |
| 4127 | + dc->cpl = 0; | |
| 4128 | + else if (dc->vm86) | |
| 4129 | + dc->cpl = 3; | |
| 4130 | + else | |
| 4131 | + dc->cpl = (flags >> GEN_FLAG_CPL_SHIFT) & 3; | |
| 4115 | 4132 | dc->iopl = (flags >> GEN_FLAG_IOPL_SHIFT) & 3; |
| 4116 | 4133 | dc->tf = (flags >> GEN_FLAG_TF_SHIFT) & 1; |
| 4117 | 4134 | dc->cc_op = CC_OP_DYNAMIC; |
| 4118 | 4135 | dc->cs_base = cs_base; |
| 4119 | 4136 | dc->tb = tb; |
| 4120 | 4137 | dc->popl_esp_hack = 0; |
| 4121 | - | |
| 4138 | + | |
| 4122 | 4139 | gen_opc_ptr = gen_opc_buf; |
| 4123 | 4140 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
| 4124 | 4141 | gen_opparam_ptr = gen_opparam_buf; |
| ... | ... | @@ -4270,13 +4287,14 @@ void cpu_x86_close(CPUX86State *env) |
| 4270 | 4287 | |
| 4271 | 4288 | /* called when cr3 or PG bit are modified */ |
| 4272 | 4289 | static int last_pg_state = -1; |
| 4290 | +static int last_pe_state = 0; | |
| 4273 | 4291 | int phys_ram_size; |
| 4274 | 4292 | int phys_ram_fd; |
| 4275 | 4293 | uint8_t *phys_ram_base; |
| 4276 | 4294 | |
| 4277 | 4295 | void cpu_x86_update_cr0(CPUX86State *env) |
| 4278 | 4296 | { |
| 4279 | - int pg_state; | |
| 4297 | + int pg_state, pe_state; | |
| 4280 | 4298 | void *map_addr; |
| 4281 | 4299 | |
| 4282 | 4300 | #ifdef DEBUG_MMU |
| ... | ... | @@ -4304,6 +4322,11 @@ void cpu_x86_update_cr0(CPUX86State *env) |
| 4304 | 4322 | } |
| 4305 | 4323 | last_pg_state = pg_state; |
| 4306 | 4324 | } |
| 4325 | + pe_state = env->cr[0] & CR0_PE_MASK; | |
| 4326 | + if (last_pe_state != pe_state) { | |
| 4327 | + tb_flush(); | |
| 4328 | + last_pe_state = pe_state; | |
| 4329 | + } | |
| 4307 | 4330 | } |
| 4308 | 4331 | |
| 4309 | 4332 | void cpu_x86_update_cr3(CPUX86State *env) | ... | ... |