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