From 84b7b8e778937f1ec3cbdb8914261a2fe0067ef2 Mon Sep 17 00:00:00 2001 From: bellard Date: Mon, 28 Nov 2005 21:19:04 +0000 Subject: PAGE_EXEC support in TLBs git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1676 c046a42c-6fe2-441c-8c8c-71466251a162 --- exec.c | 142 +++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 89 insertions(+), 53 deletions(-) (limited to 'exec.c') diff --git a/exec.c b/exec.c index 70ad14dc1..3028a524e 100644 --- a/exec.c +++ b/exec.c @@ -1209,10 +1209,12 @@ void tlb_flush(CPUState *env, int flush_global) env->current_tb = NULL; for(i = 0; i < CPU_TLB_SIZE; i++) { - env->tlb_read[0][i].address = -1; - env->tlb_write[0][i].address = -1; - env->tlb_read[1][i].address = -1; - env->tlb_write[1][i].address = -1; + env->tlb_table[0][i].addr_read = -1; + env->tlb_table[0][i].addr_write = -1; + env->tlb_table[0][i].addr_code = -1; + env->tlb_table[1][i].addr_read = -1; + env->tlb_table[1][i].addr_write = -1; + env->tlb_table[1][i].addr_code = -1; } memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); @@ -1230,9 +1232,16 @@ void tlb_flush(CPUState *env, int flush_global) static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) { - if (addr == (tlb_entry->address & - (TARGET_PAGE_MASK | TLB_INVALID_MASK))) - tlb_entry->address = -1; + if (addr == (tlb_entry->addr_read & + (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || + addr == (tlb_entry->addr_write & + (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || + addr == (tlb_entry->addr_code & + (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { + tlb_entry->addr_read = -1; + tlb_entry->addr_write = -1; + tlb_entry->addr_code = -1; + } } void tlb_flush_page(CPUState *env, target_ulong addr) @@ -1249,10 +1258,8 @@ void tlb_flush_page(CPUState *env, target_ulong addr) addr &= TARGET_PAGE_MASK; i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_flush_entry(&env->tlb_read[0][i], addr); - tlb_flush_entry(&env->tlb_write[0][i], addr); - tlb_flush_entry(&env->tlb_read[1][i], addr); - tlb_flush_entry(&env->tlb_write[1][i], addr); + tlb_flush_entry(&env->tlb_table[0][i], addr); + tlb_flush_entry(&env->tlb_table[1][i], addr); for(i = 0; i < TB_JMP_CACHE_SIZE; i++) { tb = env->tb_jmp_cache[i]; @@ -1295,10 +1302,10 @@ static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, unsigned long start, unsigned long length) { unsigned long addr; - if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { - addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend; + if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend; if ((addr - start) < length) { - tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; + tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY; } } } @@ -1340,9 +1347,9 @@ void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, start1 = start + (unsigned long)phys_ram_base; for(env = first_cpu; env != NULL; env = env->next_cpu) { for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_write[0][i], start1, length); + tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length); for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_reset_dirty_range(&env->tlb_write[1][i], start1, length); + tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length); } #if !defined(CONFIG_SOFTMMU) @@ -1378,11 +1385,11 @@ static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry) { ram_addr_t ram_addr; - if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { - ram_addr = (tlb_entry->address & TARGET_PAGE_MASK) + + if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) { + ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend - (unsigned long)phys_ram_base; if (!cpu_physical_memory_is_dirty(ram_addr)) { - tlb_entry->address |= IO_MEM_NOTDIRTY; + tlb_entry->addr_write |= IO_MEM_NOTDIRTY; } } } @@ -1392,19 +1399,19 @@ void cpu_tlb_update_dirty(CPUState *env) { int i; for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_update_dirty(&env->tlb_write[0][i]); + tlb_update_dirty(&env->tlb_table[0][i]); for(i = 0; i < CPU_TLB_SIZE; i++) - tlb_update_dirty(&env->tlb_write[1][i]); + tlb_update_dirty(&env->tlb_table[1][i]); } static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, unsigned long start) { unsigned long addr; - if ((tlb_entry->address & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) { - addr = (tlb_entry->address & TARGET_PAGE_MASK) + tlb_entry->addend; + if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_NOTDIRTY) { + addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend; if (addr == start) { - tlb_entry->address = (tlb_entry->address & TARGET_PAGE_MASK) | IO_MEM_RAM; + tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_RAM; } } } @@ -1418,17 +1425,17 @@ static inline void tlb_set_dirty(CPUState *env, addr &= TARGET_PAGE_MASK; i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - tlb_set_dirty1(&env->tlb_write[0][i], addr); - tlb_set_dirty1(&env->tlb_write[1][i], addr); + tlb_set_dirty1(&env->tlb_table[0][i], addr); + tlb_set_dirty1(&env->tlb_table[1][i], addr); } /* 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(CPUState *env, target_ulong vaddr, - target_phys_addr_t paddr, int prot, - int is_user, int is_softmmu) +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int is_user, int is_softmmu) { PhysPageDesc *p; unsigned long pd; @@ -1436,6 +1443,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, target_ulong address; target_phys_addr_t addend; int ret; + CPUTLBEntry *te; p = phys_page_find(paddr >> TARGET_PAGE_BITS); if (!p) { @@ -1445,7 +1453,7 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, } #if defined(DEBUG_TLB) printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x u=%d smmu=%d pd=0x%08lx\n", - vaddr, paddr, prot, is_user, is_softmmu, pd); + vaddr, (int)paddr, prot, is_user, is_softmmu, pd); #endif ret = 0; @@ -1465,29 +1473,30 @@ int tlb_set_page(CPUState *env, target_ulong vaddr, index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); addend -= vaddr; + te = &env->tlb_table[is_user][index]; + te->addend = addend; if (prot & PAGE_READ) { - env->tlb_read[is_user][index].address = address; - env->tlb_read[is_user][index].addend = addend; + te->addr_read = address; + } else { + te->addr_read = -1; + } + if (prot & PAGE_EXEC) { + te->addr_code = address; } else { - env->tlb_read[is_user][index].address = -1; - env->tlb_read[is_user][index].addend = -1; + te->addr_code = -1; } if (prot & PAGE_WRITE) { if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM) { /* ROM: access is ignored (same as unassigned) */ - env->tlb_write[is_user][index].address = vaddr | IO_MEM_ROM; - env->tlb_write[is_user][index].addend = addend; + te->addr_write = vaddr | IO_MEM_ROM; } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && !cpu_physical_memory_is_dirty(pd)) { - env->tlb_write[is_user][index].address = vaddr | IO_MEM_NOTDIRTY; - env->tlb_write[is_user][index].addend = addend; + te->addr_write = vaddr | IO_MEM_NOTDIRTY; } else { - env->tlb_write[is_user][index].address = address; - env->tlb_write[is_user][index].addend = addend; + te->addr_write = address; } } else { - env->tlb_write[is_user][index].address = -1; - env->tlb_write[is_user][index].addend = -1; + te->addr_write = -1; } } #if !defined(CONFIG_SOFTMMU) @@ -1586,9 +1595,9 @@ void tlb_flush_page(CPUState *env, target_ulong addr) { } -int tlb_set_page(CPUState *env, target_ulong vaddr, - target_phys_addr_t paddr, int prot, - int is_user, int is_softmmu) +int tlb_set_page_exec(CPUState *env, target_ulong vaddr, + target_phys_addr_t paddr, int prot, + int is_user, int is_softmmu) { return 0; } @@ -2052,6 +2061,41 @@ uint32_t ldl_phys(target_phys_addr_t addr) return val; } +/* warning: addr must be aligned */ +uint64_t ldq_phys(target_phys_addr_t addr) +{ + int io_index; + uint8_t *ptr; + uint64_t val; + unsigned long pd; + PhysPageDesc *p; + + p = phys_page_find(addr >> TARGET_PAGE_BITS); + if (!p) { + pd = IO_MEM_UNASSIGNED; + } else { + pd = p->phys_offset; + } + + if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM) { + /* I/O case */ + io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1); +#ifdef TARGET_WORDS_BIGENDIAN + val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32; + val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4); +#else + val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr); + val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32; +#endif + } else { + /* RAM case */ + ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + + (addr & ~TARGET_PAGE_MASK); + val = ldq_p(ptr); + } + return val; +} + /* XXX: optimize */ uint32_t ldub_phys(target_phys_addr_t addr) { @@ -2068,14 +2112,6 @@ uint32_t lduw_phys(target_phys_addr_t addr) return tswap16(val); } -/* XXX: optimize */ -uint64_t ldq_phys(target_phys_addr_t addr) -{ - uint64_t val; - cpu_physical_memory_read(addr, (uint8_t *)&val, 8); - return tswap64(val); -} - /* warning: addr must be aligned. The ram page is not masked as dirty and the code inside is not invalidated. It is useful if the dirty bits are used to track modified PTEs */ -- cgit v1.2.3