| 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 */ |
| 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 |
| 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) { |
| 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; |
| 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; |
| 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; |
| 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: |
| 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 |
|
|