cputlb.c revision 3e0677df2819b1366819fe4112dc8464425b6eda
13dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner/* 23dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * Common CPU TLB handling 33dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * 43dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * Copyright (c) 2003 Fabrice Bellard 53dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * 63dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * This library is free software; you can redistribute it and/or 73dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * modify it under the terms of the GNU Lesser General Public 83dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * License as published by the Free Software Foundation; either 93dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * version 2 of the License, or (at your option) any later version. 103dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * 113dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * This library is distributed in the hope that it will be useful, 123dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * but WITHOUT ANY WARRANTY; without even the implied warranty of 133dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 143dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * Lesser General Public License for more details. 153dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * 163dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * You should have received a copy of the GNU Lesser General Public 173dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * License along with this library; if not, see <http://www.gnu.org/licenses/>. 183dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner */ 193dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 203dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#include "config.h" 213dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#include "cpu.h" 223dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#include "exec/exec-all.h" 233dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#include "exec/cputlb.h" 243dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 253dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#ifdef CONFIG_MEMCHECK 263dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#include "memcheck/memcheck_api.h" 273dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#endif 283dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 293dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner/* statistics */ 303dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turnerint tlb_flush_count; 313dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 323dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turnerstatic const CPUTLBEntry s_cputlb_empty_entry = { 333dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner .addr_read = -1, 343dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner .addr_write = -1, 353dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner .addr_code = -1, 363dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner .addend = -1, 373dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner}; 383dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 393e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner/* NOTE: 403e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner * If flush_global is true (the usual case), flush all tlb entries. 413e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner * If flush_global is false, flush (at least) all tlb entries not 423e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner * marked global. 433e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner * 443e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner * Since QEMU doesn't currently implement a global/not-global flag 453e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner * for tlb entries, at the moment tlb_flush() will also flush all 463e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner * tlb entries in the flush_global == false case. This is OK because 473e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner * CPU architectures generally permit an implementation to drop 483e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner * entries from the TLB at any time, so flushing more entries than 493e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner * required is only an efficiency issue, not a correctness issue. 503e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner */ 513dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turnervoid tlb_flush(CPUArchState *env, int flush_global) 523dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner{ 533dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner int i; 543dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 553dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#if defined(DEBUG_TLB) 563dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner printf("tlb_flush:\n"); 573dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#endif 583dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner /* must reset current TB so that interrupts cannot modify the 593dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner links while we are modifying them */ 603dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner env->current_tb = NULL; 613dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 623dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner for (i = 0; i < CPU_TLB_SIZE; i++) { 633dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner int mmu_idx; 643dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 653dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 663dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner env->tlb_table[mmu_idx][i] = s_cputlb_empty_entry; 673dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 683dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 693dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 703dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner memset(env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *)); 713dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner tlb_flush_count++; 723dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner} 733dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 743dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turnerstatic inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr) 753dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner{ 763dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if (addr == (tlb_entry->addr_read & 773dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || 783dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner addr == (tlb_entry->addr_write & 793dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner (TARGET_PAGE_MASK | TLB_INVALID_MASK)) || 803dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner addr == (tlb_entry->addr_code & 813dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner (TARGET_PAGE_MASK | TLB_INVALID_MASK))) { 823dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner *tlb_entry = s_cputlb_empty_entry; 833dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 843dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner} 853dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 863dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turnervoid tlb_flush_page(CPUArchState *env, target_ulong addr) 873dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner{ 883dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner int i; 893dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner int mmu_idx; 903dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 913dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#if defined(DEBUG_TLB) 923dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr); 933dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#endif 943dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner /* must reset current TB so that interrupts cannot modify the 953dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner links while we are modifying them */ 963dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner env->current_tb = NULL; 973dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 983dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner addr &= TARGET_PAGE_MASK; 993dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 1003dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 1013dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner tlb_flush_entry(&env->tlb_table[mmu_idx][i], addr); 1023dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 1033dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 1043dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner tb_flush_jmp_cache(env, addr); 1053dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner} 1063dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 1073dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner/* update the TLBs so that writes to code in the virtual page 'addr' 1083dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner can be detected */ 1093dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turnervoid tlb_protect_code(ram_addr_t ram_addr) 1103dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner{ 1113dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner cpu_physical_memory_reset_dirty(ram_addr, 1123dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner ram_addr + TARGET_PAGE_SIZE, 1133dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner CODE_DIRTY_FLAG); 1143dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner} 1153dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 1163dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner/* update the TLB so that writes in physical page 'phys_addr' are no longer 1173dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner tested for self modifying code */ 1183dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turnervoid tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr, 1193dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner target_ulong vaddr) 1203dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner{ 1213dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner cpu_physical_memory_set_dirty_flags(ram_addr, CODE_DIRTY_FLAG); 1223dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner} 1233dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 1243e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turnerstatic bool tlb_is_dirty_ram(CPUTLBEntry *tlbe) 1253e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner{ 1263e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner return (tlbe->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM; 1273e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner} 1283e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner 1293e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turnervoid tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, uintptr_t start, 1303e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner uintptr_t length) 1313dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner{ 1323dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner uintptr_t addr; 1333e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner 1343e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner if (tlb_is_dirty_ram(tlb_entry)) { 1353dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend; 1363dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if ((addr - start) < length) { 1373e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner tlb_entry->addr_write &= TARGET_PAGE_MASK; 1383e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner tlb_entry->addr_write |= TLB_NOTDIRTY; 1393dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 1403dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 1413dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner} 1423dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 1433dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turnerstatic inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr) 1443dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner{ 1453e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY)) { 1463dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner tlb_entry->addr_write = vaddr; 1473e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner } 1483dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner} 1493dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 1503dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner/* update the TLB corresponding to virtual page vaddr 1513dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner so that it is no longer dirty */ 1523dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turnervoid tlb_set_dirty(CPUArchState *env, target_ulong vaddr) 1533dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner{ 1543dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner int i; 1553dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner int mmu_idx; 1563dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 1573dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner vaddr &= TARGET_PAGE_MASK; 1583dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 1593e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner for (mmu_idx = 0; mmu_idx < NB_MMU_MODES; mmu_idx++) { 1603dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner tlb_set_dirty1(&env->tlb_table[mmu_idx][i], vaddr); 1613e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner } 1623dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner} 1633dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 1643dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner/* add a new TLB entry. At most one entry for a given virtual address 1653dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner is permitted. Return 0 if OK or 2 if the page could not be mapped 1663dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner (can only happen in non SOFTMMU mode for I/O pages or pages 1673dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner conflicting with the host address space). */ 1684d6613c972c53178ff9ea39de7fa79d07649fad5David 'Digit' Turnerint tlb_set_page_exec(CPUArchState *env, target_ulong vaddr, 1693dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner hwaddr paddr, int prot, 1703dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner int mmu_idx, int is_softmmu) 1713dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner{ 1723dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner PhysPageDesc *p; 1733dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner unsigned long pd; 1743dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner unsigned int index; 1753dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner target_ulong address; 1763dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner target_ulong code_address; 1773dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner ptrdiff_t addend; 1783dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner int ret; 1793dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner CPUTLBEntry *te; 1803dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner CPUWatchpoint *wp; 1813dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner hwaddr iotlb; 1823dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 1833dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner p = phys_page_find(paddr >> TARGET_PAGE_BITS); 1843dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if (!p) { 1853dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner pd = IO_MEM_UNASSIGNED; 1863dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } else { 1873dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner pd = p->phys_offset; 1883dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 1893dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#if defined(DEBUG_TLB) 1903e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx 1913e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner " prot=%x idx=%d smmu=%d pd=0x%08lx\n", 1923e0677df2819b1366819fe4112dc8464425b6edaDavid 'Digit' Turner vaddr, paddr, prot, mmu_idx, is_softmmu, pd); 1933dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#endif 1943dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 1953dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner ret = 0; 1963dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner address = vaddr; 1973dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { 1983dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner /* IO memory case (romd handled later) */ 1993dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner address |= TLB_MMIO; 2003dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2013dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner addend = (ptrdiff_t)qemu_get_ram_ptr(pd & TARGET_PAGE_MASK); 2023dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) { 2033dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner /* Normal RAM. */ 2043dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner iotlb = pd & TARGET_PAGE_MASK; 2053dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM) 2063dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner iotlb |= IO_MEM_NOTDIRTY; 2073dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner else 2083dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner iotlb |= IO_MEM_ROM; 2093dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } else { 2103dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner /* IO handlers are currently passed a physical address. 2113dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner It would be nice to pass an offset from the base address 2123dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner of that region. This would avoid having to special case RAM, 2133dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner and avoid full address decoding in every device. 2143dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner We can't use the high bits of pd for this because 2153dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner IO_MEM_ROMD uses these as a ram address. */ 2163dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner iotlb = (pd & ~TARGET_PAGE_MASK); 2173dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if (p) { 2183dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner iotlb += p->region_offset; 2193dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } else { 2203dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner iotlb += paddr; 2213dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2223dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2233dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 2243dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner code_address = address; 2253dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner /* Make accesses to pages with watchpoints go via the 2263dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner watchpoint trap routines. */ 2273dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner QTAILQ_FOREACH(wp, &env->watchpoints, entry) { 2283dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if (vaddr == (wp->vaddr & TARGET_PAGE_MASK)) { 2293dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner iotlb = io_mem_watch + paddr; 2303dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner /* TODO: The memory case can be optimized by not trapping 2313dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner reads of pages with a write breakpoint. */ 2323dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner address |= TLB_MMIO; 2333dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2343dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2353dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 2363dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); 2373dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner env->iotlb[mmu_idx][index] = iotlb - vaddr; 2383dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te = &env->tlb_table[mmu_idx][index]; 2393dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te->addend = addend - vaddr; 2403dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if (prot & PAGE_READ) { 2413dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te->addr_read = address; 2423dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } else { 2433dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te->addr_read = -1; 2443dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2453dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 2463dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if (prot & PAGE_EXEC) { 2473dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te->addr_code = code_address; 2483dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } else { 2493dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te->addr_code = -1; 2503dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2513dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if (prot & PAGE_WRITE) { 2523dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || 2533dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner (pd & IO_MEM_ROMD)) { 2543dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner /* Write access calls the I/O callback. */ 2553dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te->addr_write = address | TLB_MMIO; 2563dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 2573dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner !cpu_physical_memory_is_dirty(pd)) { 2583dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te->addr_write = address | TLB_NOTDIRTY; 2593dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } else { 2603dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te->addr_write = address; 2613dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2623dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } else { 2633dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te->addr_write = -1; 2643dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2653dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 2663dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#ifdef CONFIG_MEMCHECK 2673dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner /* 2683dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * If we have memchecker running, we need to make sure that page, cached 2693dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * into TLB as the result of this operation will comply with our requirement 2703dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * to cause __ld/__stx_mmu being called for memory access on the pages 2713dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * containing memory blocks that require access violation checks. 2723dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * 2733dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * We need to check with memory checker if we should invalidate this page 2743dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * iff: 2753dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * - Memchecking is enabled. 2763dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * - Page that's been cached belongs to the user space. 2773dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * - Request to cache this page didn't come from softmmu. We're covered 2783dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * there, because after page was cached here we will invalidate it in 2793dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * the __ld/__stx_mmu wrapper. 2803dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * - Cached page belongs to RAM, not I/O area. 2813dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner * - Page is cached for read, or write access. 2823dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner */ 2833dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if (memcheck_instrument_mmu && mmu_idx == 1 && !is_softmmu && 2843dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner (pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 2853dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner (prot & (PAGE_READ | PAGE_WRITE)) && 2863dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner memcheck_is_checked(vaddr & TARGET_PAGE_MASK, TARGET_PAGE_SIZE)) { 2873dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if (prot & PAGE_READ) { 2883dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te->addr_read ^= TARGET_PAGE_MASK; 2893dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2903dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner if (prot & PAGE_WRITE) { 2913dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner te->addr_write ^= TARGET_PAGE_MASK; 2923dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2933dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner } 2943dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#endif // CONFIG_MEMCHECK 2953dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 2963dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner return ret; 2973dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner} 2983dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 2990e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turnerint tlb_set_page(CPUArchState *env1, target_ulong vaddr, 3000e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner hwaddr paddr, int prot, 3010e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner int mmu_idx, int is_softmmu) 3020e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner{ 3030e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner if (prot & PAGE_READ) 3040e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner prot |= PAGE_EXEC; 3050e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner return tlb_set_page_exec(env1, vaddr, paddr, prot, mmu_idx, is_softmmu); 3060e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner} 3070e0515410009c5bdd4d2d77a4a9131081573f040David 'Digit' Turner 3083dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#define MMUSUFFIX _cmmu 3093dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#define GETPC() NULL 3103dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#define env cpu_single_env 3113dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#define SOFTMMU_CODE_ACCESS 3123dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 3133dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#define SHIFT 0 3143dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#include "exec/softmmu_template.h" 3153dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 3163dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#define SHIFT 1 3173dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#include "exec/softmmu_template.h" 3183dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 3193dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#define SHIFT 2 3203dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#include "exec/softmmu_template.h" 3213dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 3223dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#define SHIFT 3 3233dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#include "exec/softmmu_template.h" 3243dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner 3253dc53fc5342d24fae977049a40c34cc63ba04ad6David 'Digit' Turner#undef env 326