summaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2014-06-05 21:06:13 +0100
committerPeter Maydell <peter.maydell@linaro.org>2014-06-05 21:06:14 +0100
commit31e25e3e5701607a2a88b5b6c5fb1057b20941fd (patch)
tree757e835a8cef83a5e28f5e99704854836ca5df62 /target-i386
parent9d48d3f01cf3f67d54cd7e2c7834e97a57cea0b8 (diff)
parent16b96f82cdfcb185560c2f8ebfc731711e2ccb2d (diff)
downloadqemu-31e25e3e5701607a2a88b5b6c5fb1057b20941fd.tar.gz
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.c7
-rw-r--r--target-i386/cpu.h33
-rw-r--r--target-i386/fpu_helper.c5
-rw-r--r--target-i386/helper.c396
-rw-r--r--target-i386/mem_helper.c23
-rw-r--r--target-i386/misc_helper.c47
-rw-r--r--target-i386/seg_helper.c65
-rw-r--r--target-i386/svm_helper.c5
-rw-r--r--target-i386/translate.c1
9 files changed, 242 insertions, 340 deletions
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index cbf1d979cb..dde052cc42 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 ee410af7ae..b5e1b411fb 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 a04e754e61..1b2900d5d2 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 46d20e4b89..11ca8649b5 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 83aa1038d7..1aec8a5f19 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 9cfa25f9ec..4aaf1e4d95 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 51c2833ea5..2d970d0cb9 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 ea5de6fa94..429d029a3d 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 3aa52eb795..2359787b42 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"