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) | ... | ... |