diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2014-06-05 21:06:13 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2014-06-05 21:06:14 +0100 |
commit | 31e25e3e5701607a2a88b5b6c5fb1057b20941fd (patch) | |
tree | 757e835a8cef83a5e28f5e99704854836ca5df62 /target-i386 | |
parent | 9d48d3f01cf3f67d54cd7e2c7834e97a57cea0b8 (diff) | |
parent | 16b96f82cdfcb185560c2f8ebfc731711e2ccb2d (diff) | |
download | qemu-31e25e3e5701607a2a88b5b6c5fb1057b20941fd.zip qemu-31e25e3e5701607a2a88b5b6c5fb1057b20941fd.tar.gz qemu-31e25e3e5701607a2a88b5b6c5fb1057b20941fd.tar.bz2 |
Merge remote-tracking branch 'remotes/bonzini/softmmu-smap' into staging
* remotes/bonzini/softmmu-smap: (33 commits)
target-i386: cleanup x86_cpu_get_phys_page_debug
target-i386: fix protection bits in the TLB for SMEP
target-i386: support long addresses for 4MB pages (PSE-36)
target-i386: raise page fault for reserved bits in large pages
target-i386: unify reserved bits and NX bit check
target-i386: simplify pte/vaddr calculation
target-i386: raise page fault for reserved physical address bits
target-i386: test reserved PS bit on PML4Es
target-i386: set correct error code for reserved bit access
target-i386: introduce support for 1 GB pages
target-i386: introduce do_check_protect label
target-i386: tweak handling of PG_NX_MASK
target-i386: commonize checks for PAE and non-PAE
target-i386: commonize checks for 4MB and 4KB pages
target-i386: commonize checks for 2MB and 4KB pages
target-i386: fix coding standards in x86_cpu_handle_mmu_fault
target-i386: simplify SMAP handling in MMU_KSMAP_IDX
target-i386: fix kernel accesses with SMAP and CPL = 3
target-i386: move check_io helpers to seg_helper.c
target-i386: rename KSMAP to KNOSMAP
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target-i386')
-rw-r--r-- | target-i386/cpu.c | 7 | ||||
-rw-r--r-- | target-i386/cpu.h | 33 | ||||
-rw-r--r-- | target-i386/fpu_helper.c | 5 | ||||
-rw-r--r-- | target-i386/helper.c | 396 | ||||
-rw-r--r-- | target-i386/mem_helper.c | 23 | ||||
-rw-r--r-- | target-i386/misc_helper.c | 47 | ||||
-rw-r--r-- | target-i386/seg_helper.c | 65 | ||||
-rw-r--r-- | target-i386/svm_helper.c | 5 | ||||
-rw-r--r-- | target-i386/translate.c | 1 |
9 files changed, 242 insertions, 340 deletions
diff --git a/target-i386/cpu.c b/target-i386/cpu.c index cbf1d97..dde052c 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -552,8 +552,7 @@ struct X86CPUDefinition { CPUID_PSE36 | CPUID_CLFLUSH | CPUID_ACPI | CPUID_MMX | \ CPUID_FXSR | CPUID_SSE | CPUID_SSE2 | CPUID_SS) /* partly implemented: - CPUID_MTRR, CPUID_MCA, CPUID_CLFLUSH (needed for Win64) - CPUID_PSE36 (needed for Solaris) */ + CPUID_MTRR, CPUID_MCA, CPUID_CLFLUSH (needed for Win64) */ /* missing: CPUID_VME, CPUID_DTS, CPUID_SS, CPUID_HT, CPUID_TM, CPUID_PBE */ #define TCG_EXT_FEATURES (CPUID_EXT_SSE3 | CPUID_EXT_PCLMULQDQ | \ @@ -569,9 +568,7 @@ struct X86CPUDefinition { CPUID_EXT_RDRAND */ #define TCG_EXT2_FEATURES ((TCG_FEATURES & CPUID_EXT2_AMD_ALIASES) | \ CPUID_EXT2_NX | CPUID_EXT2_MMXEXT | CPUID_EXT2_RDTSCP | \ - CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT) - /* missing: - CPUID_EXT2_PDPE1GB */ + CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT | CPUID_EXT2_PDPE1GB) #define TCG_EXT3_FEATURES (CPUID_EXT3_LAHF_LM | CPUID_EXT3_SVM | \ CPUID_EXT3_CR8LEG | CPUID_EXT3_ABM | CPUID_EXT3_SSE4A) #define TCG_SVM_FEATURES 0 diff --git a/target-i386/cpu.h b/target-i386/cpu.h index ee410af..b5e1b41 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -249,6 +249,7 @@ #define PG_DIRTY_BIT 6 #define PG_PSE_BIT 7 #define PG_GLOBAL_BIT 8 +#define PG_PSE_PAT_BIT 12 #define PG_NX_BIT 63 #define PG_PRESENT_MASK (1 << PG_PRESENT_BIT) @@ -260,6 +261,9 @@ #define PG_DIRTY_MASK (1 << PG_DIRTY_BIT) #define PG_PSE_MASK (1 << PG_PSE_BIT) #define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT) +#define PG_PSE_PAT_MASK (1 << PG_PSE_PAT_BIT) +#define PG_ADDRESS_MASK 0x000ffffffffff000LL +#define PG_HI_RSVD_MASK (PG_ADDRESS_MASK & ~PHYS_ADDR_MASK) #define PG_HI_USER_MASK 0x7ff0000000000000LL #define PG_NX_MASK (1LL << PG_NX_BIT) @@ -1135,6 +1139,14 @@ uint64_t cpu_get_tsc(CPUX86State *env); #define TARGET_VIRT_ADDR_SPACE_BITS 32 #endif +/* XXX: This value should match the one returned by CPUID + * and in exec.c */ +# if defined(TARGET_X86_64) +# define PHYS_ADDR_MASK 0xffffffffffLL +# else +# define PHYS_ADDR_MASK 0xfffffffffLL +# endif + static inline CPUX86State *cpu_init(const char *cpu_model) { X86CPU *cpu = cpu_x86_init(cpu_model); @@ -1151,17 +1163,24 @@ static inline CPUX86State *cpu_init(const char *cpu_model) #define cpudef_setup x86_cpudef_setup /* MMU modes definitions */ -#define MMU_MODE0_SUFFIX _kernel +#define MMU_MODE0_SUFFIX _ksmap #define MMU_MODE1_SUFFIX _user -#define MMU_MODE2_SUFFIX _ksmap /* Kernel with SMAP override */ -#define MMU_KERNEL_IDX 0 +#define MMU_MODE2_SUFFIX _knosmap /* SMAP disabled or CPL<3 && AC=1 */ +#define MMU_KSMAP_IDX 0 #define MMU_USER_IDX 1 -#define MMU_KSMAP_IDX 2 -static inline int cpu_mmu_index (CPUX86State *env) +#define MMU_KNOSMAP_IDX 2 +static inline int cpu_mmu_index(CPUX86State *env) { return (env->hflags & HF_CPL_MASK) == 3 ? MMU_USER_IDX : - ((env->hflags & HF_SMAP_MASK) && (env->eflags & AC_MASK)) - ? MMU_KSMAP_IDX : MMU_KERNEL_IDX; + (!(env->hflags & HF_SMAP_MASK) || (env->eflags & AC_MASK)) + ? MMU_KNOSMAP_IDX : MMU_KSMAP_IDX; +} + +static inline int cpu_mmu_index_kernel(CPUX86State *env) +{ + return !(env->hflags & HF_SMAP_MASK) ? MMU_KNOSMAP_IDX : + ((env->hflags & HF_CPL_MASK) < 3 && (env->eflags & AC_MASK)) + ? MMU_KNOSMAP_IDX : MMU_KSMAP_IDX; } #define CC_DST (env->cc_dst) diff --git a/target-i386/fpu_helper.c b/target-i386/fpu_helper.c index a04e754..1b2900d 100644 --- a/target-i386/fpu_helper.c +++ b/target-i386/fpu_helper.c @@ -22,10 +22,7 @@ #include "exec/helper-proto.h" #include "qemu/aes.h" #include "qemu/host-utils.h" - -#if !defined(CONFIG_USER_ONLY) -#include "exec/softmmu_exec.h" -#endif /* !defined(CONFIG_USER_ONLY) */ +#include "exec/cpu_ldst.h" #define FPU_RC_MASK 0xc00 #define FPU_RC_NEAR 0x000 diff --git a/target-i386/helper.c b/target-i386/helper.c index 46d20e4..11ca864 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -510,14 +510,6 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, #else -/* XXX: This value should match the one returned by CPUID - * and in exec.c */ -# if defined(TARGET_X86_64) -# define PHYS_ADDR_MASK 0xfffffff000LL -# else -# define PHYS_ADDR_MASK 0xffffff000LL -# endif - /* return value: * -1 = cannot handle fault * 0 = nothing more to do @@ -530,10 +522,12 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, CPUX86State *env = &cpu->env; uint64_t ptep, pte; target_ulong pde_addr, pte_addr; - int error_code, is_dirty, prot, page_size, is_write, is_user; + int error_code = 0; + int is_dirty, prot, page_size, is_write, is_user; hwaddr paddr; + uint64_t rsvd_mask = PG_HI_RSVD_MASK; uint32_t page_offset; - target_ulong vaddr, virt_addr; + target_ulong vaddr; is_user = mmu_idx == MMU_USER_IDX; #if defined(DEBUG_MMU) @@ -550,12 +544,15 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, pte = (uint32_t)pte; } #endif - virt_addr = addr & TARGET_PAGE_MASK; prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; page_size = 4096; goto do_mapping; } + if (!(env->efer & MSR_EFER_NXE)) { + rsvd_mask |= PG_NX_MASK; + } + if (env->cr[4] & CR4_PAE_MASK) { uint64_t pde, pdpe; target_ulong pdpe_addr; @@ -577,34 +574,37 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, env->a20_mask; pml4e = ldq_phys(cs->as, pml4e_addr); if (!(pml4e & PG_PRESENT_MASK)) { - error_code = 0; goto do_fault; } - if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) { - error_code = PG_ERROR_RSVD_MASK; - goto do_fault; + if (pml4e & (rsvd_mask | PG_PSE_MASK)) { + goto do_fault_rsvd; } if (!(pml4e & PG_ACCESSED_MASK)) { pml4e |= PG_ACCESSED_MASK; stl_phys_notdirty(cs->as, pml4e_addr, pml4e); } ptep = pml4e ^ PG_NX_MASK; - pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) & + pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; pdpe = ldq_phys(cs->as, pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { - error_code = 0; goto do_fault; } - if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) { - error_code = PG_ERROR_RSVD_MASK; - goto do_fault; + if (pdpe & rsvd_mask) { + goto do_fault_rsvd; } ptep &= pdpe ^ PG_NX_MASK; if (!(pdpe & PG_ACCESSED_MASK)) { pdpe |= PG_ACCESSED_MASK; stl_phys_notdirty(cs->as, pdpe_addr, pdpe); } + if (pdpe & PG_PSE_MASK) { + /* 1 GB page */ + page_size = 1024 * 1024 * 1024; + pte_addr = pdpe_addr; + pte = pdpe; + goto do_check_protect; + } } else #endif { @@ -613,134 +613,49 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, env->a20_mask; pdpe = ldq_phys(cs->as, pdpe_addr); if (!(pdpe & PG_PRESENT_MASK)) { - error_code = 0; goto do_fault; } + rsvd_mask |= PG_HI_USER_MASK | PG_NX_MASK; + if (pdpe & rsvd_mask) { + goto do_fault_rsvd; + } ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK; } - pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) & + pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask; pde = ldq_phys(cs->as, pde_addr); if (!(pde & PG_PRESENT_MASK)) { - error_code = 0; goto do_fault; } - if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) { - error_code = PG_ERROR_RSVD_MASK; - goto do_fault; + if (pde & rsvd_mask) { + goto do_fault_rsvd; } ptep &= pde ^ PG_NX_MASK; if (pde & PG_PSE_MASK) { /* 2 MB page */ page_size = 2048 * 1024; - ptep ^= PG_NX_MASK; - if ((ptep & PG_NX_MASK) && is_write1 == 2) { - goto do_fault_protect; - } - switch (mmu_idx) { - case MMU_USER_IDX: - if (!(ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - if (is_write && !(ptep & PG_RW_MASK)) { - goto do_fault_protect; - } - break; - - case MMU_KERNEL_IDX: - if (is_write1 != 2 && (env->cr[4] & CR4_SMAP_MASK) && - (ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - /* fall through */ - case MMU_KSMAP_IDX: - if (is_write1 == 2 && (env->cr[4] & CR4_SMEP_MASK) && - (ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(ptep & PG_RW_MASK)) { - goto do_fault_protect; - } - break; - - default: /* cannot happen */ - break; - } - is_dirty = is_write && !(pde & PG_DIRTY_MASK); - if (!(pde & PG_ACCESSED_MASK) || is_dirty) { - pde |= PG_ACCESSED_MASK; - if (is_dirty) - pde |= PG_DIRTY_MASK; - stl_phys_notdirty(cs->as, pde_addr, pde); - } - /* align to page_size */ - pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff); - virt_addr = addr & ~(page_size - 1); - } else { - /* 4 KB page */ - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - stl_phys_notdirty(cs->as, pde_addr, pde); - } - pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) & - env->a20_mask; - pte = ldq_phys(cs->as, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) { - error_code = PG_ERROR_RSVD_MASK; - goto do_fault; - } - /* combine pde and pte nx, user and rw protections */ - ptep &= pte ^ PG_NX_MASK; - ptep ^= PG_NX_MASK; - if ((ptep & PG_NX_MASK) && is_write1 == 2) - goto do_fault_protect; - switch (mmu_idx) { - case MMU_USER_IDX: - if (!(ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - if (is_write && !(ptep & PG_RW_MASK)) { - goto do_fault_protect; - } - break; - - case MMU_KERNEL_IDX: - if (is_write1 != 2 && (env->cr[4] & CR4_SMAP_MASK) && - (ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - /* fall through */ - case MMU_KSMAP_IDX: - if (is_write1 == 2 && (env->cr[4] & CR4_SMEP_MASK) && - (ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(ptep & PG_RW_MASK)) { - goto do_fault_protect; - } - break; - - default: /* cannot happen */ - break; - } - is_dirty = is_write && !(pte & PG_DIRTY_MASK); - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { - pte |= PG_ACCESSED_MASK; - if (is_dirty) - pte |= PG_DIRTY_MASK; - stl_phys_notdirty(cs->as, pte_addr, pte); - } - page_size = 4096; - virt_addr = addr & ~0xfff; - pte = pte & (PHYS_ADDR_MASK | 0xfff); + pte_addr = pde_addr; + pte = pde; + goto do_check_protect; + } + /* 4 KB page */ + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + stl_phys_notdirty(cs->as, pde_addr, pde); + } + pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & + env->a20_mask; + pte = ldq_phys(cs->as, pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + goto do_fault; + } + if (pte & rsvd_mask) { + goto do_fault_rsvd; } + /* combine pde and pte nx, user and rw protections */ + ptep &= pte ^ PG_NX_MASK; + page_size = 4096; } else { uint32_t pde; @@ -749,114 +664,95 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, env->a20_mask; pde = ldl_phys(cs->as, pde_addr); if (!(pde & PG_PRESENT_MASK)) { - error_code = 0; goto do_fault; } + ptep = pde | PG_NX_MASK; + /* if PSE bit is set, then we use a 4MB page */ if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { page_size = 4096 * 1024; - switch (mmu_idx) { - case MMU_USER_IDX: - if (!(pde & PG_USER_MASK)) { - goto do_fault_protect; - } - if (is_write && !(pde & PG_RW_MASK)) { - goto do_fault_protect; - } - break; - - case MMU_KERNEL_IDX: - if (is_write1 != 2 && (env->cr[4] & CR4_SMAP_MASK) && - (pde & PG_USER_MASK)) { - goto do_fault_protect; - } - /* fall through */ - case MMU_KSMAP_IDX: - if (is_write1 == 2 && (env->cr[4] & CR4_SMEP_MASK) && - (pde & PG_USER_MASK)) { - goto do_fault_protect; - } - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(pde & PG_RW_MASK)) { - goto do_fault_protect; - } - break; + pte_addr = pde_addr; + + /* Bits 20-13 provide bits 39-32 of the address, bit 21 is reserved. + * Leave bits 20-13 in place for setting accessed/dirty bits below. + */ + pte = pde | ((pde & 0x1fe000) << (32 - 13)); + rsvd_mask = 0x200000; + goto do_check_protect_pse36; + } - default: /* cannot happen */ - break; - } - is_dirty = is_write && !(pde & PG_DIRTY_MASK); - if (!(pde & PG_ACCESSED_MASK) || is_dirty) { - pde |= PG_ACCESSED_MASK; - if (is_dirty) - pde |= PG_DIRTY_MASK; - stl_phys_notdirty(cs->as, pde_addr, pde); - } + if (!(pde & PG_ACCESSED_MASK)) { + pde |= PG_ACCESSED_MASK; + stl_phys_notdirty(cs->as, pde_addr, pde); + } - pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ - ptep = pte; - virt_addr = addr & ~(page_size - 1); - } else { - if (!(pde & PG_ACCESSED_MASK)) { - pde |= PG_ACCESSED_MASK; - stl_phys_notdirty(cs->as, pde_addr, pde); - } + /* page directory entry */ + pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & + env->a20_mask; + pte = ldl_phys(cs->as, pte_addr); + if (!(pte & PG_PRESENT_MASK)) { + goto do_fault; + } + /* combine pde and pte user and rw protections */ + ptep &= pte | PG_NX_MASK; + page_size = 4096; + rsvd_mask = 0; + } - /* page directory entry */ - pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & - env->a20_mask; - pte = ldl_phys(cs->as, pte_addr); - if (!(pte & PG_PRESENT_MASK)) { - error_code = 0; - goto do_fault; - } - /* combine pde and pte user and rw protections */ - ptep = pte & pde; - switch (mmu_idx) { - case MMU_USER_IDX: - if (!(ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - if (is_write && !(ptep & PG_RW_MASK)) { - goto do_fault_protect; - } - break; +do_check_protect: + rsvd_mask |= (page_size - 1) & PG_ADDRESS_MASK & ~PG_PSE_PAT_MASK; +do_check_protect_pse36: + if (pte & rsvd_mask) { + goto do_fault_rsvd; + } + ptep ^= PG_NX_MASK; + if ((ptep & PG_NX_MASK) && is_write1 == 2) { + goto do_fault_protect; + } + switch (mmu_idx) { + case MMU_USER_IDX: + if (!(ptep & PG_USER_MASK)) { + goto do_fault_protect; + } + if (is_write && !(ptep & PG_RW_MASK)) { + goto do_fault_protect; + } + break; - case MMU_KERNEL_IDX: - if (is_write1 != 2 && (env->cr[4] & CR4_SMAP_MASK) && - (ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - /* fall through */ - case MMU_KSMAP_IDX: - if (is_write1 == 2 && (env->cr[4] & CR4_SMEP_MASK) && - (ptep & PG_USER_MASK)) { - goto do_fault_protect; - } - if ((env->cr[0] & CR0_WP_MASK) && - is_write && !(ptep & PG_RW_MASK)) { - goto do_fault_protect; - } - break; + case MMU_KSMAP_IDX: + if (is_write1 != 2 && (ptep & PG_USER_MASK)) { + goto do_fault_protect; + } + /* fall through */ + case MMU_KNOSMAP_IDX: + if (is_write1 == 2 && (env->cr[4] & CR4_SMEP_MASK) && + (ptep & PG_USER_MASK)) { + goto do_fault_protect; + } + if ((env->cr[0] & CR0_WP_MASK) && + is_write && !(ptep & PG_RW_MASK)) { + goto do_fault_protect; + } + break; - default: /* cannot happen */ - break; - } - is_dirty = is_write && !(pte & PG_DIRTY_MASK); - if (!(pte & PG_ACCESSED_MASK) || is_dirty) { - pte |= PG_ACCESSED_MASK; - if (is_dirty) - pte |= PG_DIRTY_MASK; - stl_phys_notdirty(cs->as, pte_addr, pte); - } - page_size = 4096; - virt_addr = addr & ~0xfff; + default: /* cannot happen */ + break; + } + is_dirty = is_write && !(pte & PG_DIRTY_MASK); + if (!(pte & PG_ACCESSED_MASK) || is_dirty) { + pte |= PG_ACCESSED_MASK; + if (is_dirty) { + pte |= PG_DIRTY_MASK; } + stl_phys_notdirty(cs->as, pte_addr, pte); } + /* the page can be put in the TLB */ prot = PAGE_READ; - if (!(ptep & PG_NX_MASK)) + if (!(ptep & PG_NX_MASK) && + !((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK))) { prot |= PAGE_EXEC; + } if (pte & PG_DIRTY_MASK) { /* only set write access if already dirty... otherwise wait for dirty access */ @@ -872,16 +768,21 @@ int x86_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, do_mapping: pte = pte & env->a20_mask; + /* align to page_size */ + pte &= PG_ADDRESS_MASK & ~(page_size - 1); + /* Even if 4MB pages, we map only one 4KB page in the cache to avoid filling it too fast */ - page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); - paddr = (pte & TARGET_PAGE_MASK) + page_offset; - vaddr = virt_addr + page_offset; + vaddr = addr & TARGET_PAGE_MASK; + page_offset = vaddr & (page_size - 1); + paddr = pte + page_offset; tlb_set_page(cs, vaddr, paddr, prot, mmu_idx, page_size); return 0; + do_fault_rsvd: + error_code |= PG_ERROR_RSVD_MASK; do_fault_protect: - error_code = PG_ERROR_P_MASK; + error_code |= PG_ERROR_P_MASK; do_fault: error_code |= (is_write << PG_ERROR_W_BIT); if (is_user) @@ -910,7 +811,6 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) CPUX86State *env = &cpu->env; target_ulong pde_addr, pte_addr; uint64_t pte; - hwaddr paddr; uint32_t page_offset; int page_size; @@ -928,25 +828,24 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) /* test virtual address sign extension */ sext = (int64_t)addr >> 47; - if (sext != 0 && sext != -1) + if (sext != 0 && sext != -1) { return -1; - + } pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & env->a20_mask; pml4e = ldq_phys(cs->as, pml4e_addr); - if (!(pml4e & PG_PRESENT_MASK)) + if (!(pml4e & PG_PRESENT_MASK)) { return -1; - - pdpe_addr = ((pml4e & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) + + } + pdpe_addr = ((pml4e & PG_ADDRESS_MASK) + (((addr >> 30) & 0x1ff) << 3)) & env->a20_mask; pdpe = ldq_phys(cs->as, pdpe_addr); - if (!(pdpe & PG_PRESENT_MASK)) + if (!(pdpe & PG_PRESENT_MASK)) { return -1; - + } if (pdpe & PG_PSE_MASK) { page_size = 1024 * 1024 * 1024; - pte = pdpe & ~( (page_size - 1) & ~0xfff); - pte &= ~(PG_NX_MASK | PG_HI_USER_MASK); + pte = pdpe; goto out; } @@ -960,7 +859,7 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) return -1; } - pde_addr = ((pdpe & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) + + pde_addr = ((pdpe & PG_ADDRESS_MASK) + (((addr >> 21) & 0x1ff) << 3)) & env->a20_mask; pde = ldq_phys(cs->as, pde_addr); if (!(pde & PG_PRESENT_MASK)) { @@ -969,17 +868,17 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) if (pde & PG_PSE_MASK) { /* 2 MB page */ page_size = 2048 * 1024; - pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */ + pte = pde; } else { /* 4 KB page */ - pte_addr = ((pde & ~0xfff & ~(PG_NX_MASK | PG_HI_USER_MASK)) + + pte_addr = ((pde & PG_ADDRESS_MASK) + (((addr >> 12) & 0x1ff) << 3)) & env->a20_mask; page_size = 4096; pte = ldq_phys(cs->as, pte_addr); } - pte &= ~(PG_NX_MASK | PG_HI_USER_MASK); - if (!(pte & PG_PRESENT_MASK)) + if (!(pte & PG_PRESENT_MASK)) { return -1; + } } else { uint32_t pde; @@ -989,14 +888,15 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) if (!(pde & PG_PRESENT_MASK)) return -1; if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { - pte = pde & ~0x003ff000; /* align to 4MB */ + pte = pde | ((pde & 0x1fe000) << (32 - 13)); page_size = 4096 * 1024; } else { /* page directory entry */ pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask; pte = ldl_phys(cs->as, pte_addr); - if (!(pte & PG_PRESENT_MASK)) + if (!(pte & PG_PRESENT_MASK)) { return -1; + } page_size = 4096; } pte = pte & env->a20_mask; @@ -1005,9 +905,9 @@ hwaddr x86_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) #ifdef TARGET_X86_64 out: #endif + pte &= PG_ADDRESS_MASK & ~(page_size - 1); page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1); - paddr = (pte & TARGET_PAGE_MASK) + page_offset; - return paddr; + return pte | page_offset; } void hw_breakpoint_insert(CPUX86State *env, int index) diff --git a/target-i386/mem_helper.c b/target-i386/mem_helper.c index 83aa103..1aec8a5 100644 --- a/target-i386/mem_helper.c +++ b/target-i386/mem_helper.c @@ -19,10 +19,7 @@ #include "cpu.h" #include "exec/helper-proto.h" - -#if !defined(CONFIG_USER_ONLY) -#include "exec/softmmu_exec.h" -#endif /* !defined(CONFIG_USER_ONLY) */ +#include "exec/cpu_ldst.h" /* broken thread support */ @@ -110,24 +107,6 @@ void helper_boundl(CPUX86State *env, target_ulong a0, int v) } #if !defined(CONFIG_USER_ONLY) - -#define MMUSUFFIX _mmu - -#define SHIFT 0 -#include "exec/softmmu_template.h" - -#define SHIFT 1 -#include "exec/softmmu_template.h" - -#define SHIFT 2 -#include "exec/softmmu_template.h" - -#define SHIFT 3 -#include "exec/softmmu_template.h" - -#endif - -#if !defined(CONFIG_USER_ONLY) /* try to fill the TLB and return an exception if error. If retaddr is * NULL, it means that the function was called in C code (i.e. not * from generated code or from helper.c) diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c index 9cfa25f..4aaf1e4 100644 --- a/target-i386/misc_helper.c +++ b/target-i386/misc_helper.c @@ -20,52 +20,7 @@ #include "cpu.h" #include "exec/ioport.h" #include "exec/helper-proto.h" - -#if !defined(CONFIG_USER_ONLY) -#include "exec/softmmu_exec.h" -#endif /* !defined(CONFIG_USER_ONLY) */ - -/* check if Port I/O is allowed in TSS */ -static inline void check_io(CPUX86State *env, int addr, int size) -{ - int io_offset, val, mask; - - /* TSS must be a valid 32 bit one */ - if (!(env->tr.flags & DESC_P_MASK) || - ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || - env->tr.limit < 103) { - goto fail; - } - io_offset = cpu_lduw_kernel(env, env->tr.base + 0x66); - io_offset += (addr >> 3); - /* Note: the check needs two bytes */ - if ((io_offset + 1) > env->tr.limit) { - goto fail; - } - val = cpu_lduw_kernel(env, env->tr.base + io_offset); - val >>= (addr & 7); - mask = (1 << size) - 1; - /* all bits must be zero to allow the I/O */ - if ((val & mask) != 0) { - fail: - raise_exception_err(env, EXCP0D_GPF, 0); - } -} - -void helper_check_iob(CPUX86State *env, uint32_t t0) -{ - check_io(env, t0, 1); -} - -void helper_check_iow(CPUX86State *env, uint32_t t0) -{ - check_io(env, t0, 2); -} - -void helper_check_iol(CPUX86State *env, uint32_t t0) -{ - check_io(env, t0, 4); -} +#include "exec/cpu_ldst.h" void helper_outb(uint32_t port, uint32_t data) { diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c index 51c2833..2d970d0 100644 --- a/target-i386/seg_helper.c +++ b/target-i386/seg_helper.c @@ -21,13 +21,10 @@ #include "cpu.h" #include "qemu/log.h" #include "exec/helper-proto.h" +#include "exec/cpu_ldst.h" //#define DEBUG_PCALL -#if !defined(CONFIG_USER_ONLY) -#include "exec/softmmu_exec.h" -#endif /* !defined(CONFIG_USER_ONLY) */ - #ifdef DEBUG_PCALL # define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__) # define LOG_PCALL_STATE(cpu) \ @@ -37,6 +34,24 @@ # define LOG_PCALL_STATE(cpu) do { } while (0) #endif +#ifndef CONFIG_USER_ONLY +#define CPU_MMU_INDEX (cpu_mmu_index_kernel(env)) +#define MEMSUFFIX _kernel +#define DATA_SIZE 1 +#include "exec/cpu_ldst_template.h" + +#define DATA_SIZE 2 +#include "exec/cpu_ldst_template.h" + +#define DATA_SIZE 4 +#include "exec/cpu_ldst_template.h" + +#define DATA_SIZE 8 +#include "exec/cpu_ldst_template.h" +#undef CPU_MMU_INDEX +#undef MEMSUFFIX +#endif + /* return non zero if error */ static inline int load_segment(CPUX86State *env, uint32_t *e1_ptr, uint32_t *e2_ptr, int selector) @@ -2471,3 +2486,45 @@ void cpu_x86_load_seg(CPUX86State *env, int seg_reg, int selector) } } #endif + +/* check if Port I/O is allowed in TSS */ +static inline void check_io(CPUX86State *env, int addr, int size) +{ + int io_offset, val, mask; + + /* TSS must be a valid 32 bit one */ + if (!(env->tr.flags & DESC_P_MASK) || + ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 || + env->tr.limit < 103) { + goto fail; + } + io_offset = cpu_lduw_kernel(env, env->tr.base + 0x66); + io_offset += (addr >> 3); + /* Note: the check needs two bytes */ + if ((io_offset + 1) > env->tr.limit) { + goto fail; + } + val = cpu_lduw_kernel(env, env->tr.base + io_offset); + val >>= (addr & 7); + mask = (1 << size) - 1; + /* all bits must be zero to allow the I/O */ + if ((val & mask) != 0) { + fail: + raise_exception_err(env, EXCP0D_GPF, 0); + } +} + +void helper_check_iob(CPUX86State *env, uint32_t t0) +{ + check_io(env, t0, 1); +} + +void helper_check_iow(CPUX86State *env, uint32_t t0) +{ + check_io(env, t0, 2); +} + +void helper_check_iol(CPUX86State *env, uint32_t t0) +{ + check_io(env, t0, 4); +} diff --git a/target-i386/svm_helper.c b/target-i386/svm_helper.c index ea5de6f..429d029 100644 --- a/target-i386/svm_helper.c +++ b/target-i386/svm_helper.c @@ -20,10 +20,7 @@ #include "cpu.h" #include "exec/cpu-all.h" #include "exec/helper-proto.h" - -#if !defined(CONFIG_USER_ONLY) -#include "exec/softmmu_exec.h" -#endif /* !defined(CONFIG_USER_ONLY) */ +#include "exec/cpu_ldst.h" /* Secure Virtual Machine helpers */ diff --git a/target-i386/translate.c b/target-i386/translate.c index 3aa52eb..2359787 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -27,6 +27,7 @@ #include "cpu.h" #include "disas/disas.h" #include "tcg-op.h" +#include "exec/cpu_ldst.h" #include "exec/helper-proto.h" #include "exec/helper-gen.h" |