aboutsummaryrefslogtreecommitdiff
path: root/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'exec.c')
-rw-r--r--exec.c157
1 files changed, 92 insertions, 65 deletions
diff --git a/exec.c b/exec.c
index 77d6866c38..d93a14df9c 100644
--- a/exec.c
+++ b/exec.c
@@ -499,6 +499,14 @@ not_found:
return &phys_sections[s_index];
}
+static
+bool memory_region_is_unassigned(MemoryRegion *mr)
+{
+ return mr != &io_mem_ram && mr != &io_mem_rom
+ && mr != &io_mem_notdirty && !mr->rom_device
+ && mr != &io_mem_watch;
+}
+
static target_phys_addr_t section_addr(MemoryRegionSection *section,
target_phys_addr_t addr)
{
@@ -1919,7 +1927,7 @@ CPUArchState *cpu_copy(CPUArchState *env)
#if !defined(CONFIG_USER_ONLY)
-static inline void tlb_flush_jmp_cache(CPUArchState *env, target_ulong addr)
+static inline void tb_flush_jmp_cache(CPUArchState *env, target_ulong addr)
{
unsigned int i;
@@ -1934,7 +1942,7 @@ static inline void tlb_flush_jmp_cache(CPUArchState *env, target_ulong addr)
TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
}
-static CPUTLBEntry s_cputlb_empty_entry = {
+static const CPUTLBEntry s_cputlb_empty_entry = {
.addr_read = -1,
.addr_write = -1,
.addr_code = -1,
@@ -1964,14 +1972,15 @@ void tlb_flush(CPUArchState *env, int flush_global)
links while we are modifying them */
env->current_tb = NULL;
- for(i = 0; i < CPU_TLB_SIZE; i++) {
+ for (i = 0; i < CPU_TLB_SIZE; i++) {
int mmu_idx;
+
for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
env->tlb_table[mmu_idx][i] = s_cputlb_empty_entry;
}
}
- memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
+ memset(env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
env->tlb_flush_addr = -1;
env->tlb_flush_mask = 0;
@@ -2014,10 +2023,11 @@ void tlb_flush_page(CPUArchState *env, target_ulong addr)
addr &= TARGET_PAGE_MASK;
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++)
+ for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr);
+ }
- tlb_flush_jmp_cache(env, addr);
+ tb_flush_jmp_cache(env, addr);
}
/* update the TLBs so that writes to code in the virtual page 'addr'
@@ -2046,6 +2056,7 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
uintptr_t start, uintptr_t length)
{
uintptr_t addr;
+
if (tlb_is_dirty_ram(tlb_entry)) {
addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
if ((addr - start) < length) {
@@ -2054,13 +2065,29 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
}
}
+static void cpu_tlb_reset_dirty_all(ram_addr_t start1, ram_addr_t length)
+{
+ CPUArchState *env;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ int mmu_idx;
+
+ for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
+ unsigned int i;
+
+ for (i = 0; i < CPU_TLB_SIZE; i++) {
+ tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
+ start1, length);
+ }
+ }
+ }
+}
+
/* Note: start and end must be within the same ram block. */
void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
int dirty_flags)
{
- CPUArchState *env;
uintptr_t length, start1;
- int i;
start &= TARGET_PAGE_MASK;
end = TARGET_PAGE_ALIGN(end);
@@ -2079,15 +2106,7 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
!= (end - 1) - start) {
abort();
}
-
- for(env = first_cpu; env != NULL; env = env->next_cpu) {
- int mmu_idx;
- for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
- for(i = 0; i < CPU_TLB_SIZE; i++)
- tlb_reset_dirty_range(&env->tlb_table[mmu_idx][i],
- start1, length);
- }
- }
+ cpu_tlb_reset_dirty_all(start1, length);
}
int cpu_physical_memory_set_dirty_tracking(int enable)
@@ -2112,21 +2131,11 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
}
}
-/* update the TLB according to the current state of the dirty bits */
-void cpu_tlb_update_dirty(CPUArchState *env)
-{
- int i;
- int mmu_idx;
- for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
- for(i = 0; i < CPU_TLB_SIZE; i++)
- tlb_update_dirty(&env->tlb_table[mmu_idx][i]);
- }
-}
-
static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
{
- if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
+ if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY)) {
tlb_entry->addr_write = vaddr;
+ }
}
/* update the TLB corresponding to virtual page vaddr
@@ -2138,8 +2147,9 @@ static inline void tlb_set_dirty(CPUArchState *env, target_ulong vaddr)
vaddr &= TARGET_PAGE_MASK;
i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++)
+ for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) {
tlb_set_dirty1(&env->tlb_table[mmu_idx][i], vaddr);
+ }
}
/* Our TLB does not support large pages, so remember the area covered by
@@ -2182,6 +2192,53 @@ static bool is_ram_rom_romd(MemoryRegionSection *s)
return is_ram_rom(s) || is_romd(s);
}
+static
+target_phys_addr_t memory_region_section_get_iotlb(CPUArchState *env,
+ MemoryRegionSection *section,
+ target_ulong vaddr,
+ target_phys_addr_t paddr,
+ int prot,
+ target_ulong *address)
+{
+ target_phys_addr_t iotlb;
+ CPUWatchpoint *wp;
+
+ if (is_ram_rom(section)) {
+ /* Normal RAM. */
+ iotlb = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK)
+ + section_addr(section, paddr);
+ if (!section->readonly) {
+ iotlb |= phys_section_notdirty;
+ } else {
+ iotlb |= phys_section_rom;
+ }
+ } else {
+ /* IO handlers are currently passed a physical address.
+ It would be nice to pass an offset from the base address
+ of that region. This would avoid having to special case RAM,
+ and avoid full address decoding in every device.
+ We can't use the high bits of pd for this because
+ IO_MEM_ROMD uses these as a ram address. */
+ iotlb = section - phys_sections;
+ iotlb += section_addr(section, paddr);
+ }
+
+ /* Make accesses to pages with watchpoints go via the
+ watchpoint trap routines. */
+ QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
+ if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
+ /* Avoid trapping reads of pages with a write breakpoint. */
+ if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {
+ iotlb = phys_section_watch + paddr;
+ *address |= TLB_MMIO;
+ break;
+ }
+ }
+ }
+
+ return iotlb;
+}
+
/* 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. */
@@ -2195,7 +2252,6 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
target_ulong code_address;
uintptr_t addend;
CPUTLBEntry *te;
- CPUWatchpoint *wp;
target_phys_addr_t iotlb;
assert(size >= TARGET_PAGE_SIZE);
@@ -2220,38 +2276,10 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
} else {
addend = 0;
}
- if (is_ram_rom(section)) {
- /* Normal RAM. */
- iotlb = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK)
- + section_addr(section, paddr);
- if (!section->readonly)
- iotlb |= phys_section_notdirty;
- else
- iotlb |= phys_section_rom;
- } else {
- /* IO handlers are currently passed a physical address.
- It would be nice to pass an offset from the base address
- of that region. This would avoid having to special case RAM,
- and avoid full address decoding in every device.
- We can't use the high bits of pd for this because
- IO_MEM_ROMD uses these as a ram address. */
- iotlb = section - phys_sections;
- iotlb += section_addr(section, paddr);
- }
+ iotlb = memory_region_section_get_iotlb(env, section, vaddr, paddr, prot,
+ &address);
code_address = address;
- /* Make accesses to pages with watchpoints go via the
- watchpoint trap routines. */
- QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
- if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) {
- /* Avoid trapping reads of pages with a write breakpoint. */
- if ((prot & PAGE_WRITE) || (wp->flags & BP_MEM_READ)) {
- iotlb = phys_section_watch + paddr;
- address |= TLB_MMIO;
- break;
- }
- }
- }
index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
env->iotlb[mmu_idx][index] = iotlb - vaddr;
@@ -4614,13 +4642,12 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
}
pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK;
mr = iotlb_to_region(pd);
- if (mr != &io_mem_ram && mr != &io_mem_rom
- && mr != &io_mem_notdirty && !mr->rom_device
- && mr != &io_mem_watch) {
+ if (memory_region_is_unassigned(mr)) {
#if defined(TARGET_ALPHA) || defined(TARGET_MIPS) || defined(TARGET_SPARC)
cpu_unassigned_access(env1, addr, 0, 1, 0, 4);
#else
- cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
+ cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x"
+ TARGET_FMT_lx "\n", addr);
#endif
}
p = (void *)((uintptr_t)addr + env1->tlb_table[mmu_idx][page_index].addend);