#include "trace.h"
#endif
+#include "cputlb.h"
+
#define WANT_EXEC_OBSOLETE
#include "exec-obsolete.h"
//#define DEBUG_TB_INVALIDATE
//#define DEBUG_FLUSH
-//#define DEBUG_TLB
//#define DEBUG_UNASSIGNED
/* make various TB consistency checks */
//#define DEBUG_TB_CHECK
-//#define DEBUG_TLB_CHECK
//#define DEBUG_IOPORT
//#define DEBUG_SUBPAGE
/* any access to the tbs or the page table must use this lock */
spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
-#if defined(__arm__) || defined(__sparc_v9__)
+#if defined(__arm__) || defined(__sparc__)
/* The prologue must be reachable with a direct jump. ARM and Sparc64
have limited branch ranges (possibly also PPC) so place it in a
section close to code segment. */
#define code_gen_section \
__attribute__((__section__(".gen_code"))) \
__attribute__((aligned (32)))
-#elif defined(_WIN32)
-/* Maximum alignment for Win32 is 16. */
+#elif defined(_WIN32) && !defined(_WIN64)
#define code_gen_section \
__attribute__((aligned (16)))
#else
#define V_L1_SHIFT (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS)
-unsigned long qemu_real_host_page_size;
-unsigned long qemu_host_page_size;
-unsigned long qemu_host_page_mask;
+uintptr_t qemu_real_host_page_size;
+uintptr_t qemu_host_page_size;
+uintptr_t qemu_host_page_mask;
/* This is a multi-level map on the virtual address space.
The bottom level has pointers to PageDesc. */
static MemoryRegion io_mem_watch;
#endif
-/* log support */
-#ifdef WIN32
-static const char *logfilename = "qemu.log";
-#else
-static const char *logfilename = "/tmp/qemu.log";
-#endif
-FILE *logfile;
-int loglevel;
-static int log_append = 0;
-
/* statistics */
-#if !defined(CONFIG_USER_ONLY)
-static int tlb_flush_count;
-#endif
static int tb_flush_count;
static int tb_phys_invalidate_count;
phys_page_set_level(&phys_map, &index, &nb, leaf, P_L2_LEVELS - 1);
}
-static MemoryRegionSection *phys_page_find(target_phys_addr_t index)
+MemoryRegionSection *phys_page_find(target_phys_addr_t index)
{
PhysPageEntry lp = phys_map;
PhysPageEntry *p;
return &phys_sections[s_index];
}
-static target_phys_addr_t section_addr(MemoryRegionSection *section,
- target_phys_addr_t addr)
+bool memory_region_is_unassigned(MemoryRegion *mr)
{
- addr -= section->offset_within_address_space;
- addr += section->offset_within_region;
- return addr;
+ return mr != &io_mem_ram && mr != &io_mem_rom
+ && mr != &io_mem_notdirty && !mr->rom_device
+ && mr != &io_mem_watch;
}
-static void tlb_protect_code(ram_addr_t ram_addr);
-static void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr,
- target_ulong vaddr);
#define mmap_lock() do { } while(0)
#define mmap_unlock() do { } while(0)
#endif
/* Cannot map more than that */
if (code_gen_buffer_size > (800 * 1024 * 1024))
code_gen_buffer_size = (800 * 1024 * 1024);
-#elif defined(__sparc_v9__)
+#elif defined(__sparc__) && HOST_LONG_BITS == 64
// Map the buffer below 2G, so we can use direct calls and branches
- flags |= MAP_FIXED;
- start = (void *) 0x60000000UL;
+ start = (void *) 0x40000000UL;
if (code_gen_buffer_size > (512 * 1024 * 1024))
code_gen_buffer_size = (512 * 1024 * 1024);
#elif defined(__arm__)
/* Cannot map more than that */
if (code_gen_buffer_size > (800 * 1024 * 1024))
code_gen_buffer_size = (800 * 1024 * 1024);
-#elif defined(__sparc_v9__)
+#elif defined(__sparc__) && HOST_LONG_BITS == 64
// Map the buffer below 2G, so we can use direct calls and branches
- flags |= MAP_FIXED;
- addr = (void *) 0x60000000UL;
+ addr = (void *) 0x40000000UL;
if (code_gen_buffer_size > (512 * 1024 * 1024)) {
code_gen_buffer_size = (512 * 1024 * 1024);
}
for(;;) {
tb1 = *ptb;
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (tb1 == tb) {
*ptb = tb1->page_next[n1];
break;
/* find tb(n) in circular list */
for(;;) {
tb1 = *ptb;
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (n1 == n && tb1 == tb)
break;
if (n1 == 2) {
another TB */
static inline void tb_reset_jump(TranslationBlock *tb, int n)
{
- tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
+ tb_set_jmp_target(tb, n, (uintptr_t)(tb->tc_ptr + tb->tb_next_offset[n]));
}
void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
/* suppress any remaining jumps to this TB */
tb1 = tb->jmp_first;
for(;;) {
- n1 = (long)tb1 & 3;
+ n1 = (uintptr_t)tb1 & 3;
if (n1 == 2)
break;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
tb2 = tb1->jmp_next[n1];
tb_reset_jump(tb1, n1);
tb1->jmp_next[n1] = NULL;
tb1 = tb2;
}
- tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
+ tb->jmp_first = (TranslationBlock *)((uintptr_t)tb | 2); /* fail safe */
tb_phys_invalidate_count++;
}
tb = p->first_tb;
while (tb != NULL) {
- n = (long)tb & 3;
- tb = (TranslationBlock *)((long)tb & ~3);
+ n = (uintptr_t)tb & 3;
+ tb = (TranslationBlock *)((uintptr_t)tb & ~3);
/* NOTE: this is subtle as a TB may span two physical pages */
if (n == 0) {
/* NOTE: tb_end may be after the end of the page, but
tb->flags = flags;
tb->cflags = cflags;
cpu_gen_code(env, tb, &code_gen_size);
- code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
+ code_gen_ptr = (void *)(((uintptr_t)code_gen_ptr + code_gen_size +
+ CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
/* check next page if needed */
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
return tb;
}
-/* invalidate all TBs which intersect with the target physical page
- starting in range [start;end[. NOTE: start and end must refer to
- the same physical page. 'is_cpu_write_access' should be true if called
- from a real cpu write access: the virtual CPU will exit the current
- TB if code is modified inside this TB. */
+/*
+ * Invalidate all TBs which intersect with the target physical address range
+ * [start;end[. NOTE: start and end may refer to *different* physical pages.
+ * 'is_cpu_write_access' should be true if called from a real cpu write
+ * access: the virtual CPU will exit the current TB if code is modified inside
+ * this TB.
+ */
+void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end,
+ int is_cpu_write_access)
+{
+ while (start < end) {
+ tb_invalidate_phys_page_range(start, end, is_cpu_write_access);
+ start &= TARGET_PAGE_MASK;
+ start += TARGET_PAGE_SIZE;
+ }
+}
+
+/*
+ * Invalidate all TBs which intersect with the target physical address range
+ * [start;end[. NOTE: start and end must refer to the *same* physical page.
+ * 'is_cpu_write_access' should be true if called from a real cpu write
+ * access: the virtual CPU will exit the current TB if code is modified inside
+ * this TB.
+ */
void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
int is_cpu_write_access)
{
/* XXX: see if in some cases it could be faster to invalidate all the code */
tb = p->first_tb;
while (tb != NULL) {
- n = (long)tb & 3;
- tb = (TranslationBlock *)((long)tb & ~3);
+ n = (uintptr_t)tb & 3;
+ tb = (TranslationBlock *)((uintptr_t)tb & ~3);
tb_next = tb->page_next[n];
/* NOTE: this is subtle as a TB may span two physical pages */
if (n == 0) {
qemu_log("modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
cpu_single_env->mem_io_vaddr, len,
cpu_single_env->eip,
- cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
+ cpu_single_env->eip +
+ (intptr_t)cpu_single_env->segs[R_CS].base);
}
#endif
p = page_find(start >> TARGET_PAGE_BITS);
#if !defined(CONFIG_SOFTMMU)
static void tb_invalidate_phys_page(tb_page_addr_t addr,
- unsigned long pc, void *puc)
+ uintptr_t pc, void *puc)
{
TranslationBlock *tb;
PageDesc *p;
}
#endif
while (tb != NULL) {
- n = (long)tb & 3;
- tb = (TranslationBlock *)((long)tb & ~3);
+ n = (uintptr_t)tb & 3;
+ tb = (TranslationBlock *)((uintptr_t)tb & ~3);
#ifdef TARGET_HAS_PRECISE_SMC
if (current_tb == tb &&
(current_tb->cflags & CF_COUNT_MASK) != 1) {
#ifndef CONFIG_USER_ONLY
page_already_protected = p->first_tb != NULL;
#endif
- p->first_tb = (TranslationBlock *)((long)tb | n);
+ p->first_tb = (TranslationBlock *)((uintptr_t)tb | n);
invalidate_page_bitmap(p);
#if defined(TARGET_HAS_SMC) || 1
else
tb->page_addr[1] = -1;
- tb->jmp_first = (TranslationBlock *)((long)tb | 2);
+ tb->jmp_first = (TranslationBlock *)((uintptr_t)tb | 2);
tb->jmp_next[0] = NULL;
tb->jmp_next[1] = NULL;
TranslationBlock *tb_find_pc(uintptr_t tc_ptr)
{
int m_min, m_max, m;
- unsigned long v;
+ uintptr_t v;
TranslationBlock *tb;
if (nb_tbs <= 0)
return NULL;
- if (tc_ptr < (unsigned long)code_gen_buffer ||
- tc_ptr >= (unsigned long)code_gen_ptr)
+ if (tc_ptr < (uintptr_t)code_gen_buffer ||
+ tc_ptr >= (uintptr_t)code_gen_ptr) {
return NULL;
+ }
/* binary search (cf Knuth) */
m_min = 0;
m_max = nb_tbs - 1;
while (m_min <= m_max) {
m = (m_min + m_max) >> 1;
tb = &tbs[m];
- v = (unsigned long)tb->tc_ptr;
+ v = (uintptr_t)tb->tc_ptr;
if (v == tc_ptr)
return tb;
else if (tc_ptr < v) {
if (tb1 != NULL) {
/* find head of list */
for(;;) {
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (n1 == 2)
break;
tb1 = tb1->jmp_next[n1];
ptb = &tb_next->jmp_first;
for(;;) {
tb1 = *ptb;
- n1 = (long)tb1 & 3;
- tb1 = (TranslationBlock *)((long)tb1 & ~3);
+ n1 = (uintptr_t)tb1 & 3;
+ tb1 = (TranslationBlock *)((uintptr_t)tb1 & ~3);
if (n1 == n && tb1 == tb)
break;
ptb = &tb1->jmp_next[n1];
tb_invalidate_phys_page_range(pc, pc + 1, 0);
}
#else
-static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
+void tb_invalidate_phys_addr(target_phys_addr_t addr)
{
- target_phys_addr_t addr;
ram_addr_t ram_addr;
MemoryRegionSection *section;
- addr = cpu_get_phys_page_debug(env, pc);
section = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!(memory_region_is_ram(section->mr)
|| (section->mr->rom_device && section->mr->readable))) {
return;
}
ram_addr = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK)
- + section_addr(section, addr);
+ + memory_region_section_addr(section, addr);
tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
}
+
+static void breakpoint_invalidate(CPUArchState *env, target_ulong pc)
+{
+ tb_invalidate_phys_addr(cpu_get_phys_page_debug(env, pc) |
+ (pc & ~TARGET_PAGE_MASK));
+}
#endif
#endif /* TARGET_HAS_ICE */
#endif
}
-/* enable or disable low levels log */
-void cpu_set_log(int log_flags)
-{
- loglevel = log_flags;
- if (loglevel && !logfile) {
- logfile = fopen(logfilename, log_append ? "a" : "w");
- if (!logfile) {
- perror(logfilename);
- _exit(1);
- }
-#if !defined(CONFIG_SOFTMMU)
- /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
- {
- static char logfile_buf[4096];
- setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
- }
-#elif defined(_WIN32)
- /* Win32 doesn't support line-buffering, so use unbuffered output. */
- setvbuf(logfile, NULL, _IONBF, 0);
-#else
- setvbuf(logfile, NULL, _IOLBF, 0);
-#endif
- log_append = 1;
- }
- if (!loglevel && logfile) {
- fclose(logfile);
- logfile = NULL;
- }
-}
-
-void cpu_set_log_filename(const char *filename)
-{
- logfilename = strdup(filename);
- if (logfile) {
- fclose(logfile);
- logfile = NULL;
- }
- cpu_set_log(loglevel);
-}
-
static void cpu_unlink_tb(CPUArchState *env)
{
/* FIXME: TB unchaining isn't SMP safe. For now just ignore the
cpu_unlink_tb(env);
}
-const CPULogItem cpu_log_items[] = {
- { CPU_LOG_TB_OUT_ASM, "out_asm",
- "show generated host assembly code for each compiled TB" },
- { CPU_LOG_TB_IN_ASM, "in_asm",
- "show target assembly code for each compiled TB" },
- { CPU_LOG_TB_OP, "op",
- "show micro ops for each compiled TB" },
- { CPU_LOG_TB_OP_OPT, "op_opt",
- "show micro ops "
-#ifdef TARGET_I386
- "before eflags optimization and "
-#endif
- "after liveness analysis" },
- { CPU_LOG_INT, "int",
- "show interrupts/exceptions in short format" },
- { CPU_LOG_EXEC, "exec",
- "show trace before each executed TB (lots of logs)" },
- { CPU_LOG_TB_CPU, "cpu",
- "show CPU state before block translation" },
-#ifdef TARGET_I386
- { CPU_LOG_PCALL, "pcall",
- "show protected mode far calls/returns/exceptions" },
- { CPU_LOG_RESET, "cpu_reset",
- "show CPU state before CPU resets" },
-#endif
-#ifdef DEBUG_IOPORT
- { CPU_LOG_IOPORT, "ioport",
- "show all i/o ports accesses" },
-#endif
- { 0, NULL, NULL },
-};
-
-static int cmp1(const char *s1, int n, const char *s2)
-{
- if (strlen(s2) != n)
- return 0;
- return memcmp(s1, s2, n) == 0;
-}
-
-/* takes a comma separated list of log masks. Return 0 if error. */
-int cpu_str_to_log_mask(const char *str)
-{
- const CPULogItem *item;
- int mask;
- const char *p, *p1;
-
- p = str;
- mask = 0;
- for(;;) {
- p1 = strchr(p, ',');
- if (!p1)
- p1 = p + strlen(p);
- if(cmp1(p,p1-p,"all")) {
- for(item = cpu_log_items; item->mask != 0; item++) {
- mask |= item->mask;
- }
- } else {
- for(item = cpu_log_items; item->mask != 0; item++) {
- if (cmp1(p, p1 - p, item->name))
- goto found;
- }
- return 0;
- }
- found:
- mask |= item->mask;
- if (*p1 != ',')
- break;
- p = p1 + 1;
- }
- return mask;
-}
-
void cpu_abort(CPUArchState *env, const char *fmt, ...)
{
va_list ap;
}
#if !defined(CONFIG_USER_ONLY)
-
-static inline void tlb_flush_jmp_cache(CPUArchState *env, target_ulong addr)
+void tb_flush_jmp_cache(CPUArchState *env, target_ulong addr)
{
unsigned int i;
TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
}
-static CPUTLBEntry s_cputlb_empty_entry = {
- .addr_read = -1,
- .addr_write = -1,
- .addr_code = -1,
- .addend = -1,
-};
-
-/* NOTE:
- * If flush_global is true (the usual case), flush all tlb entries.
- * If flush_global is false, flush (at least) all tlb entries not
- * marked global.
- *
- * Since QEMU doesn't currently implement a global/not-global flag
- * for tlb entries, at the moment tlb_flush() will also flush all
- * tlb entries in the flush_global == false case. This is OK because
- * CPU architectures generally permit an implementation to drop
- * entries from the TLB at any time, so flushing more entries than
- * required is only an efficiency issue, not a correctness issue.
- */
-void tlb_flush(CPUArchState *env, int flush_global)
-{
- int i;
-
-#if defined(DEBUG_TLB)
- printf("tlb_flush:\n");
-#endif
- /* must reset current TB so that interrupts cannot modify the
- links while we are modifying them */
- env->current_tb = NULL;
-
- 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 *));
-
- env->tlb_flush_addr = -1;
- env->tlb_flush_mask = 0;
- tlb_flush_count++;
-}
-
-static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
+static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t end,
+ uintptr_t length)
{
- 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 = s_cputlb_empty_entry;
- }
-}
+ uintptr_t start1;
-void tlb_flush_page(CPUArchState *env, target_ulong addr)
-{
- int i;
- int mmu_idx;
-
-#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;
+ /* we modify the TLB cache so that the dirty bit will be set again
+ when accessing the range */
+ start1 = (uintptr_t)qemu_safe_ram_ptr(start);
+ /* Check that we don't span multiple blocks - this breaks the
+ address comparisons below. */
+ if ((uintptr_t)qemu_safe_ram_ptr(end - 1) - start1
+ != (end - 1) - start) {
+ abort();
}
- /* must reset current TB so that interrupts cannot modify the
- links while we are modifying them */
- env->current_tb = NULL;
-
- addr &= TARGET_PAGE_MASK;
- i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- 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);
-}
+ cpu_tlb_reset_dirty_all(start1, length);
-/* update the TLBs so that writes to code in the virtual page 'addr'
- can be detected */
-static void tlb_protect_code(ram_addr_t ram_addr)
-{
- cpu_physical_memory_reset_dirty(ram_addr,
- ram_addr + TARGET_PAGE_SIZE,
- CODE_DIRTY_FLAG);
-}
-
-/* update the TLB so that writes in physical page 'phys_addr' are no longer
- tested for self modifying code */
-static void tlb_unprotect_code_phys(CPUArchState *env, ram_addr_t ram_addr,
- target_ulong vaddr)
-{
- cpu_physical_memory_set_dirty_flags(ram_addr, CODE_DIRTY_FLAG);
-}
-
-static bool tlb_is_dirty_ram(CPUTLBEntry *tlbe)
-{
- return (tlbe->addr_write & (TLB_INVALID_MASK|TLB_MMIO|TLB_NOTDIRTY)) == 0;
-}
-
-static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
- unsigned long start, unsigned long length)
-{
- unsigned long addr;
- if (tlb_is_dirty_ram(tlb_entry)) {
- addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
- if ((addr - start) < length) {
- tlb_entry->addr_write |= TLB_NOTDIRTY;
- }
- }
}
/* 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;
- unsigned long length, start1;
- int i;
+ uintptr_t length;
start &= TARGET_PAGE_MASK;
end = TARGET_PAGE_ALIGN(end);
return;
cpu_physical_memory_mask_dirty_range(start, length, dirty_flags);
- /* we modify the TLB cache so that the dirty bit will be set again
- when accessing the range */
- start1 = (unsigned long)qemu_safe_ram_ptr(start);
- /* Check that we don't span multiple blocks - this breaks the
- address comparisons below. */
- if ((unsigned long)qemu_safe_ram_ptr(end - 1) - start1
- != (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);
- }
+ if (tcg_enabled()) {
+ tlb_reset_dirty_range_all(start, end, length);
}
}
return ret;
}
-static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
-{
- ram_addr_t ram_addr;
- void *p;
-
- if (tlb_is_dirty_ram(tlb_entry)) {
- p = (void *)(unsigned long)((tlb_entry->addr_write & TARGET_PAGE_MASK)
- + tlb_entry->addend);
- ram_addr = qemu_ram_addr_from_host_nofail(p);
- if (!cpu_physical_memory_is_dirty(ram_addr)) {
- tlb_entry->addr_write |= TLB_NOTDIRTY;
- }
- }
-}
-
-/* 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))
- tlb_entry->addr_write = vaddr;
-}
-
-/* update the TLB corresponding to virtual page vaddr
- so that it is no longer dirty */
-static inline void tlb_set_dirty(CPUArchState *env, target_ulong vaddr)
-{
- int i;
- int mmu_idx;
-
- vaddr &= TARGET_PAGE_MASK;
- i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- 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
- 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_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_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;
-}
-
-static bool is_ram_rom(MemoryRegionSection *s)
-{
- return memory_region_is_ram(s->mr);
-}
-
-static bool is_romd(MemoryRegionSection *s)
-{
- MemoryRegion *mr = s->mr;
-
- return mr->rom_device && mr->readable;
-}
-
-static bool is_ram_rom_romd(MemoryRegionSection *s)
-{
- return is_ram_rom(s) || is_romd(s);
-}
-
-/* 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,
- target_phys_addr_t paddr, int prot,
- int mmu_idx, target_ulong size)
-{
- MemoryRegionSection *section;
- unsigned int index;
- target_ulong address;
- target_ulong code_address;
- unsigned long addend;
- CPUTLBEntry *te;
- CPUWatchpoint *wp;
target_phys_addr_t iotlb;
+ CPUWatchpoint *wp;
- assert(size >= TARGET_PAGE_SIZE);
- if (size != TARGET_PAGE_SIZE) {
- tlb_add_large_page(env, vaddr, size);
- }
- section = phys_page_find(paddr >> TARGET_PAGE_BITS);
-#if defined(DEBUG_TLB)
- printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x" TARGET_FMT_plx
- " prot=%x idx=%d pd=0x%08lx\n",
- vaddr, paddr, prot, mmu_idx, pd);
-#endif
-
- address = vaddr;
- if (!is_ram_rom_romd(section)) {
- /* IO memory case (romd handled later) */
- address |= TLB_MMIO;
- }
- if (is_ram_rom_romd(section)) {
- addend = (unsigned long)memory_region_get_ram_ptr(section->mr)
- + section_addr(section, paddr);
- } else {
- addend = 0;
- }
- if (is_ram_rom(section)) {
+ if (memory_region_is_ram(section->mr)) {
/* Normal RAM. */
iotlb = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK)
- + section_addr(section, paddr);
- if (!section->readonly)
+ + memory_region_section_addr(section, paddr);
+ if (!section->readonly) {
iotlb |= phys_section_notdirty;
- else
+ } 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
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_addr(section, paddr);
}
- code_address = address;
/* Make accesses to pages with watchpoints go via the
watchpoint trap routines. */
QTAILQ_FOREACH(wp, &env->watchpoints, entry) {
/* 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;
+ *address |= TLB_MMIO;
break;
}
}
}
- index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- env->iotlb[mmu_idx][index] = iotlb - vaddr;
- te = &env->tlb_table[mmu_idx][index];
- te->addend = addend - vaddr;
- if (prot & PAGE_READ) {
- te->addr_read = address;
- } else {
- te->addr_read = -1;
- }
-
- if (prot & PAGE_EXEC) {
- te->addr_code = code_address;
- } else {
- te->addr_code = -1;
- }
- if (prot & PAGE_WRITE) {
- if ((memory_region_is_ram(section->mr) && section->readonly)
- || is_romd(section)) {
- /* Write access calls the I/O callback. */
- te->addr_write = address | TLB_MMIO;
- } else if (memory_region_is_ram(section->mr)
- && !cpu_physical_memory_is_dirty(
- section->mr->ram_addr
- + section_addr(section, paddr))) {
- te->addr_write = address | TLB_NOTDIRTY;
- } else {
- te->addr_write = address;
- }
- } else {
- te->addr_write = -1;
- }
+ return iotlb;
}
#else
-
-void tlb_flush(CPUArchState *env, int flush_global)
-{
-}
-
-void tlb_flush_page(CPUArchState *env, target_ulong addr)
-{
-}
-
/*
* Walks guest process memory "regions" one by one
* and calls callback function 'fn' for each region.
{
walk_memory_regions_fn fn;
void *priv;
- unsigned long start;
+ uintptr_t start;
int prot;
};
int walk_memory_regions(void *priv, walk_memory_regions_fn fn)
{
struct walk_memory_regions_data data;
- unsigned long i;
+ uintptr_t i;
data.fn = fn;
data.priv = priv;
mmap_unlock();
return 0;
}
-
-static inline void tlb_set_dirty(CPUArchState *env,
- unsigned long addr, target_ulong vaddr)
-{
-}
#endif /* defined(CONFIG_USER_ONLY) */
#if !defined(CONFIG_USER_ONLY)
phys_sections_nb = 0;
}
-/* register physical memory.
- For RAM, 'size' must be a multiple of the target page size.
- If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
- io memory page. The address used when calling the IO function is
- the offset from the start of the region, plus region_offset. Both
- start_addr and region_offset are rounded down to a page boundary
- before calculating this offset. This should not be a problem unless
- the low bits of start_addr and region_offset differ. */
static void register_subpage(MemoryRegionSection *section)
{
subpage_t *subpage;
subpage = container_of(existing->mr, subpage_t, iomem);
}
start = section->offset_within_address_space & ~TARGET_PAGE_MASK;
- end = start + section->size;
+ end = start + section->size - 1;
subpage_register(subpage, start, end, phys_section_add(section));
}
remain.offset_within_address_space += now.size;
remain.offset_within_region += now.size;
}
- now = remain;
- now.size &= TARGET_PAGE_MASK;
- if (now.size) {
- register_multipage(&now);
+ while (remain.size >= TARGET_PAGE_SIZE) {
+ now = remain;
+ if (remain.offset_within_region & ~TARGET_PAGE_MASK) {
+ now.size = TARGET_PAGE_SIZE;
+ register_subpage(&now);
+ } else {
+ now.size &= TARGET_PAGE_MASK;
+ register_multipage(&now);
+ }
remain.size -= now.size;
remain.offset_within_address_space += now.size;
remain.offset_within_region += now.size;
return last;
}
+static void qemu_ram_setup_dump(void *addr, ram_addr_t size)
+{
+ int ret;
+ QemuOpts *machine_opts;
+
+ /* Use MADV_DONTDUMP, if user doesn't want the guest memory in the core */
+ machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+ if (machine_opts &&
+ !qemu_opt_get_bool(machine_opts, "dump-guest-core", true)) {
+ ret = qemu_madvise(addr, size, QEMU_MADV_DONTDUMP);
+ if (ret) {
+ perror("qemu_madvise");
+ fprintf(stderr, "madvise doesn't support MADV_DONTDUMP, "
+ "but dump_guest_core=off specified\n");
+ }
+ }
+}
+
void qemu_ram_set_idstr(ram_addr_t addr, const char *name, DeviceState *dev)
{
RAMBlock *new_block, *block;
assert(new_block);
assert(!new_block->idstr[0]);
- if (dev && dev->parent_bus && dev->parent_bus->info->get_dev_path) {
- char *id = dev->parent_bus->info->get_dev_path(dev);
+ if (dev) {
+ char *id = qdev_get_dev_path(dev);
if (id) {
snprintf(new_block->idstr, sizeof(new_block->idstr), "%s/", id);
g_free(id);
}
}
+static int memory_try_enable_merging(void *addr, size_t len)
+{
+ QemuOpts *opts;
+
+ opts = qemu_opts_find(qemu_find_opts("machine"), 0);
+ if (opts && !qemu_opt_get_bool(opts, "mem-merge", true)) {
+ /* disabled by the user */
+ return 0;
+ }
+
+ return qemu_madvise(addr, len, QEMU_MADV_MERGEABLE);
+}
+
ram_addr_t qemu_ram_alloc_from_ptr(ram_addr_t size, void *host,
MemoryRegion *mr)
{
new_block->host = file_ram_alloc(new_block, size, mem_path);
if (!new_block->host) {
new_block->host = qemu_vmalloc(size);
- qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
+ memory_try_enable_merging(new_block->host, size);
}
#else
fprintf(stderr, "-mem-path option unsupported\n");
exit(1);
#endif
} else {
-#if defined(TARGET_S390X) && defined(CONFIG_KVM)
- /* S390 KVM requires the topmost vma of the RAM to be smaller than
- an system defined value, which is at least 256GB. Larger systems
- have larger values. We put the guest between the end of data
- segment (system break) and this value. We use 32GB as a base to
- have enough room for the system break to grow. */
- new_block->host = mmap((void*)0x800000000, size,
- PROT_EXEC|PROT_READ|PROT_WRITE,
- MAP_SHARED | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
- if (new_block->host == MAP_FAILED) {
- fprintf(stderr, "Allocating RAM failed\n");
- abort();
- }
-#else
if (xen_enabled()) {
xen_ram_alloc(new_block->offset, size, mr);
+ } else if (kvm_enabled()) {
+ /* some s390/kvm configurations have special constraints */
+ new_block->host = kvm_vmalloc(size);
} else {
new_block->host = qemu_vmalloc(size);
}
-#endif
- qemu_madvise(new_block->host, size, QEMU_MADV_MERGEABLE);
+ memory_try_enable_merging(new_block->host, size);
}
}
new_block->length = size;
ram_list.phys_dirty = g_realloc(ram_list.phys_dirty,
last_ram_offset() >> TARGET_PAGE_BITS);
memset(ram_list.phys_dirty + (new_block->offset >> TARGET_PAGE_BITS),
- 0xff, size >> TARGET_PAGE_BITS);
+ 0, size >> TARGET_PAGE_BITS);
+ cpu_physical_memory_set_dirty_range(new_block->offset, size, 0xff);
+
+ qemu_ram_setup_dump(new_block->host, size);
if (kvm_enabled())
kvm_setup_guest_memory(new_block->host, size);
length, addr);
exit(1);
}
- qemu_madvise(vaddr, length, QEMU_MADV_MERGEABLE);
+ memory_try_enable_merging(vaddr, length);
+ qemu_ram_setup_dump(vaddr, length);
}
return;
}
static void core_eventfd_add(MemoryListener *listener,
MemoryRegionSection *section,
- bool match_data, uint64_t data, int fd)
+ bool match_data, uint64_t data, EventNotifier *e)
{
}
static void core_eventfd_del(MemoryListener *listener,
MemoryRegionSection *section,
- bool match_data, uint64_t data, int fd)
+ bool match_data, uint64_t data, EventNotifier *e)
{
}
static void io_eventfd_add(MemoryListener *listener,
MemoryRegionSection *section,
- bool match_data, uint64_t data, int fd)
+ bool match_data, uint64_t data, EventNotifier *e)
{
}
static void io_eventfd_del(MemoryListener *listener,
MemoryRegionSection *section,
- bool match_data, uint64_t data, int fd)
+ bool match_data, uint64_t data, EventNotifier *e)
{
}
if (is_write) {
if (!memory_region_is_ram(section->mr)) {
target_phys_addr_t addr1;
- addr1 = section_addr(section, addr);
+ addr1 = memory_region_section_addr(section, addr);
/* XXX: could force cpu_single_env to NULL to avoid
potential bugs */
if (l >= 4 && ((addr1 & 3) == 0)) {
} else if (!section->readonly) {
ram_addr_t addr1;
addr1 = memory_region_get_ram_addr(section->mr)
- + section_addr(section, addr);
+ + memory_region_section_addr(section, addr);
/* RAM case */
ptr = qemu_get_ram_ptr(addr1);
memcpy(ptr, buf, l);
qemu_put_ram_ptr(ptr);
}
} else {
- if (!is_ram_rom_romd(section)) {
+ if (!(memory_region_is_ram(section->mr) ||
+ memory_region_is_romd(section->mr))) {
target_phys_addr_t addr1;
/* I/O case */
- addr1 = section_addr(section, addr);
+ addr1 = memory_region_section_addr(section, addr);
if (l >= 4 && ((addr1 & 3) == 0)) {
/* 32 bit read access */
val = io_mem_read(section->mr, addr1, 4);
} else {
/* RAM case */
ptr = qemu_get_ram_ptr(section->mr->ram_addr
- + section_addr(section, addr));
+ + memory_region_section_addr(section,
+ addr));
memcpy(buf, ptr, l);
qemu_put_ram_ptr(ptr);
}
l = len;
section = phys_page_find(page >> TARGET_PAGE_BITS);
- if (!is_ram_rom_romd(section)) {
+ if (!(memory_region_is_ram(section->mr) ||
+ memory_region_is_romd(section->mr))) {
/* do nothing */
} else {
unsigned long addr1;
addr1 = memory_region_get_ram_addr(section->mr)
- + section_addr(section, addr);
+ + memory_region_section_addr(section, addr);
/* ROM/RAM case */
ptr = qemu_get_ram_ptr(addr1);
memcpy(ptr, buf, l);
+ if (!cpu_physical_memory_is_dirty(addr1)) {
+ /* invalidate code */
+ tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
+ /* set dirty bit */
+ cpu_physical_memory_set_dirty_flags(
+ addr1, (0xff & ~CODE_DIRTY_FLAG));
+ }
qemu_put_ram_ptr(ptr);
}
len -= l;
}
if (!todo) {
raddr = memory_region_get_ram_addr(section->mr)
- + section_addr(section, addr);
+ + memory_region_section_addr(section, addr);
}
len -= l;
section = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!is_ram_rom_romd(section)) {
+ if (!(memory_region_is_ram(section->mr) ||
+ memory_region_is_romd(section->mr))) {
/* I/O case */
- addr = section_addr(section, addr);
+ addr = memory_region_section_addr(section, addr);
val = io_mem_read(section->mr, addr, 4);
#if defined(TARGET_WORDS_BIGENDIAN)
if (endian == DEVICE_LITTLE_ENDIAN) {
/* RAM case */
ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(section->mr)
& TARGET_PAGE_MASK)
- + section_addr(section, addr));
+ + memory_region_section_addr(section, addr));
switch (endian) {
case DEVICE_LITTLE_ENDIAN:
val = ldl_le_p(ptr);
section = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!is_ram_rom_romd(section)) {
+ if (!(memory_region_is_ram(section->mr) ||
+ memory_region_is_romd(section->mr))) {
/* I/O case */
- addr = section_addr(section, addr);
+ addr = memory_region_section_addr(section, addr);
/* XXX This is broken when device endian != cpu endian.
Fix and add "endian" variable check */
/* RAM case */
ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(section->mr)
& TARGET_PAGE_MASK)
- + section_addr(section, addr));
+ + memory_region_section_addr(section, addr));
switch (endian) {
case DEVICE_LITTLE_ENDIAN:
val = ldq_le_p(ptr);
section = phys_page_find(addr >> TARGET_PAGE_BITS);
- if (!is_ram_rom_romd(section)) {
+ if (!(memory_region_is_ram(section->mr) ||
+ memory_region_is_romd(section->mr))) {
/* I/O case */
- addr = section_addr(section, addr);
+ addr = memory_region_section_addr(section, addr);
val = io_mem_read(section->mr, addr, 2);
#if defined(TARGET_WORDS_BIGENDIAN)
if (endian == DEVICE_LITTLE_ENDIAN) {
/* RAM case */
ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(section->mr)
& TARGET_PAGE_MASK)
- + section_addr(section, addr));
+ + memory_region_section_addr(section, addr));
switch (endian) {
case DEVICE_LITTLE_ENDIAN:
val = lduw_le_p(ptr);
section = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!memory_region_is_ram(section->mr) || section->readonly) {
- addr = section_addr(section, addr);
+ addr = memory_region_section_addr(section, addr);
if (memory_region_is_ram(section->mr)) {
section = &phys_sections[phys_section_rom];
}
} else {
unsigned long addr1 = (memory_region_get_ram_addr(section->mr)
& TARGET_PAGE_MASK)
- + section_addr(section, addr);
+ + memory_region_section_addr(section, addr);
ptr = qemu_get_ram_ptr(addr1);
stl_p(ptr, val);
section = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!memory_region_is_ram(section->mr) || section->readonly) {
- addr = section_addr(section, addr);
+ addr = memory_region_section_addr(section, addr);
if (memory_region_is_ram(section->mr)) {
section = &phys_sections[phys_section_rom];
}
} else {
ptr = qemu_get_ram_ptr((memory_region_get_ram_addr(section->mr)
& TARGET_PAGE_MASK)
- + section_addr(section, addr));
+ + memory_region_section_addr(section, addr));
stq_p(ptr, val);
}
}
section = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!memory_region_is_ram(section->mr) || section->readonly) {
- addr = section_addr(section, addr);
+ addr = memory_region_section_addr(section, addr);
if (memory_region_is_ram(section->mr)) {
section = &phys_sections[phys_section_rom];
}
} else {
unsigned long addr1;
addr1 = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK)
- + section_addr(section, addr);
+ + memory_region_section_addr(section, addr);
/* RAM case */
ptr = qemu_get_ram_ptr(addr1);
switch (endian) {
section = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!memory_region_is_ram(section->mr) || section->readonly) {
- addr = section_addr(section, addr);
+ addr = memory_region_section_addr(section, addr);
if (memory_region_is_ram(section->mr)) {
section = &phys_sections[phys_section_rom];
}
} else {
unsigned long addr1;
addr1 = (memory_region_get_ram_addr(section->mr) & TARGET_PAGE_MASK)
- + section_addr(section, addr);
+ + memory_region_section_addr(section, addr);
/* RAM case */
ptr = qemu_get_ram_ptr(addr1);
switch (endian) {
/* in deterministic execution mode, instructions doing device I/Os
must be at the end of the TB */
-void cpu_io_recompile(CPUArchState *env, void *retaddr)
+void cpu_io_recompile(CPUArchState *env, uintptr_t retaddr)
{
TranslationBlock *tb;
uint32_t n, cflags;
target_ulong pc, cs_base;
uint64_t flags;
- tb = tb_find_pc((uintptr_t)retaddr);
+ tb = tb_find_pc(retaddr);
if (!tb) {
cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
- retaddr);
+ (void *)retaddr);
}
n = env->icount_decr.u16.low + tb->icount;
- cpu_restore_state(tb, env, (unsigned long)retaddr);
+ cpu_restore_state(tb, env, retaddr);
/* Calculate how many instructions had been executed before the fault
occurred. */
n = n - env->icount_decr.u16.low;
tcg_dump_info(f, cpu_fprintf);
}
-/* NOTE: this function can trigger an exception */
-/* NOTE2: the returned address is not exactly the physical address: it
- is the offset relative to phys_ram_base */
-tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
-{
- int mmu_idx, page_index, pd;
- void *p;
- MemoryRegion *mr;
-
- page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
- mmu_idx = cpu_mmu_index(env1);
- if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code !=
- (addr & TARGET_PAGE_MASK))) {
-#ifdef CONFIG_TCG_PASS_AREG0
- cpu_ldub_code(env1, addr);
-#else
- ldub_code(addr);
-#endif
- }
- 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 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);
-#endif
- }
- p = (void *)((uintptr_t)addr + env1->tlb_table[mmu_idx][page_index].addend);
- return qemu_ram_addr_from_host_nofail(p);
-}
-
/*
* A helper function for the _utterly broken_ virtio device model to find out if
* it's running on a big endian machine. Don't do this at home kids!
#endif
}
-#define MMUSUFFIX _cmmu
-#undef GETPC
-#define GETPC() NULL
-#define env cpu_single_env
-#define SOFTMMU_CODE_ACCESS
-
-#define SHIFT 0
-#include "softmmu_template.h"
-
-#define SHIFT 1
-#include "softmmu_template.h"
-
-#define SHIFT 2
-#include "softmmu_template.h"
+#endif
-#define SHIFT 3
-#include "softmmu_template.h"
+#ifndef CONFIG_USER_ONLY
+bool cpu_physical_memory_is_io(target_phys_addr_t phys_addr)
+{
+ MemoryRegionSection *section;
-#undef env
+ section = phys_page_find(phys_addr >> TARGET_PAGE_BITS);
+ return !(memory_region_is_ram(section->mr) ||
+ memory_region_is_romd(section->mr));
+}
#endif