/[qemu]/qemu/target-i386/helper2.c
ViewVC logotype

Diff of /qemu/target-i386/helper2.c

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

revision 1.37 by bellard, Wed Nov 23 21:02:10 2005 UTC revision 1.38 by bellard, Mon Nov 28 21:19:42 2005 UTC
# Line 127  CPUX86State *cpu_x86_init(void) Line 127  CPUX86State *cpu_x86_init(void)
127          /* currently not enabled for std i386 because not fully tested */          /* currently not enabled for std i386 because not fully tested */
128          env->cpuid_features |= CPUID_APIC;          env->cpuid_features |= CPUID_APIC;
129          env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);          env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
130          env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL;          env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
131          env->cpuid_xlevel = 0x80000008;          env->cpuid_xlevel = 0x80000008;
132    
133          /* these features are needed for Win64 and aren't fully implemented */          /* these features are needed for Win64 and aren't fully implemented */
# Line 576  target_ulong cpu_get_phys_page_debug(CPU Line 576  target_ulong cpu_get_phys_page_debug(CPU
576    
577  #else  #else
578    
579    #define PHYS_ADDR_MASK 0xfffff000
580    
581  /* return value:  /* return value:
582     -1 = cannot handle fault     -1 = cannot handle fault
583     0  = nothing more to do     0  = nothing more to do
# Line 583  target_ulong cpu_get_phys_page_debug(CPU Line 585  target_ulong cpu_get_phys_page_debug(CPU
585     2  = soft MMU activation required for this block     2  = soft MMU activation required for this block
586  */  */
587  int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,  int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
588                               int is_write, int is_user, int is_softmmu)                               int is_write1, int is_user, int is_softmmu)
589  {  {
590        uint64_t ptep, pte;
591      uint32_t pdpe_addr, pde_addr, pte_addr;      uint32_t pdpe_addr, pde_addr, pte_addr;
592      uint32_t pde, pte, ptep, pdpe;      int error_code, is_dirty, prot, page_size, ret, is_write;
     int error_code, is_dirty, prot, page_size, ret;  
593      unsigned long paddr, page_offset;      unsigned long paddr, page_offset;
594      target_ulong vaddr, virt_addr;      target_ulong vaddr, virt_addr;
595            
596  #if defined(DEBUG_MMU)  #if defined(DEBUG_MMU)
597      printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",      printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
598             addr, is_write, is_user, env->eip);             addr, is_write1, is_user, env->eip);
599  #endif  #endif
600      is_write &= 1;      is_write = is_write1 & 1;
601            
602      if (!(env->cr[0] & CR0_PG_MASK)) {      if (!(env->cr[0] & CR0_PG_MASK)) {
603          pte = addr;          pte = addr;
604          virt_addr = addr & TARGET_PAGE_MASK;          virt_addr = addr & TARGET_PAGE_MASK;
605          prot = PAGE_READ | PAGE_WRITE;          prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
606          page_size = 4096;          page_size = 4096;
607          goto do_mapping;          goto do_mapping;
608      }      }
609    
610      if (env->cr[4] & CR4_PAE_MASK) {      if (env->cr[4] & CR4_PAE_MASK) {
611            uint64_t pde, pdpe;
612    
613          /* XXX: we only use 32 bit physical addresses */          /* XXX: we only use 32 bit physical addresses */
614  #ifdef TARGET_X86_64  #ifdef TARGET_X86_64
615          if (env->hflags & HF_LMA_MASK) {          if (env->hflags & HF_LMA_MASK) {
616              uint32_t pml4e_addr, pml4e;              uint32_t pml4e_addr;
617                uint64_t pml4e;
618              int32_t sext;              int32_t sext;
619    
             /* XXX: handle user + rw rights */  
             /* XXX: handle NX flag */  
620              /* test virtual address sign extension */              /* test virtual address sign extension */
621              sext = (int64_t)addr >> 47;              sext = (int64_t)addr >> 47;
622              if (sext != 0 && sext != -1) {              if (sext != 0 && sext != -1) {
# Line 623  int cpu_x86_handle_mmu_fault(CPUX86State Line 626  int cpu_x86_handle_mmu_fault(CPUX86State
626                            
627              pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &              pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
628                  env->a20_mask;                  env->a20_mask;
629              pml4e = ldl_phys(pml4e_addr);              pml4e = ldq_phys(pml4e_addr);
630              if (!(pml4e & PG_PRESENT_MASK)) {              if (!(pml4e & PG_PRESENT_MASK)) {
631                  error_code = 0;                  error_code = 0;
632                  goto do_fault;                  goto do_fault;
633              }              }
634                if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) {
635                    error_code = PG_ERROR_RSVD_MASK;
636                    goto do_fault;
637                }
638              if (!(pml4e & PG_ACCESSED_MASK)) {              if (!(pml4e & PG_ACCESSED_MASK)) {
639                  pml4e |= PG_ACCESSED_MASK;                  pml4e |= PG_ACCESSED_MASK;
640                  stl_phys_notdirty(pml4e_addr, pml4e);                  stl_phys_notdirty(pml4e_addr, pml4e);
641              }              }
642                            ptep = pml4e ^ PG_NX_MASK;
643              pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) &              pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
644                  env->a20_mask;                  env->a20_mask;
645              pdpe = ldl_phys(pdpe_addr);              pdpe = ldq_phys(pdpe_addr);
646              if (!(pdpe & PG_PRESENT_MASK)) {              if (!(pdpe & PG_PRESENT_MASK)) {
647                  error_code = 0;                  error_code = 0;
648                  goto do_fault;                  goto do_fault;
649              }              }
650                if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) {
651                    error_code = PG_ERROR_RSVD_MASK;
652                    goto do_fault;
653                }
654                ptep &= pdpe ^ PG_NX_MASK;
655              if (!(pdpe & PG_ACCESSED_MASK)) {              if (!(pdpe & PG_ACCESSED_MASK)) {
656                  pdpe |= PG_ACCESSED_MASK;                  pdpe |= PG_ACCESSED_MASK;
657                  stl_phys_notdirty(pdpe_addr, pdpe);                  stl_phys_notdirty(pdpe_addr, pdpe);
658              }              }
659          } else          } else
660  #endif  #endif
661          {          {
662                /* XXX: load them when cr3 is loaded ? */
663              pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) &              pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) &
664                  env->a20_mask;                  env->a20_mask;
665              pdpe = ldl_phys(pdpe_addr);              pdpe = ldq_phys(pdpe_addr);
666              if (!(pdpe & PG_PRESENT_MASK)) {              if (!(pdpe & PG_PRESENT_MASK)) {
667                  error_code = 0;                  error_code = 0;
668                  goto do_fault;                  goto do_fault;
669              }              }
670                ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
671          }          }
672    
673          pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) &          pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
674              env->a20_mask;              env->a20_mask;
675          pde = ldl_phys(pde_addr);          pde = ldq_phys(pde_addr);
676          if (!(pde & PG_PRESENT_MASK)) {          if (!(pde & PG_PRESENT_MASK)) {
677              error_code = 0;              error_code = 0;
678              goto do_fault;              goto do_fault;
679          }          }
680            if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) {
681                error_code = PG_ERROR_RSVD_MASK;
682                goto do_fault;
683            }
684            ptep &= pde ^ PG_NX_MASK;
685          if (pde & PG_PSE_MASK) {          if (pde & PG_PSE_MASK) {
686              /* 2 MB page */              /* 2 MB page */
687              page_size = 2048 * 1024;              page_size = 2048 * 1024;
688              goto handle_big_page;              ptep ^= PG_NX_MASK;
689                if ((ptep & PG_NX_MASK) && is_write1 == 2)
690                    goto do_fault_protect;
691                if (is_user) {
692                    if (!(ptep & PG_USER_MASK))
693                        goto do_fault_protect;
694                    if (is_write && !(ptep & PG_RW_MASK))
695                        goto do_fault_protect;
696                } else {
697                    if ((env->cr[0] & CR0_WP_MASK) &&
698                        is_write && !(ptep & PG_RW_MASK))
699                        goto do_fault_protect;
700                }
701                is_dirty = is_write && !(pde & PG_DIRTY_MASK);
702                if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
703                    pde |= PG_ACCESSED_MASK;
704                    if (is_dirty)
705                        pde |= PG_DIRTY_MASK;
706                    stl_phys_notdirty(pde_addr, pde);
707                }
708                /* align to page_size */
709                pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff);
710                virt_addr = addr & ~(page_size - 1);
711          } else {          } else {
712              /* 4 KB page */              /* 4 KB page */
713              if (!(pde & PG_ACCESSED_MASK)) {              if (!(pde & PG_ACCESSED_MASK)) {
714                  pde |= PG_ACCESSED_MASK;                  pde |= PG_ACCESSED_MASK;
715                  stl_phys_notdirty(pde_addr, pde);                  stl_phys_notdirty(pde_addr, pde);
716              }              }
717              pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) &              pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
718                  env->a20_mask;                  env->a20_mask;
719              goto handle_4k_page;              pte = ldq_phys(pte_addr);
720                if (!(pte & PG_PRESENT_MASK)) {
721                    error_code = 0;
722                    goto do_fault;
723                }
724                if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) {
725                    error_code = PG_ERROR_RSVD_MASK;
726                    goto do_fault;
727                }
728                /* combine pde and pte nx, user and rw protections */
729                ptep &= pte ^ PG_NX_MASK;
730                ptep ^= PG_NX_MASK;
731                if ((ptep & PG_NX_MASK) && is_write1 == 2)
732                    goto do_fault_protect;
733                if (is_user) {
734                    if (!(ptep & PG_USER_MASK))
735                        goto do_fault_protect;
736                    if (is_write && !(ptep & PG_RW_MASK))
737                        goto do_fault_protect;
738                } else {
739                    if ((env->cr[0] & CR0_WP_MASK) &&
740                        is_write && !(ptep & PG_RW_MASK))
741                        goto do_fault_protect;
742                }
743                is_dirty = is_write && !(pte & PG_DIRTY_MASK);
744                if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
745                    pte |= PG_ACCESSED_MASK;
746                    if (is_dirty)
747                        pte |= PG_DIRTY_MASK;
748                    stl_phys_notdirty(pte_addr, pte);
749                }
750                page_size = 4096;
751                virt_addr = addr & ~0xfff;
752                pte = pte & (PHYS_ADDR_MASK | 0xfff);
753          }          }
754      } else {      } else {
755            uint32_t pde;
756    
757          /* page directory entry */          /* page directory entry */
758          pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) &          pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) &
759              env->a20_mask;              env->a20_mask;
# Line 689  int cpu_x86_handle_mmu_fault(CPUX86State Line 765  int cpu_x86_handle_mmu_fault(CPUX86State
765          /* if PSE bit is set, then we use a 4MB page */          /* if PSE bit is set, then we use a 4MB page */
766          if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {          if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
767              page_size = 4096 * 1024;              page_size = 4096 * 1024;
         handle_big_page:  
768              if (is_user) {              if (is_user) {
769                  if (!(pde & PG_USER_MASK))                  if (!(pde & PG_USER_MASK))
770                      goto do_fault_protect;                      goto do_fault_protect;
# Line 720  int cpu_x86_handle_mmu_fault(CPUX86State Line 795  int cpu_x86_handle_mmu_fault(CPUX86State
795              /* page directory entry */              /* page directory entry */
796              pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &              pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
797                  env->a20_mask;                  env->a20_mask;
         handle_4k_page:  
798              pte = ldl_phys(pte_addr);              pte = ldl_phys(pte_addr);
799              if (!(pte & PG_PRESENT_MASK)) {              if (!(pte & PG_PRESENT_MASK)) {
800                  error_code = 0;                  error_code = 0;
# Line 748  int cpu_x86_handle_mmu_fault(CPUX86State Line 822  int cpu_x86_handle_mmu_fault(CPUX86State
822              page_size = 4096;              page_size = 4096;
823              virt_addr = addr & ~0xfff;              virt_addr = addr & ~0xfff;
824          }          }
825        }
826          /* the page can be put in the TLB */      /* the page can be put in the TLB */
827          prot = PAGE_READ;      prot = PAGE_READ;
828          if (pte & PG_DIRTY_MASK) {      if (!(ptep & PG_NX_MASK))
829              /* only set write access if already dirty... otherwise wait          prot |= PAGE_EXEC;
830                 for dirty access */      if (pte & PG_DIRTY_MASK) {
831              if (is_user) {          /* only set write access if already dirty... otherwise wait
832                  if (ptep & PG_RW_MASK)             for dirty access */
833                      prot |= PAGE_WRITE;          if (is_user) {
834              } else {              if (ptep & PG_RW_MASK)
835                  if (!(env->cr[0] & CR0_WP_MASK) ||                  prot |= PAGE_WRITE;
836                      (ptep & PG_RW_MASK))          } else {
837                      prot |= PAGE_WRITE;              if (!(env->cr[0] & CR0_WP_MASK) ||
838              }                  (ptep & PG_RW_MASK))
839                    prot |= PAGE_WRITE;
840          }          }
841      }      }
842   do_mapping:   do_mapping:
# Line 773  int cpu_x86_handle_mmu_fault(CPUX86State Line 848  int cpu_x86_handle_mmu_fault(CPUX86State
848      paddr = (pte & TARGET_PAGE_MASK) + page_offset;      paddr = (pte & TARGET_PAGE_MASK) + page_offset;
849      vaddr = virt_addr + page_offset;      vaddr = virt_addr + page_offset;
850            
851      ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);      ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
852      return ret;      return ret;
853   do_fault_protect:   do_fault_protect:
854      error_code = PG_ERROR_P_MASK;      error_code = PG_ERROR_P_MASK;
855   do_fault:   do_fault:
856      env->cr[2] = addr;      env->cr[2] = addr;
857      env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;      error_code |= (is_write << PG_ERROR_W_BIT);
858      if (is_user)      if (is_user)
859          env->error_code |= PG_ERROR_U_MASK;          error_code |= PG_ERROR_U_MASK;
860        if (is_write1 == 2 &&
861            (env->efer & MSR_EFER_NXE) &&
862            (env->cr[4] & CR4_PAE_MASK))
863            error_code |= PG_ERROR_I_D_MASK;
864        env->error_code = error_code;
865      return 1;      return 1;
866  }  }
867    

Legend:
Removed from v.1.37  
changed lines
  Added in v.1.38

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