Commit 4b4f782c78f49c78c912e1e44c6a63fb7bf9aab4

Authored by bellard
1 parent 84b7b8e7

NX support


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1677 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 120 additions and 40 deletions
target-i386/helper2.c
... ... @@ -127,7 +127,7 @@ CPUX86State *cpu_x86_init(void)
127 127 /* currently not enabled for std i386 because not fully tested */
128 128 env->cpuid_features |= CPUID_APIC;
129 129 env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
130   - env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL;
  130 + env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
131 131 env->cpuid_xlevel = 0x80000008;
132 132  
133 133 /* these features are needed for Win64 and aren't fully implemented */
... ... @@ -576,6 +576,8 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
576 576  
577 577 #else
578 578  
  579 +#define PHYS_ADDR_MASK 0xfffff000
  580 +
579 581 /* return value:
580 582 -1 = cannot handle fault
581 583 0 = nothing more to do
... ... @@ -583,37 +585,38 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
583 585 2 = soft MMU activation required for this block
584 586 */
585 587 int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
586   - int is_write, int is_user, int is_softmmu)
  588 + int is_write1, int is_user, int is_softmmu)
587 589 {
  590 + uint64_t ptep, pte;
588 591 uint32_t pdpe_addr, pde_addr, pte_addr;
589   - uint32_t pde, pte, ptep, pdpe;
590   - int error_code, is_dirty, prot, page_size, ret;
  592 + int error_code, is_dirty, prot, page_size, ret, is_write;
591 593 unsigned long paddr, page_offset;
592 594 target_ulong vaddr, virt_addr;
593 595  
594 596 #if defined(DEBUG_MMU)
595 597 printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
596   - addr, is_write, is_user, env->eip);
  598 + addr, is_write1, is_user, env->eip);
597 599 #endif
598   - is_write &= 1;
  600 + is_write = is_write1 & 1;
599 601  
600 602 if (!(env->cr[0] & CR0_PG_MASK)) {
601 603 pte = addr;
602 604 virt_addr = addr & TARGET_PAGE_MASK;
603   - prot = PAGE_READ | PAGE_WRITE;
  605 + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
604 606 page_size = 4096;
605 607 goto do_mapping;
606 608 }
607 609  
608 610 if (env->cr[4] & CR4_PAE_MASK) {
  611 + uint64_t pde, pdpe;
  612 +
609 613 /* XXX: we only use 32 bit physical addresses */
610 614 #ifdef TARGET_X86_64
611 615 if (env->hflags & HF_LMA_MASK) {
612   - uint32_t pml4e_addr, pml4e;
  616 + uint32_t pml4e_addr;
  617 + uint64_t pml4e;
613 618 int32_t sext;
614 619  
615   - /* XXX: handle user + rw rights */
616   - /* XXX: handle NX flag */
617 620 /* test virtual address sign extension */
618 621 sext = (int64_t)addr >> 47;
619 622 if (sext != 0 && sext != -1) {
... ... @@ -623,61 +626,134 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
623 626  
624 627 pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
625 628 env->a20_mask;
626   - pml4e = ldl_phys(pml4e_addr);
  629 + pml4e = ldq_phys(pml4e_addr);
627 630 if (!(pml4e & PG_PRESENT_MASK)) {
628 631 error_code = 0;
629 632 goto do_fault;
630 633 }
  634 + if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) {
  635 + error_code = PG_ERROR_RSVD_MASK;
  636 + goto do_fault;
  637 + }
631 638 if (!(pml4e & PG_ACCESSED_MASK)) {
632 639 pml4e |= PG_ACCESSED_MASK;
633 640 stl_phys_notdirty(pml4e_addr, pml4e);
634 641 }
635   -
636   - pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) &
  642 + ptep = pml4e ^ PG_NX_MASK;
  643 + pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
637 644 env->a20_mask;
638   - pdpe = ldl_phys(pdpe_addr);
  645 + pdpe = ldq_phys(pdpe_addr);
639 646 if (!(pdpe & PG_PRESENT_MASK)) {
640 647 error_code = 0;
641 648 goto do_fault;
642 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;
643 655 if (!(pdpe & PG_ACCESSED_MASK)) {
644 656 pdpe |= PG_ACCESSED_MASK;
645 657 stl_phys_notdirty(pdpe_addr, pdpe);
646 658 }
647   - } else
  659 + } else
648 660 #endif
649 661 {
  662 + /* XXX: load them when cr3 is loaded ? */
650 663 pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) &
651 664 env->a20_mask;
652   - pdpe = ldl_phys(pdpe_addr);
  665 + pdpe = ldq_phys(pdpe_addr);
653 666 if (!(pdpe & PG_PRESENT_MASK)) {
654 667 error_code = 0;
655 668 goto do_fault;
656 669 }
  670 + ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
657 671 }
658 672  
659   - pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) &
  673 + pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
660 674 env->a20_mask;
661   - pde = ldl_phys(pde_addr);
  675 + pde = ldq_phys(pde_addr);
662 676 if (!(pde & PG_PRESENT_MASK)) {
663 677 error_code = 0;
664 678 goto do_fault;
665 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;
666 685 if (pde & PG_PSE_MASK) {
667 686 /* 2 MB page */
668 687 page_size = 2048 * 1024;
669   - goto handle_big_page;
  688 + 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);
670 711 } else {
671 712 /* 4 KB page */
672 713 if (!(pde & PG_ACCESSED_MASK)) {
673 714 pde |= PG_ACCESSED_MASK;
674 715 stl_phys_notdirty(pde_addr, pde);
675 716 }
676   - pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) &
  717 + pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
677 718 env->a20_mask;
678   - goto handle_4k_page;
  719 + 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);
679 753 }
680 754 } else {
  755 + uint32_t pde;
  756 +
681 757 /* page directory entry */
682 758 pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) &
683 759 env->a20_mask;
... ... @@ -689,7 +765,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
689 765 /* if PSE bit is set, then we use a 4MB page */
690 766 if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
691 767 page_size = 4096 * 1024;
692   - handle_big_page:
693 768 if (is_user) {
694 769 if (!(pde & PG_USER_MASK))
695 770 goto do_fault_protect;
... ... @@ -720,7 +795,6 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
720 795 /* page directory entry */
721 796 pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
722 797 env->a20_mask;
723   - handle_4k_page:
724 798 pte = ldl_phys(pte_addr);
725 799 if (!(pte & PG_PRESENT_MASK)) {
726 800 error_code = 0;
... ... @@ -748,20 +822,21 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
748 822 page_size = 4096;
749 823 virt_addr = addr & ~0xfff;
750 824 }
751   -
752   - /* the page can be put in the TLB */
753   - prot = PAGE_READ;
754   - if (pte & PG_DIRTY_MASK) {
755   - /* only set write access if already dirty... otherwise wait
756   - for dirty access */
757   - if (is_user) {
758   - if (ptep & PG_RW_MASK)
759   - prot |= PAGE_WRITE;
760   - } else {
761   - if (!(env->cr[0] & CR0_WP_MASK) ||
762   - (ptep & PG_RW_MASK))
763   - prot |= PAGE_WRITE;
764   - }
  825 + }
  826 + /* the page can be put in the TLB */
  827 + prot = PAGE_READ;
  828 + if (!(ptep & PG_NX_MASK))
  829 + prot |= PAGE_EXEC;
  830 + if (pte & PG_DIRTY_MASK) {
  831 + /* only set write access if already dirty... otherwise wait
  832 + for dirty access */
  833 + if (is_user) {
  834 + if (ptep & PG_RW_MASK)
  835 + prot |= PAGE_WRITE;
  836 + } else {
  837 + if (!(env->cr[0] & CR0_WP_MASK) ||
  838 + (ptep & PG_RW_MASK))
  839 + prot |= PAGE_WRITE;
765 840 }
766 841 }
767 842 do_mapping:
... ... @@ -773,15 +848,20 @@ int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
773 848 paddr = (pte & TARGET_PAGE_MASK) + page_offset;
774 849 vaddr = virt_addr + page_offset;
775 850  
776   - ret = tlb_set_page(env, vaddr, paddr, prot, is_user, is_softmmu);
  851 + ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
777 852 return ret;
778 853 do_fault_protect:
779 854 error_code = PG_ERROR_P_MASK;
780 855 do_fault:
781 856 env->cr[2] = addr;
782   - env->error_code = (is_write << PG_ERROR_W_BIT) | error_code;
  857 + error_code |= (is_write << PG_ERROR_W_BIT);
783 858 if (is_user)
784   - env->error_code |= PG_ERROR_U_MASK;
  859 + 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;
785 865 return 1;
786 866 }
787 867  
... ...