Commit 717fc2ad8dbedcb19ec939b752489d2d1a21647b

Authored by bellard
1 parent c05bab77

more ring 0 instructions - full x86 MMU emulation based on mmap() syscall - fixed popl (%esp)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@258 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 249 additions and 30 deletions
translate-i386.c
@@ -24,11 +24,14 @@ @@ -24,11 +24,14 @@
24 #include <inttypes.h> 24 #include <inttypes.h>
25 #include <signal.h> 25 #include <signal.h>
26 #include <assert.h> 26 #include <assert.h>
  27 +#include <sys/mman.h>
27 28
28 #include "cpu-i386.h" 29 #include "cpu-i386.h"
29 #include "exec.h" 30 #include "exec.h"
30 #include "disas.h" 31 #include "disas.h"
31 32
  33 +//#define DEBUG_MMU
  34 +
32 /* XXX: move that elsewhere */ 35 /* XXX: move that elsewhere */
33 static uint16_t *gen_opc_ptr; 36 static uint16_t *gen_opc_ptr;
34 static uint32_t *gen_opparam_ptr; 37 static uint32_t *gen_opparam_ptr;
@@ -59,6 +62,7 @@ typedef struct DisasContext { @@ -59,6 +62,7 @@ typedef struct DisasContext {
59 int iopl; 62 int iopl;
60 int tf; /* TF cpu flag */ 63 int tf; /* TF cpu flag */
61 struct TranslationBlock *tb; 64 struct TranslationBlock *tb;
  65 + int popl_esp_hack; /* for correct popl with esp base handling */
62 } DisasContext; 66 } DisasContext;
63 67
64 /* i386 arith/logic operations */ 68 /* i386 arith/logic operations */
@@ -862,12 +866,16 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ @@ -862,12 +866,16 @@ static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_
862 } 866 }
863 867
864 if (base >= 0) { 868 if (base >= 0) {
  869 + /* for correct popl handling with esp */
  870 + if (base == 4 && s->popl_esp_hack)
  871 + disp += 4;
865 gen_op_movl_A0_reg[base](); 872 gen_op_movl_A0_reg[base]();
866 if (disp != 0) 873 if (disp != 0)
867 gen_op_addl_A0_im(disp); 874 gen_op_addl_A0_im(disp);
868 } else { 875 } else {
869 gen_op_movl_A0_im(disp); 876 gen_op_movl_A0_im(disp);
870 } 877 }
  878 + /* XXX: index == 4 is always invalid */
871 if (havesib && (index != 4 || scale != 0)) { 879 if (havesib && (index != 4 || scale != 0)) {
872 gen_op_addl_A0_reg_sN[scale][index](); 880 gen_op_addl_A0_reg_sN[scale][index]();
873 } 881 }
@@ -1894,7 +1902,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) @@ -1894,7 +1902,9 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
1894 ot = dflag ? OT_LONG : OT_WORD; 1902 ot = dflag ? OT_LONG : OT_WORD;
1895 modrm = ldub(s->pc++); 1903 modrm = ldub(s->pc++);
1896 gen_pop_T0(s); 1904 gen_pop_T0(s);
  1905 + s->popl_esp_hack = 1;
1897 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1); 1906 gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
  1907 + s->popl_esp_hack = 0;
1898 gen_pop_update(s); 1908 gen_pop_update(s);
1899 break; 1909 break;
1900 case 0xc8: /* enter */ 1910 case 0xc8: /* enter */
@@ -2940,29 +2950,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) @@ -2940,29 +2950,10 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
2940 if (s->vm86 && s->iopl != 3) { 2950 if (s->vm86 && s->iopl != 3) {
2941 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); 2951 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
2942 } else { 2952 } else {
2943 - /* XXX: not restartable */  
2944 - gen_stack_A0(s);  
2945 - /* pop offset */  
2946 - gen_op_ld_T0_A0[1 + s->dflag]();  
2947 - if (s->dflag == 0)  
2948 - gen_op_andl_T0_ffff();  
2949 - /* NOTE: keeping EIP updated is not a problem in case of  
2950 - exception */  
2951 - gen_op_jmp_T0();  
2952 - /* pop selector */  
2953 - gen_op_addl_A0_im(2 << s->dflag);  
2954 - gen_op_ld_T0_A0[1 + s->dflag]();  
2955 - /* pop eflags */  
2956 - gen_op_addl_A0_im(2 << s->dflag);  
2957 - gen_op_ld_T1_A0[1 + s->dflag]();  
2958 - gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);  
2959 - gen_op_movl_T0_T1();  
2960 - if (s->dflag) {  
2961 - gen_op_movl_eflags_T0();  
2962 - } else {  
2963 - gen_op_movw_eflags_T0();  
2964 - }  
2965 - gen_stack_update(s, (6 << s->dflag)); 2953 + if (s->cc_op != CC_OP_DYNAMIC)
  2954 + gen_op_set_cc_op(s->cc_op);
  2955 + gen_op_jmp_im(pc_start - s->cs_base);
  2956 + gen_op_iret_protected(s->dflag);
2966 s->cc_op = CC_OP_EFLAGS; 2957 s->cc_op = CC_OP_EFLAGS;
2967 } 2958 }
2968 s->is_jmp = 1; 2959 s->is_jmp = 1;
@@ -3096,10 +3087,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) @@ -3096,10 +3087,18 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
3096 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); 3087 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3097 } else { 3088 } else {
3098 gen_pop_T0(s); 3089 gen_pop_T0(s);
3099 - if (s->dflag) {  
3100 - gen_op_movl_eflags_T0(); 3090 + if (s->cpl == 0) {
  3091 + if (s->dflag) {
  3092 + gen_op_movl_eflags_T0_cpl0();
  3093 + } else {
  3094 + gen_op_movw_eflags_T0_cpl0();
  3095 + }
3101 } else { 3096 } else {
3102 - gen_op_movw_eflags_T0(); 3097 + if (s->dflag) {
  3098 + gen_op_movl_eflags_T0();
  3099 + } else {
  3100 + gen_op_movw_eflags_T0();
  3101 + }
3103 } 3102 }
3104 gen_pop_update(s); 3103 gen_pop_update(s);
3105 s->cc_op = CC_OP_EFLAGS; 3104 s->cc_op = CC_OP_EFLAGS;
@@ -3358,8 +3357,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) @@ -3358,8 +3357,15 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
3358 gen_op_cpuid(); 3357 gen_op_cpuid();
3359 break; 3358 break;
3360 case 0xf4: /* hlt */ 3359 case 0xf4: /* hlt */
3361 - /* XXX: if cpl == 0, then should do something else */  
3362 - gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); 3360 + if (s->cpl != 0) {
  3361 + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
  3362 + } else {
  3363 + if (s->cc_op != CC_OP_DYNAMIC)
  3364 + gen_op_set_cc_op(s->cc_op);
  3365 + gen_op_jmp_im(s->pc - s->cs_base);
  3366 + gen_op_hlt();
  3367 + s->is_jmp = 1;
  3368 + }
3363 break; 3369 break;
3364 case 0x100: 3370 case 0x100:
3365 modrm = ldub(s->pc++); 3371 modrm = ldub(s->pc++);
@@ -3462,6 +3468,16 @@ long disas_insn(DisasContext *s, uint8_t *pc_start) @@ -3462,6 +3468,16 @@ long disas_insn(DisasContext *s, uint8_t *pc_start)
3462 gen_op_lmsw_T0(); 3468 gen_op_lmsw_T0();
3463 } 3469 }
3464 break; 3470 break;
  3471 + case 7: /* invlpg */
  3472 + if (s->cpl != 0) {
  3473 + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
  3474 + } else {
  3475 + if (mod == 3)
  3476 + goto illegal_op;
  3477 + gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
  3478 + gen_op_invlpg_A0();
  3479 + }
  3480 + break;
3465 default: 3481 default:
3466 goto illegal_op; 3482 goto illegal_op;
3467 } 3483 }
@@ -3866,7 +3882,7 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len) @@ -3866,7 +3882,7 @@ static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
3866 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for 3882 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
3867 basic block 'tb'. If search_pc is TRUE, also generate PC 3883 basic block 'tb'. If search_pc is TRUE, also generate PC
3868 information for each intermediate instruction. */ 3884 information for each intermediate instruction. */
3869 -int gen_intermediate_code(TranslationBlock *tb, int search_pc) 3885 +static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc)
3870 { 3886 {
3871 DisasContext dc1, *dc = &dc1; 3887 DisasContext dc1, *dc = &dc1;
3872 uint8_t *pc_ptr; 3888 uint8_t *pc_ptr;
@@ -3892,7 +3908,8 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc) @@ -3892,7 +3908,8 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc)
3892 dc->cc_op = CC_OP_DYNAMIC; 3908 dc->cc_op = CC_OP_DYNAMIC;
3893 dc->cs_base = cs_base; 3909 dc->cs_base = cs_base;
3894 dc->tb = tb; 3910 dc->tb = tb;
3895 - 3911 + dc->popl_esp_hack = 0;
  3912 +
3896 gen_opc_ptr = gen_opc_buf; 3913 gen_opc_ptr = gen_opc_buf;
3897 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; 3914 gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
3898 gen_opparam_ptr = gen_opparam_buf; 3915 gen_opparam_ptr = gen_opparam_buf;
@@ -3908,6 +3925,7 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc) @@ -3908,6 +3925,7 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc)
3908 while (lj < j) 3925 while (lj < j)
3909 gen_opc_instr_start[lj++] = 0; 3926 gen_opc_instr_start[lj++] = 0;
3910 gen_opc_pc[lj] = (uint32_t)pc_ptr; 3927 gen_opc_pc[lj] = (uint32_t)pc_ptr;
  3928 + gen_opc_cc_op[lj] = dc->cc_op;
3911 gen_opc_instr_start[lj] = 1; 3929 gen_opc_instr_start[lj] = 1;
3912 } 3930 }
3913 } 3931 }
@@ -3974,6 +3992,16 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc) @@ -3974,6 +3992,16 @@ int gen_intermediate_code(TranslationBlock *tb, int search_pc)
3974 return 0; 3992 return 0;
3975 } 3993 }
3976 3994
  3995 +int gen_intermediate_code(TranslationBlock *tb)
  3996 +{
  3997 + return gen_intermediate_code_internal(tb, 0);
  3998 +}
  3999 +
  4000 +int gen_intermediate_code_pc(TranslationBlock *tb)
  4001 +{
  4002 + return gen_intermediate_code_internal(tb, 1);
  4003 +}
  4004 +
3977 CPUX86State *cpu_x86_init(void) 4005 CPUX86State *cpu_x86_init(void)
3978 { 4006 {
3979 CPUX86State *env; 4007 CPUX86State *env;
@@ -4006,6 +4034,197 @@ void cpu_x86_close(CPUX86State *env) @@ -4006,6 +4034,197 @@ void cpu_x86_close(CPUX86State *env)
4006 free(env); 4034 free(env);
4007 } 4035 }
4008 4036
  4037 +/***********************************************************/
  4038 +/* x86 mmu */
  4039 +
  4040 +/* called when cr3 or PG bit are modified */
  4041 +static int last_pg_state = -1;
  4042 +int phys_ram_size;
  4043 +int phys_ram_fd;
  4044 +uint8_t *phys_ram_base;
  4045 +
  4046 +void cpu_x86_update_cr0(CPUX86State *env)
  4047 +{
  4048 + int pg_state;
  4049 + void *map_addr;
  4050 +
  4051 +#ifdef DEBUG_MMU
  4052 + printf("CR0 update: CR0=0x%08x\n", env->cr[0]);
  4053 +#endif
  4054 + pg_state = env->cr[0] & CR0_PG_MASK;
  4055 + if (pg_state != last_pg_state) {
  4056 + if (!pg_state) {
  4057 + /* we map the physical memory at address 0 */
  4058 +
  4059 + map_addr = mmap((void *)0, phys_ram_size, PROT_WRITE | PROT_READ,
  4060 + MAP_SHARED | MAP_FIXED, phys_ram_fd, 0);
  4061 + if (map_addr == MAP_FAILED) {
  4062 + fprintf(stderr,
  4063 + "Could not map physical memory at host address 0x%08x\n",
  4064 + 0);
  4065 + exit(1);
  4066 + }
  4067 + page_set_flags(0, phys_ram_size,
  4068 + PAGE_VALID | PAGE_READ | PAGE_WRITE | PAGE_EXEC);
  4069 + } else {
  4070 + /* we unmap the physical memory */
  4071 + munmap((void *)0, phys_ram_size);
  4072 + page_set_flags(0, phys_ram_size, 0);
  4073 + }
  4074 + last_pg_state = pg_state;
  4075 + }
  4076 +}
  4077 +
  4078 +void cpu_x86_update_cr3(CPUX86State *env)
  4079 +{
  4080 + if (env->cr[0] & CR0_PG_MASK) {
  4081 +#ifdef DEBUG_MMU
  4082 + printf("CR3 update: CR3=%08x\n", env->cr[3]);
  4083 +#endif
  4084 + page_unmap();
  4085 + }
  4086 +}
  4087 +
  4088 +void cpu_x86_init_mmu(CPUX86State *env)
  4089 +{
  4090 + last_pg_state = -1;
  4091 + cpu_x86_update_cr0(env);
  4092 +}
  4093 +
  4094 +void cpu_x86_flush_tlb(CPUX86State *env, uint32_t addr)
  4095 +{
  4096 +}
  4097 +
  4098 +/* return value:
  4099 + -1 = cannot handle fault
  4100 + 0 = nothing more to do
  4101 + 1 = generate PF fault
  4102 +*/
  4103 +int cpu_x86_handle_mmu_fault(CPUX86State *env, uint32_t addr, int is_write)
  4104 +{
  4105 + uint8_t *pde_ptr, *pte_ptr;
  4106 + uint32_t pde, pte, virt_addr;
  4107 + int cpl, error_code, is_dirty, is_user, prot, page_size;
  4108 + void *map_addr;
  4109 +
  4110 + cpl = env->segs[R_CS].selector & 3;
  4111 + is_user = (cpl == 3);
  4112 +
  4113 +#ifdef DEBUG_MMU
  4114 + printf("MMU fault: addr=0x%08x w=%d u=%d eip=%08x\n",
  4115 + addr, is_write, is_user, env->eip);
  4116 +#endif
  4117 +
  4118 + if (env->user_mode_only) {
  4119 + /* user mode only emulation */
  4120 + error_code = 0;
  4121 + goto do_fault;
  4122 + }
  4123 +
  4124 + if (!(env->cr[0] & CR0_PG_MASK))
  4125 + return -1;
  4126 +
  4127 + /* page directory entry */
  4128 + pde_ptr = phys_ram_base + ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3));
  4129 + pde = ldl(pde_ptr);
  4130 + if (!(pde & PG_PRESENT_MASK)) {
  4131 + error_code = 0;
  4132 + goto do_fault;
  4133 + }
  4134 + if (is_user) {
  4135 + if (!(pde & PG_USER_MASK))
  4136 + goto do_fault_protect;
  4137 + if (is_write && !(pde & PG_RW_MASK))
  4138 + goto do_fault_protect;
  4139 + } else {
  4140 + if ((env->cr[0] & CR0_WP_MASK) && (pde & PG_USER_MASK) &&
  4141 + is_write && !(pde & PG_RW_MASK))
  4142 + goto do_fault_protect;
  4143 + }
  4144 + /* if PSE bit is set, then we use a 4MB page */
  4145 + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
  4146 + is_dirty = is_write && !(pde & PG_DIRTY_MASK);
  4147 + if (!(pde & PG_ACCESSED_MASK)) {
  4148 + pde |= PG_ACCESSED_MASK;
  4149 + if (is_dirty)
  4150 + pde |= PG_DIRTY_MASK;
  4151 + stl(pde_ptr, pde);
  4152 + }
  4153 +
  4154 + pte = pde & ~0x003ff000; /* align to 4MB */
  4155 + page_size = 4096 * 1024;
  4156 + virt_addr = addr & ~0x003fffff;
  4157 + } else {
  4158 + if (!(pde & PG_ACCESSED_MASK)) {
  4159 + pde |= PG_ACCESSED_MASK;
  4160 + stl(pde_ptr, pde);
  4161 + }
  4162 +
  4163 + /* page directory entry */
  4164 + pte_ptr = phys_ram_base + ((pde & ~0xfff) + ((addr >> 10) & 0xffc));
  4165 + pte = ldl(pte_ptr);
  4166 + if (!(pte & PG_PRESENT_MASK)) {
  4167 + error_code = 0;
  4168 + goto do_fault;
  4169 + }
  4170 + if (is_user) {
  4171 + if (!(pte & PG_USER_MASK))
  4172 + goto do_fault_protect;
  4173 + if (is_write && !(pte & PG_RW_MASK))
  4174 + goto do_fault_protect;
  4175 + } else {
  4176 + if ((env->cr[0] & CR0_WP_MASK) && (pte & PG_USER_MASK) &&
  4177 + is_write && !(pte & PG_RW_MASK))
  4178 + goto do_fault_protect;
  4179 + }
  4180 + is_dirty = is_write && !(pte & PG_DIRTY_MASK);
  4181 + if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
  4182 + pte |= PG_ACCESSED_MASK;
  4183 + if (is_dirty)
  4184 + pte |= PG_DIRTY_MASK;
  4185 + stl(pte_ptr, pte);
  4186 + }
  4187 + page_size = 4096;
  4188 + virt_addr = addr & ~0xfff;
  4189 + }
  4190 + /* the page can be put in the TLB */
  4191 + prot = PROT_READ;
  4192 + if (is_user) {
  4193 + if (pte & PG_RW_MASK)
  4194 + prot |= PROT_WRITE;
  4195 + } else {
  4196 + if (!(env->cr[0] & CR0_WP_MASK) || !(pte & PG_USER_MASK) ||
  4197 + (pte & PG_RW_MASK))
  4198 + prot |= PROT_WRITE;
  4199 + }
  4200 + map_addr = mmap((void *)virt_addr, page_size, prot,
  4201 + MAP_SHARED | MAP_FIXED, phys_ram_fd, pte & ~0xfff);
  4202 + if (map_addr == MAP_FAILED) {
  4203 + fprintf(stderr,
  4204 + "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
  4205 + pte & ~0xfff, virt_addr);
  4206 + exit(1);
  4207 + }
  4208 + page_set_flags(virt_addr, virt_addr + page_size,
  4209 + PAGE_VALID | PAGE_EXEC | prot);
  4210 +#ifdef DEBUG_MMU
  4211 + printf("mmaping 0x%08x to virt 0x%08x pse=%d\n",
  4212 + pte & ~0xfff, virt_addr, (page_size != 4096));
  4213 +#endif
  4214 + return 0;
  4215 + do_fault_protect:
  4216 + error_code = PG_ERROR_P_MASK;
  4217 + do_fault:
  4218 + env->cr[2] = addr;
  4219 + env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
  4220 + if (is_user)
  4221 + env->error_code |= PG_ERROR_U_MASK;
  4222 + return 1;
  4223 +}
  4224 +
  4225 +/***********************************************************/
  4226 +/* x86 debug */
  4227 +
4009 static const char *cc_op_str[] = { 4228 static const char *cc_op_str[] = {
4010 "DYNAMIC", 4229 "DYNAMIC",
4011 "EFLAGS", 4230 "EFLAGS",