/[qemu]/qemu/translate-i386.c
ViewVC logotype

Diff of /qemu/translate-i386.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.42 by bellard, Sat Jun 21 13:13:13 2003 UTC revision 1.43 by bellard, Tue Jun 24 13:20:53 2003 UTC
# Line 24  Line 24 
24  #include <inttypes.h>  #include <inttypes.h>
25  #include <signal.h>  #include <signal.h>
26  #include <assert.h>  #include <assert.h>
27    #include <sys/mman.h>
28    
29  #include "cpu-i386.h"  #include "cpu-i386.h"
30  #include "exec.h"  #include "exec.h"
31  #include "disas.h"  #include "disas.h"
32    
33    //#define DEBUG_MMU
34    
35  /* XXX: move that elsewhere */  /* XXX: move that elsewhere */
36  static uint16_t *gen_opc_ptr;  static uint16_t *gen_opc_ptr;
37  static uint32_t *gen_opparam_ptr;  static uint32_t *gen_opparam_ptr;
# Line 59  typedef struct DisasContext { Line 62  typedef struct DisasContext {
62      int iopl;      int iopl;
63      int tf;     /* TF cpu flag */      int tf;     /* TF cpu flag */
64      struct TranslationBlock *tb;      struct TranslationBlock *tb;
65        int popl_esp_hack; /* for correct popl with esp base handling */
66  } DisasContext;  } DisasContext;
67    
68  /* i386 arith/logic operations */  /* i386 arith/logic operations */
# Line 862  static void gen_lea_modrm(DisasContext * Line 866  static void gen_lea_modrm(DisasContext *
866          }          }
867                    
868          if (base >= 0) {          if (base >= 0) {
869                /* for correct popl handling with esp */
870                if (base == 4 && s->popl_esp_hack)
871                    disp += 4;
872              gen_op_movl_A0_reg[base]();              gen_op_movl_A0_reg[base]();
873              if (disp != 0)              if (disp != 0)
874                  gen_op_addl_A0_im(disp);                  gen_op_addl_A0_im(disp);
875          } else {          } else {
876              gen_op_movl_A0_im(disp);              gen_op_movl_A0_im(disp);
877          }          }
878            /* XXX: index == 4 is always invalid */
879          if (havesib && (index != 4 || scale != 0)) {          if (havesib && (index != 4 || scale != 0)) {
880              gen_op_addl_A0_reg_sN[scale][index]();              gen_op_addl_A0_reg_sN[scale][index]();
881          }          }
# Line 1894  long disas_insn(DisasContext *s, uint8_t Line 1902  long disas_insn(DisasContext *s, uint8_t
1902          ot = dflag ? OT_LONG : OT_WORD;          ot = dflag ? OT_LONG : OT_WORD;
1903          modrm = ldub(s->pc++);          modrm = ldub(s->pc++);
1904          gen_pop_T0(s);          gen_pop_T0(s);
1905            s->popl_esp_hack = 1;
1906          gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);          gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
1907            s->popl_esp_hack = 0;
1908          gen_pop_update(s);          gen_pop_update(s);
1909          break;          break;
1910      case 0xc8: /* enter */      case 0xc8: /* enter */
# Line 2940  long disas_insn(DisasContext *s, uint8_t Line 2950  long disas_insn(DisasContext *s, uint8_t
2950          if (s->vm86 && s->iopl != 3) {          if (s->vm86 && s->iopl != 3) {
2951              gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);              gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
2952          } else {          } else {
2953              /* XXX: not restartable */              if (s->cc_op != CC_OP_DYNAMIC)
2954              gen_stack_A0(s);                  gen_op_set_cc_op(s->cc_op);
2955              /* pop offset */              gen_op_jmp_im(pc_start - s->cs_base);
2956              gen_op_ld_T0_A0[1 + s->dflag]();              gen_op_iret_protected(s->dflag);
             if (s->dflag == 0)  
                 gen_op_andl_T0_ffff();  
             /* NOTE: keeping EIP updated is not a problem in case of  
                exception */  
             gen_op_jmp_T0();  
             /* pop selector */  
             gen_op_addl_A0_im(2 << s->dflag);  
             gen_op_ld_T0_A0[1 + s->dflag]();  
             /* pop eflags */  
             gen_op_addl_A0_im(2 << s->dflag);  
             gen_op_ld_T1_A0[1 + s->dflag]();  
             gen_movl_seg_T0(s, R_CS, pc_start - s->cs_base);  
             gen_op_movl_T0_T1();  
             if (s->dflag) {  
                 gen_op_movl_eflags_T0();  
             } else {  
                 gen_op_movw_eflags_T0();  
             }  
             gen_stack_update(s, (6 << s->dflag));  
2957              s->cc_op = CC_OP_EFLAGS;              s->cc_op = CC_OP_EFLAGS;
2958          }          }
2959          s->is_jmp = 1;          s->is_jmp = 1;
# Line 3096  long disas_insn(DisasContext *s, uint8_t Line 3087  long disas_insn(DisasContext *s, uint8_t
3087              gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);              gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
3088          } else {          } else {
3089              gen_pop_T0(s);              gen_pop_T0(s);
3090              if (s->dflag) {              if (s->cpl == 0) {
3091                  gen_op_movl_eflags_T0();                  if (s->dflag) {
3092                        gen_op_movl_eflags_T0_cpl0();
3093                    } else {
3094                        gen_op_movw_eflags_T0_cpl0();
3095                    }
3096              } else {              } else {
3097                  gen_op_movw_eflags_T0();                  if (s->dflag) {
3098                        gen_op_movl_eflags_T0();
3099                    } else {
3100                        gen_op_movw_eflags_T0();
3101                    }
3102              }              }
3103              gen_pop_update(s);              gen_pop_update(s);
3104              s->cc_op = CC_OP_EFLAGS;              s->cc_op = CC_OP_EFLAGS;
# Line 3358  long disas_insn(DisasContext *s, uint8_t Line 3357  long disas_insn(DisasContext *s, uint8_t
3357          gen_op_cpuid();          gen_op_cpuid();
3358          break;          break;
3359      case 0xf4: /* hlt */      case 0xf4: /* hlt */
3360          /* XXX: if cpl == 0, then should do something else */          if (s->cpl != 0) {
3361          gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);              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            }
3369          break;          break;
3370      case 0x100:      case 0x100:
3371          modrm = ldub(s->pc++);          modrm = ldub(s->pc++);
# Line 3462  long disas_insn(DisasContext *s, uint8_t Line 3468  long disas_insn(DisasContext *s, uint8_t
3468                  gen_op_lmsw_T0();                  gen_op_lmsw_T0();
3469              }              }
3470              break;              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;
3481          default:          default:
3482              goto illegal_op;              goto illegal_op;
3483          }          }
# Line 3866  static void optimize_flags(uint16_t *opc Line 3882  static void optimize_flags(uint16_t *opc
3882  /* generate intermediate code in gen_opc_buf and gen_opparam_buf for  /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
3883     basic block 'tb'. If search_pc is TRUE, also generate PC     basic block 'tb'. If search_pc is TRUE, also generate PC
3884     information for each intermediate instruction. */     information for each intermediate instruction. */
3885  int gen_intermediate_code(TranslationBlock *tb, int search_pc)  static inline int gen_intermediate_code_internal(TranslationBlock *tb, int search_pc)
3886  {  {
3887      DisasContext dc1, *dc = &dc1;      DisasContext dc1, *dc = &dc1;
3888      uint8_t *pc_ptr;      uint8_t *pc_ptr;
# Line 3892  int gen_intermediate_code(TranslationBlo Line 3908  int gen_intermediate_code(TranslationBlo
3908      dc->cc_op = CC_OP_DYNAMIC;      dc->cc_op = CC_OP_DYNAMIC;
3909      dc->cs_base = cs_base;      dc->cs_base = cs_base;
3910      dc->tb = tb;      dc->tb = tb;
3911        dc->popl_esp_hack = 0;
3912        
3913      gen_opc_ptr = gen_opc_buf;      gen_opc_ptr = gen_opc_buf;
3914      gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;      gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
3915      gen_opparam_ptr = gen_opparam_buf;      gen_opparam_ptr = gen_opparam_buf;
# Line 3908  int gen_intermediate_code(TranslationBlo Line 3925  int gen_intermediate_code(TranslationBlo
3925                  while (lj < j)                  while (lj < j)
3926                      gen_opc_instr_start[lj++] = 0;                      gen_opc_instr_start[lj++] = 0;
3927                  gen_opc_pc[lj] = (uint32_t)pc_ptr;                  gen_opc_pc[lj] = (uint32_t)pc_ptr;
3928                    gen_opc_cc_op[lj] = dc->cc_op;
3929                  gen_opc_instr_start[lj] = 1;                  gen_opc_instr_start[lj] = 1;
3930              }              }
3931          }          }
# Line 3974  int gen_intermediate_code(TranslationBlo Line 3992  int gen_intermediate_code(TranslationBlo
3992      return 0;      return 0;
3993  }  }
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    
4005  CPUX86State *cpu_x86_init(void)  CPUX86State *cpu_x86_init(void)
4006  {  {
4007      CPUX86State *env;      CPUX86State *env;
# Line 4006  void cpu_x86_close(CPUX86State *env) Line 4034  void cpu_x86_close(CPUX86State *env)
4034      free(env);      free(env);
4035  }  }
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    
4228  static const char *cc_op_str[] = {  static const char *cc_op_str[] = {
4229      "DYNAMIC",      "DYNAMIC",
4230      "EFLAGS",      "EFLAGS",

Legend:
Removed from v.1.42  
changed lines
  Added in v.1.43

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26