Large page TLB flush
+ Remove unused is_softmmu parameter.
Upstream d4c430a80f000d722bb70287af4d4c184a8d7006
Upstream 97b348e7d221c94ddde609346407bd2cd6f85044
Change-Id: I7ccc6a8ffc040f91a58a3206d95417d22001b67b
diff --git a/cputlb.c b/cputlb.c
index d234d5a..d68c25d 100644
--- a/cputlb.c
+++ b/cputlb.c
@@ -68,6 +68,9 @@
}
memset(env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
+
+ env->tlb_flush_addr = -1;
+ env->tlb_flush_mask = 0;
tlb_flush_count++;
}
@@ -91,6 +94,16 @@
#if defined(DEBUG_TLB)
printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
#endif
+ /* Check if we need to flush due to large pages. */
+ if ((addr & env->tlb_flush_mask) == env->tlb_flush_addr) {
+#if defined(DEBUG_TLB)
+ printf("tlb_flush_page: forced full flush ("
+ TARGET_FMT_lx "/" TARGET_FMT_lx ")\n",
+ env->tlb_flush_addr, env->tlb_flush_mask);
+#endif
+ tlb_flush(env, 1);
+ return;
+ }
/* must reset current TB so that interrupts cannot modify the
links while we are modifying them */
env->current_tb = NULL;
@@ -161,13 +174,35 @@
}
}
-/* add a new TLB entry. At most one entry for a given virtual address
- is permitted. Return 0 if OK or 2 if the page could not be mapped
- (can only happen in non SOFTMMU mode for I/O pages or pages
- conflicting with the host address space). */
-int tlb_set_page_exec(CPUArchState *env, target_ulong vaddr,
- hwaddr paddr, int prot,
- int mmu_idx, int is_softmmu)
+/* Our TLB does not support large pages, so remember the area covered by
+ large pages and trigger a full TLB flush if these are invalidated. */
+static void tlb_add_large_page(CPUArchState *env, target_ulong vaddr,
+ target_ulong size)
+{
+ target_ulong mask = ~(size - 1);
+
+ if (env->tlb_flush_addr == (target_ulong)-1) {
+ env->tlb_flush_addr = vaddr & mask;
+ env->tlb_flush_mask = mask;
+ return;
+ }
+ /* Extend the existing region to include the new page.
+ This is a compromise between unnecessary flushes and the cost
+ of maintaining a full variable size TLB. */
+ mask &= env->tlb_flush_mask;
+ while (((env->tlb_flush_addr ^ vaddr) & mask) != 0) {
+ mask <<= 1;
+ }
+ env->tlb_flush_addr &= mask;
+ env->tlb_flush_mask = mask;
+}
+
+/* Add a new TLB entry. At most one entry for a given virtual address
+ is permitted. Only a single TARGET_PAGE_SIZE region is mapped, the
+ supplied size is only used by tlb_flush_page. */
+void tlb_set_page(CPUArchState *env, target_ulong vaddr,
+ hwaddr paddr, int prot,
+ int mmu_idx, target_ulong size)
{
PhysPageDesc *p;
unsigned long pd;
@@ -175,11 +210,14 @@
target_ulong address;
target_ulong code_address;
ptrdiff_t addend;
- int ret;
CPUTLBEntry *te;
CPUWatchpoint *wp;
hwaddr iotlb;
+ assert(size >= TARGET_PAGE_SIZE);
+ if (size != TARGET_PAGE_SIZE) {
+ tlb_add_large_page(env, vaddr, size);
+ }
p = phys_page_find(paddr >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
@@ -188,11 +226,10 @@
}
#if defined(DEBUG_TLB)
printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
- " prot=%x idx=%d smmu=%d pd=0x%08lx\n",
- vaddr, paddr, prot, mmu_idx, is_softmmu, pd);
+ " prot=%x idx=%d pd=0x%08lx\n",
+ vaddr, paddr, prot, mmu_idx, pd);
#endif
- ret = 0;
address = vaddr;
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
/* IO memory case (romd handled later) */
@@ -280,7 +317,8 @@
* - Cached page belongs to RAM, not I/O area.
* - Page is cached for read, or write access.
*/
- if (memcheck_instrument_mmu && mmu_idx == 1 && !is_softmmu &&
+#if 0
+ if (memcheck_instrument_mmu && mmu_idx == 1 &&
(pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
(prot & (PAGE_READ | PAGE_WRITE)) &&
memcheck_is_checked(vaddr & TARGET_PAGE_MASK, TARGET_PAGE_SIZE)) {
@@ -291,18 +329,8 @@
te->addr_write ^= TARGET_PAGE_MASK;
}
}
+#endif
#endif // CONFIG_ANDROID_MEMCHECK
-
- return ret;
-}
-
-int tlb_set_page(CPUArchState *env1, target_ulong vaddr,
- hwaddr paddr, int prot,
- int mmu_idx, int is_softmmu)
-{
- if (prot & PAGE_READ)
- prot |= PAGE_EXEC;
- return tlb_set_page_exec(env1, vaddr, paddr, prot, mmu_idx, is_softmmu);
}
/* NOTE: this function can trigger an exception */
diff --git a/include/exec/cpu-defs.h b/include/exec/cpu-defs.h
index fdaf5c4..43ead8e 100644
--- a/include/exec/cpu-defs.h
+++ b/include/exec/cpu-defs.h
@@ -108,7 +108,7 @@
#define CPU_COMMON_TLB \
/* The meaning of the MMU modes is defined in the target code. */ \
CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \
- hwaddr iotlb[NB_MMU_MODES][CPU_TLB_SIZE]; \
+ hwaddr iotlb[NB_MMU_MODES][CPU_TLB_SIZE]; \
target_ulong tlb_flush_addr; \
target_ulong tlb_flush_mask;
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index c3d1a78..45a7530 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -91,12 +91,9 @@
/* cputlb.c */
void tlb_flush_page(CPUArchState *env, target_ulong addr);
void tlb_flush(CPUArchState *env, int flush_global);
-int tlb_set_page_exec(CPUArchState *env, target_ulong vaddr,
- hwaddr paddr, int prot,
- int mmu_idx, int is_softmmu);
-int tlb_set_page(CPUArchState *env1, target_ulong vaddr,
- hwaddr paddr, int prot,
- int mmu_idx, int is_softmmu);
+void tlb_set_page(CPUArchState *env, target_ulong vaddr,
+ hwaddr paddr, int prot,
+ int mmu_idx, target_ulong size);
void tb_reset_jump_recursive(TranslationBlock *tb);
void tb_invalidate_phys_addr(hwaddr addr);
#else
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 0ef41fa..38b783f 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -302,7 +302,7 @@
int cpu_arm_signal_handler(int host_signum, void *pinfo,
void *puc);
int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
- int mmu_idx, int is_softmuu);
+ int mmu_idx);
#define cpu_handle_mmu_fault cpu_arm_handle_mmu_fault
static inline void cpu_set_tls(CPUARMState *env, target_ulong newtls)
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 201e2f4..570d98f 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -597,7 +597,7 @@
}
int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address, int rw,
- int mmu_idx, int is_softmmu)
+ int mmu_idx)
{
if (rw == 2) {
env->exception_index = EXCP_PREFETCH_ABORT;
@@ -1303,9 +1303,9 @@
static
#endif
int get_phys_addr(CPUARMState *env, uint32_t address,
- int access_type, int is_user,
- uint32_t *phys_ptr, int *prot,
- target_ulong *page_size)
+ int access_type, int is_user,
+ uint32_t *phys_ptr, int *prot,
+ target_ulong *page_size)
{
/* Fast Context Switch Extension. */
if (address < 0x02000000)
@@ -1319,8 +1319,8 @@
return 0;
} else if (arm_feature(env, ARM_FEATURE_MPU)) {
*page_size = TARGET_PAGE_SIZE;
- return get_phys_addr_mpu(env, address, access_type, is_user, phys_ptr,
- prot);
+ return get_phys_addr_mpu(env, address, access_type, is_user, phys_ptr,
+ prot);
} else if (env->cp15.c1_sys & (1 << 23)) {
return get_phys_addr_v6(env, address, access_type, is_user, phys_ptr,
prot, page_size);
@@ -1331,7 +1331,7 @@
}
int cpu_arm_handle_mmu_fault (CPUARMState *env, target_ulong address,
- int access_type, int mmu_idx, int is_softmmu)
+ int access_type, int mmu_idx)
{
uint32_t phys_addr;
target_ulong page_size;
@@ -1345,7 +1345,8 @@
/* Map a single [sub]page. */
phys_addr &= ~(uint32_t)0x3ff;
address &= ~(uint32_t)0x3ff;
- tlb_set_page (env, address, phys_addr, prot, mmu_idx, page_size);
+ tlb_set_page (env, address, phys_addr, prot | PAGE_EXEC, mmu_idx,
+ page_size);
return 0;
}
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index a4a5bcd..3cafd5f 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -86,7 +86,7 @@
generated code */
saved_env = env;
env = env1;
- ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+ ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (unlikely(ret)) {
if (retaddr) {
/* now we have a real cpu fault */
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index f8b7837..e1af551 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -956,7 +956,7 @@
/* helper.c */
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
- int is_write, int mmu_idx, int is_softmmu);
+ int is_write, int mmu_idx);
void cpu_x86_set_a20(CPUX86State *env, int a20_state);
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
uint32_t *eax, uint32_t *ebx,
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 5d808f7..be54783 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -928,7 +928,7 @@
#if defined(CONFIG_USER_ONLY)
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
- int is_write, int mmu_idx, int is_softmmu)
+ int is_write, int mmu_idx)
{
/* user mode only emulation */
is_write &= 1;
@@ -958,14 +958,13 @@
-1 = cannot handle fault
0 = nothing more to do
1 = generate PF fault
- 2 = soft MMU activation required for this block
*/
int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
- int is_write1, int mmu_idx, int is_softmmu)
+ int is_write1, int mmu_idx)
{
uint64_t ptep, pte;
target_ulong pde_addr, pte_addr;
- int error_code, is_dirty, prot, page_size, ret, is_write, is_user;
+ int error_code, is_dirty, prot, page_size, is_write, is_user;
hwaddr paddr;
uint32_t page_offset;
target_ulong vaddr, virt_addr;
@@ -1226,8 +1225,8 @@
paddr = (pte & TARGET_PAGE_MASK) + page_offset;
vaddr = virt_addr + page_offset;
- ret = tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu);
- return ret;
+ tlb_set_page(env, vaddr, paddr, prot, mmu_idx, page_size);
+ return 0;
do_fault_protect:
error_code = PG_ERROR_P_MASK;
do_fault:
diff --git a/target-i386/op_helper.c b/target-i386/op_helper.c
index 2af7f7a..73dbd50 100644
--- a/target-i386/op_helper.c
+++ b/target-i386/op_helper.c
@@ -4937,7 +4937,7 @@
generated code */
saved_env = env;
env = env1;
- ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+ ret = cpu_x86_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (ret) {
if (retaddr) {
/* now we have a real cpu fault */
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 66ee291..9c4ba73 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -648,7 +648,7 @@
/* helper.c */
int cpu_mips_handle_mmu_fault (CPUMIPSState *env, target_ulong address, int rw,
- int mmu_idx, int is_softmmu);
+ int mmu_idx);
#define cpu_handle_mmu_fault cpu_mips_handle_mmu_fault
void do_interrupt (CPUMIPSState *env);
hwaddr cpu_mips_translate_address (CPUMIPSState *env, target_ulong address,
diff --git a/target-mips/helper.c b/target-mips/helper.c
index fbaee25..433ad39 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -420,8 +420,8 @@
prot |= PAGE_WRITE;
tlb_set_page(env, address & TARGET_PAGE_MASK,
- physical & TARGET_PAGE_MASK, prot,
- mmu_idx, is_softmmu);
+ physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
+ mmu_idx, TARGET_PAGE_SIZE);
ret = TLBRET_MATCH;
goto out;
}
@@ -436,7 +436,7 @@
}
int cpu_mips_handle_mmu_fault (CPUMIPSState *env, target_ulong address, int rw,
- int mmu_idx, int is_softmmu)
+ int mmu_idx)
{
#if !defined(CONFIG_USER_ONLY)
hwaddr physical;
@@ -449,8 +449,8 @@
#if 0
log_cpu_state(env, 0);
#endif
- qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n",
- __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu);
+ qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d\n",
+ __func__, env->active_tc.PC, address, rw, mmu_idx);
rw &= 1;
@@ -466,12 +466,13 @@
qemu_log("%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_plx " prot %d\n",
__func__, address, ret, physical, prot);
if (ret == TLBRET_MATCH) {
- ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
- physical & TARGET_PAGE_MASK, prot,
- mmu_idx, is_softmmu);
+ tlb_set_page(env, address & TARGET_PAGE_MASK,
+ physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
+ mmu_idx, TARGET_PAGE_SIZE);
+ ret = 0;
}
else if (ret == TLBRET_NOMATCH)
- ret = cpu_mips_tlb_refill(env,address,rw,mmu_idx,is_softmmu);
+ ret = cpu_mips_tlb_refill(env,address,rw,mmu_idx,1);
if (ret < 0)
#endif
{
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 429267b..d7f21d4 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -1972,7 +1972,7 @@
generated code */
saved_env = env;
env = env1;
- ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx, 1);
+ ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx);
if (ret) {
if (retaddr) {
/* now we have a real cpu fault */