Commit f51589dad53ff431d827f1326b5313b81488e0dc

Authored by bellard
1 parent 82e41634

Support resolving addresses in PAE mode in cpu_get_phys_page_debug


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1240 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 73 additions and 19 deletions
target-i386/helper2.c
... ... @@ -742,33 +742,87 @@ target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
742 742 #else
743 743 target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
744 744 {
745   - uint8_t *pde_ptr, *pte_ptr;
  745 + uint32_t pde_addr, pte_addr;
746 746 uint32_t pde, pte, paddr, page_offset, page_size;
747 747  
748   - if (!(env->cr[0] & CR0_PG_MASK)) {
749   - pte = addr;
750   - page_size = 4096;
751   - } else {
752   - /* page directory entry */
753   - pde_ptr = phys_ram_base +
754   - (((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask);
755   - pde = ldl_raw(pde_ptr);
756   - if (!(pde & PG_PRESENT_MASK))
  748 + if (env->cr[4] & CR4_PAE_MASK) {
  749 + uint32_t pdpe_addr, pde_addr, pte_addr;
  750 + uint32_t pdpe;
  751 +
  752 + /* XXX: we only use 32 bit physical addresses */
  753 +#ifdef TARGET_X86_64
  754 + if (env->hflags & HF_LMA_MASK) {
  755 + uint32_t pml4e_addr, pml4e;
  756 + int32_t sext;
  757 +
  758 + /* test virtual address sign extension */
  759 + sext = (int64_t)addr >> 47;
  760 + if (sext != 0 && sext != -1)
  761 + return -1;
  762 +
  763 + pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
  764 + env->a20_mask;
  765 + pml4e = ldl_phys_aligned(pml4e_addr);
  766 + if (!(pml4e & PG_PRESENT_MASK))
  767 + return -1;
  768 +
  769 + pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) &
  770 + env->a20_mask;
  771 + pdpe = ldl_phys_aligned(pdpe_addr);
  772 + if (!(pdpe & PG_PRESENT_MASK))
  773 + return -1;
  774 + } else
  775 +#endif
  776 + {
  777 + pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) &
  778 + env->a20_mask;
  779 + pdpe = ldl_phys_aligned(pdpe_addr);
  780 + if (!(pdpe & PG_PRESENT_MASK))
  781 + return -1;
  782 + }
  783 +
  784 + pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) &
  785 + env->a20_mask;
  786 + pde = ldl_phys_aligned(pde_addr);
  787 + if (!(pde & PG_PRESENT_MASK)) {
757 788 return -1;
758   - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
759   - pte = pde & ~0x003ff000; /* align to 4MB */
760   - page_size = 4096 * 1024;
  789 + }
  790 + if (pde & PG_PSE_MASK) {
  791 + /* 2 MB page */
  792 + page_size = 2048 * 1024;
  793 + pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
  794 + } else {
  795 + /* 4 KB page */
  796 + pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) &
  797 + env->a20_mask;
  798 + page_size = 4096;
  799 + pte = ldl_phys_aligned(pte_addr);
  800 + }
  801 + } else {
  802 + if (!(env->cr[0] & CR0_PG_MASK)) {
  803 + pte = addr;
  804 + page_size = 4096;
761 805 } else {
762 806 /* page directory entry */
763   - pte_ptr = phys_ram_base +
764   - (((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask);
765   - pte = ldl_raw(pte_ptr);
766   - if (!(pte & PG_PRESENT_MASK))
  807 + pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask;
  808 + pde = ldl_phys_aligned(pde_addr);
  809 + if (!(pde & PG_PRESENT_MASK))
767 810 return -1;
768   - page_size = 4096;
  811 + if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
  812 + pte = pde & ~0x003ff000; /* align to 4MB */
  813 + page_size = 4096 * 1024;
  814 + } else {
  815 + /* page directory entry */
  816 + pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask;
  817 + pte = ldl_phys_aligned(pte_addr);
  818 + if (!(pte & PG_PRESENT_MASK))
  819 + return -1;
  820 + page_size = 4096;
  821 + }
769 822 }
  823 + pte = pte & env->a20_mask;
770 824 }
771   - pte = pte & env->a20_mask;
  825 +
772 826 page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
773 827 paddr = (pte & TARGET_PAGE_MASK) + page_offset;
774 828 return paddr;
... ...