exec.c revision 2856f125faa24fa9173360af74346df4736ca53f
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * virtual page mapping and translated block handling
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * Copyright (c) 2003 Fabrice Bellard
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * This library is free software; you can redistribute it and/or
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * modify it under the terms of the GNU Lesser General Public
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * License as published by the Free Software Foundation; either
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * version 2 of the License, or (at your option) any later version.
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * This library is distributed in the hope that it will be useful,
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * but WITHOUT ANY WARRANTY; without even the implied warranty of
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * Lesser General Public License for more details.
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * You should have received a copy of the GNU Lesser General Public
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * License along with this library; if not, write to the Free Software
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync * other than GPL or LGPL is available it will apply instead, Sun elects to use only
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * a choice of LGPL license versions is made available with the language indicating
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * that LGPLv2 or any later version may be used, or where a choice of which version
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * of the LGPL is applied is otherwise unspecified.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else /* VBOX */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif /* VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync//#define DEBUG_TB_INVALIDATE
0c94a8282c9042b02f022302a3d987746140eab9vboxsync//#define DEBUG_FLUSH
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync//#define DEBUG_TLB
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync//#define DEBUG_UNASSIGNED
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* make various TB consistency checks */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync//#define DEBUG_TB_CHECK
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync//#define DEBUG_TLB_CHECK
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* TB consistency checks only implemented for usermode emulation. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncTranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
0c94a8282c9042b02f022302a3d987746140eab9vboxsync/* any access to the tbs or the page table must use this lock */
0c94a8282c9042b02f022302a3d987746140eab9vboxsync/* The prologue must be reachable with a direct jump. ARM and Sparc64
0c94a8282c9042b02f022302a3d987746140eab9vboxsync have limited branch ranges (possibly also PPC) so place it in a
0c94a8282c9042b02f022302a3d987746140eab9vboxsync section close to code segment. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else /* VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic unsigned long code_gen_buffer_size;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* threshold to flush the translated code buffer */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic unsigned long code_gen_buffer_max_size;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else /* VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* we have memory ranges (the high PC-BIOS mapping) which
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync causes some pages to fall outside the dirty map here. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if !defined(VBOX)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* current CPU in the current thread. It is only valid inside
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cpu_exec() */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* 0 = Do not count executed instructions.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 1 = Precise instruction counting.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 2 = Adaptive rate instruction counting. */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync/* Current instruction counter. While executing translated code this may
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync include some instructions that have not yet been executed. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsynctypedef struct PageDesc {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* list of TBs intersecting this ram page */
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync /* in order to optimize self modifying code, we count the number
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync of lookups we do to a given page to use a bitmap */
0c94a8282c9042b02f022302a3d987746140eab9vboxsync unsigned long flags;
0c94a8282c9042b02f022302a3d987746140eab9vboxsynctypedef struct PhysPageDesc {
0c94a8282c9042b02f022302a3d987746140eab9vboxsync /* offset in host memory of the page + io_index in the low 12 bits */
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync/* XXX: this is a temporary hack for alpha target.
0c94a8282c9042b02f022302a3d987746140eab9vboxsync * In the future, this is to be replaced by a multi-level table
0c94a8282c9042b02f022302a3d987746140eab9vboxsync * to actually be able to handle the complete 64 bits address space.
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncstatic void io_mem_init(void);
0c94a8282c9042b02f022302a3d987746140eab9vboxsync/* XXX: for system emulation, it could just be an array */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void io_mem_init(void);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync/* io memory support */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncCPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncCPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync/* log support */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#endif /* !VBOX */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncstatic int log_append = 0;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync/* statistics */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif /* !VBOX */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsynctypedef struct subpage_t {
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else // VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void page_init(void)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* NOTE: we can always suppose that qemu_host_page_size >=
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync TARGET_PAGE_SIZE */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync RTMemProtect(code_gen_buffer, sizeof(code_gen_buffer),
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else /* !VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* !VBOX */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync while ((1 << qemu_host_page_bits) < qemu_host_page_size)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync while ((1 << qemu_host_page_bits) < (int)qemu_host_page_size)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* We use other means to set reserved bit on our pages */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (n == 2) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync } while (!feof(f));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic inline PageDesc **page_l1_map(target_ulong index)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncDECLINLINE(PageDesc **) page_l1_map(target_ulong index)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync /* Host memory outside guest VM. For 32-bit targets we have already
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync excluded high addresses. */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncstatic inline PageDesc *page_find_alloc(target_ulong index)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncDECLINLINE(PageDesc *) page_find_alloc(target_ulong index)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync /* allocate if not found */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync unsigned long addr;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync /* Don't use qemu_malloc because it may recurse. */
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncstatic inline PageDesc *page_find(target_ulong index)
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncDECLINLINE(PageDesc *) page_find(target_ulong index)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncstatic PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync void **lp, **p;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p = (void **)l1_phys_map;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* allocate if not found */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* allocate if not found */
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync for (i = 0; i < L2_SIZE; i++)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#if defined(VBOX) && !defined(VBOX_WITH_NEW_PHYS_CODE)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync pd = ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync if (RT_UNLIKELY((pd->phys_offset & ~TARGET_PAGE_MASK) == IO_MEM_RAM_MISSING))
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync remR3GrowDynRange(pd->phys_offset & TARGET_PAGE_MASK);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncstatic inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncDECLINLINE(PhysPageDesc *) phys_page_find(target_phys_addr_t index)
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsyncstatic void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#define mmap_lock() do { } while(0)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#define mmap_unlock() do { } while(0)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync/** @todo nike: isn't 32M too much ? */
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync/* Currently it is not recommanded to allocate big chunks of data in
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync user mode. It will change when a dedicated libc will be used */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync/* VBox allocates codegen buffer dynamically */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncstatic uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync /* in user mode, phys_ram_size is not meaningful */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* XXX: needs ajustments */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_buffer_size = (unsigned long)(phys_ram_size / 4);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync /* The code gen buffer location may have constraints depending on
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync the host cpu and OS */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_buffer = RTMemExecAlloc(code_gen_buffer_size);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync LogRel(("REM: failed allocate codegen buffer %lld\n",
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else //!VBOX
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync /* Cannot map more than that */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync // Map the buffer below 2G, so we can use direct calls and branches
0c94a8282c9042b02f022302a3d987746140eab9vboxsync code_gen_buffer = mmap(start, code_gen_buffer_size,
0c94a8282c9042b02f022302a3d987746140eab9vboxsync fprintf(stderr, "Could not allocate dynamic translator buffer\n");
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync * 0x40000000 is free */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* Cannot map more than that */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync fprintf(stderr, "Could not allocate dynamic translator buffer\n");
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync code_gen_buffer = qemu_malloc(code_gen_buffer_size);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync fprintf(stderr, "Could not allocate dynamic translator buffer\n");
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync map_exec(code_gen_prologue, sizeof(code_gen_prologue));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif /* !VBOX */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif /* !USE_STATIC_CODE_GEN_BUFFER */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync map_exec(code_gen_prologue, sizeof(code_gen_prologue));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync/* Must be called before using the QEMU cpus. 'tb_size' is the size
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync (in bytes) allocated to the translation buffer. Zero means default
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void cpu_common_save(QEMUFile *f, void *opaque)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncstatic int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#endif //!VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif // !VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic inline void invalidate_page_bitmap(PageDesc *p)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncDECLINLINE(void) invalidate_page_bitmap(PageDesc *p)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync/* set to NULL all the 'first_tb' fields in all PageDescs */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncstatic void page_flush_tb(void)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync for(i = 0; i < L1_SIZE; i++) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync for(j = 0; j < L2_SIZE; j++) {
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync/* flush all the translation blocks */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync/* XXX: tb_flush is currently not thread safe */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync cpu_abort(env1, "Internal error: code buffer overflow\n");
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync for(env = first_cpu; env != NULL; env = env->next_cpu) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync /* XXX: flush processor icache at this point if cache flush is
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync expensive */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncstatic void tb_invalidate_check(target_ulong address)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync/* verify that all the pages have correct rights for code */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncstatic void tb_page_check(void)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync unsigned int n1;
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync /* suppress any remaining jumps to this TB */
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync /* check end of list */
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#endif // DEBUG_TB_CHECK
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync/* invalidate one TB */
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsyncstatic inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsyncDECLINLINE(void) tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ptb = (TranslationBlock **)((char *)tb1 + next_offset);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncDECLINLINE(void) tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync unsigned int n1;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncstatic inline void tb_jmp_remove(TranslationBlock *tb, int n)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncDECLINLINE(void) tb_jmp_remove(TranslationBlock *tb, int n)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync unsigned int n1;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* find tb(n) in circular list */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* now we can suppress tb(n) from the list */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync/* reset the jump entry 'n' of a TB so that it is not chained to
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync another TB */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncstatic inline void tb_reset_jump(TranslationBlock *tb, int n)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncDECLINLINE(void) tb_reset_jump(TranslationBlock *tb, int n)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncvoid tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync unsigned int h, n1;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* remove the TB from the hash list */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* remove the TB from the page list */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* remove the TB from the hash list */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync for(env = first_cpu; env != NULL; env = env->next_cpu) {
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync /* suppress this TB from the two jump lists */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* suppress any remaining jumps to this TB */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncvoid tb_invalidate_virt(CPUState *env, uint32_t eip)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync printf("invalidating TB (%08X) at %08X\n", tb, eip);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync //Note: this will leak TBs, but the whole cache will be flushed
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync // when it happens too often
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync * Gets the page offset.
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncunsigned long get_phys_page_offset(target_ulong addr)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync PhysPageDesc *p = phys_page_find(addr >> TARGET_PAGE_BITS);
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync return p ? p->phys_offset : 0;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync# endif /* VBOX_STRICT */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#endif /* VBOX */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncstatic inline void set_bits(uint8_t *tab, int start, int len)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncDECLINLINE(void) set_bits(uint8_t *tab, int start, int len)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* NOTE: this is subtle as a TB may span two physical pages */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (n == 0) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* NOTE: tb_end may be after the end of the page, but
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync it is not a problem */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* flush must be done */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* cannot fail at this point */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Don't forget to invalidate previous TB info. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* check next page if needed */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* invalidate all TBs which intersect with the target physical page
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync starting in range [start;end[. NOTE: start and end must refer to
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync the same physical page. 'is_cpu_write_access' should be true if called
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync from a real cpu write access: the virtual CPU will exit the current
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync TB if code is modified inside this TB. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncvoid tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int n, current_tb_modified, current_tb_not_found, current_flags;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* build code bitmap */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* we remove all the TBs in the range [start, end[ */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* XXX: see if in some cases it could be faster to invalidate all the code */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* NOTE: this is subtle as a TB may span two physical pages */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if (n == 0) {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* NOTE: tb_end may be after the end of the page, but
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync it is not a problem */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync tb_start = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* now we have a real cpu fault */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* If we are modifying the current TB, we must stop
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync its execution. We could be more precise by checking
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync that the modification is after the current PC, but it
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync would require a specialized function to partially
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync restore the CPU state */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync current_cs_base = (target_ulong)env->segs[R_CS].base;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* TARGET_HAS_PRECISE_SMC */
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync /* we need to do that to handle the case where a signal
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync occurs while doing tb_phys_invalidate() */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* if no code remaining, no need to continue to use slow writes */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* we generate a block containing just the instruction
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync modifying the memory. It will ensure that it cannot modify
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* len must be <= 8 and start must be a multiple of len */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncDECLINLINE(void) tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_invalidate_phys_page_range(start, start + len, 1);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic void tb_invalidate_phys_page(target_phys_addr_t addr,
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync /* If we are modifying the current TB, we must stop
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync its execution. We could be more precise by checking
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync that the modification is after the current PC, but it
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync would require a specialized function to partially
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync restore the CPU state */
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_cs_base = (target_ulong)env->segs[R_CS].base;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif /* TARGET_HAS_PRECISE_SMC */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* we generate a block containing just the instruction
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync modifying the memory. It will ensure that it cannot modify
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* add the tb in the target page and protect it if necessary */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncstatic inline void tb_alloc_page(TranslationBlock *tb,
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncDECLINLINE(void) tb_alloc_page(TranslationBlock *tb,
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* force the host page as non writable (writes will have a
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync page fault + mprotect overhead) */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync for(addr = page_addr; addr < page_addr + qemu_host_page_size;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync printf("protecting code page: 0x" TARGET_FMT_lx "\n",
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* if some code is already present, then the pages are already
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync protected. So we handle the case where only the first TB is
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync allocated in a physical page */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif /* TARGET_HAS_SMC */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* Allocate a new translation block. Flush the translation buffer if
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync too many translation blocks or too much generated code. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync (code_gen_ptr - code_gen_buffer) >= (int)code_gen_buffer_max_size)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* In practice this is mostly used for single use temporary TB
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync Ignore the hard cases and just back up if this TB happens to
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync be the last one generated. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* add a new TB and link it to the physical page tables. phys_page2 is
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync (-1) to indicate that only one page contains the TB. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync unsigned int h;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* Grab the mmap lock to stop another thread invalidating this TB
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync before we are done. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* add in the physical hash table */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* add in the page list */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb->jmp_first = (TranslationBlock *)((long)tb | 2);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* init original jump addresses */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb[1].tc_ptr. Return NULL if not found */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync unsigned long v;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* binary search (cf Knuth) */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync else if (tc_ptr < v) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncstatic void tb_reset_jump_recursive(TranslationBlock *tb);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncstatic inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncDECLINLINE(void) tb_reset_jump_recursive2(TranslationBlock *tb, int n)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync unsigned int n1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* find head of list */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* we are now sure now that tb jumps to tb1 */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* remove tb from the jmp_first list */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* suppress the jump to next tb in generated code */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* suppress jumps in the tb on which we could have jumped */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncstatic void tb_reset_jump_recursive(TranslationBlock *tb)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncstatic void breakpoint_invalidate(CPUState *env, target_ulong pc)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* Add a watchpoint. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncint cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type)
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync /* FIXME: This flush is needed because of the hack to make memory ops
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync terminate the TB. It can be removed once the proper IO trap and
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync re-execute bits are in. */
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync/* Remove a watchpoint. */
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsyncint cpu_watchpoint_remove(CPUState *env, target_ulong addr)
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync/* Remove all watchpoints. */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync breakpoint is reached */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsyncint cpu_breakpoint_insert(CPUState *env, target_ulong pc)
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync/* remove all breakpoints */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync/* remove a breakpoint */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsyncint cpu_breakpoint_remove(CPUState *env, target_ulong pc)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* enable or disable single step mode. EXCP_DEBUG is returned by the
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync CPU loop after each instruction */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* must flush all the translated code to avoid inconsistancies */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* XXX: only flush what is necessary */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* enable or disable low levels log */
0c94a8282c9042b02f022302a3d987746140eab9vboxsync /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#endif /* !VBOX */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync/* mask must never be zero, except for A20 change call */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#if !defined(USE_NPTL)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ASMAtomicOrS32((int32_t volatile *)&env->interrupt_request, mask);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#else /* !VBOX */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* FIXME: This is probably not threadsafe. A different thread could
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync be in the middle of a read-modify-write operation. */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#endif /* !VBOX */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* FIXME: TB unchaining isn't SMP safe. For now just ignore the
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync problem and hope the cpu will stop of its own accord. For userspace
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync emulation this often isn't actually as bad as it sounds. Often
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync signals are used primarily to interrupt blocking syscalls. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* CPU_INTERRUPT_EXIT isn't a real interrupt. It just means
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync an async event happened and we need to process it. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync && (mask & ~(old_mask | CPU_INTERRUPT_EXIT)) != 0) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cpu_abort(env, "Raised interrupt while not in I/O function");
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* if the cpu is currently executing code, we must unlink it and
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync all the potentially executing TB */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync * Note: the current implementation can be executed by another thread without problems; make sure this remains true
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * for future changes!
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request, ~mask);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else /* !VBOX */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#endif /* !VBOX */
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show generated host assembly code for each compiled TB" },
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show target assembly code for each compiled TB" },
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show micro ops after optimization for each compiled TB" },
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show interrupts/exceptions in short format" },
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show trace before each executed TB (lots of logs)" },
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync "show CPU state before bloc translation" },
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show protected mode far calls/returns/exceptions" },
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync "show all i/o ports accesses" },
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsyncstatic int cmp1(const char *s1, int n, const char *s2)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* takes a comma separated list of log masks. Return 0 if error. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync const char *p, *p1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(item = cpu_log_items; item->mask != 0; item++) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(item = cpu_log_items; item->mask != 0; item++) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* !VBOX */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* !VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* preserve chaining and index */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncDECLINLINE(void) tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync unsigned int i;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* Discard jump cache entries for any tb which might potentially
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync overlap the flushed page. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync i = tb_jmp_cache_hash_page(addr - TARGET_PAGE_SIZE);
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync /* inform raw mode about TLB page flush */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* VBOX */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync/* NOTE: if flush_global is true, also flush global entries (not
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync implemented yet) */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* must reset current TB so that interrupts cannot modify the
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync links while we are modifying them */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync for(i = 0; i < CPU_TLB_SIZE; i++) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* inform raw mode about TLB flush */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncDECLINLINE(void) tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncvoid tlb_flush_page(CPUState *env, target_ulong addr)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* must reset current TB so that interrupts cannot modify the
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync links while we are modifying them */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* update the TLBs so that writes to code in the virtual page 'addr'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync can be detected */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#if defined(VBOX) && defined(REM_MONITOR_CODE_PAGES)
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync /** @todo Retest this? This function has changed... */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* update the TLB so that writes in physical page 'phys_addr' are no longer
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync tested for self modifying code */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync if (RT_LIKELY((ram_addr >> TARGET_PAGE_BITS) < phys_ram_dirty_size))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncDECLINLINE(void) tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync unsigned long addr;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsyncvoid cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* XXX: should not depend on cpu context */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(i = 0; i < len; i++) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (RT_LIKELY((start >> TARGET_PAGE_BITS) < phys_ram_dirty_size))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(i = 0; i < len; i++)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* we modify the TLB cache so that the dirty bit will be set again
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync when accessing the range */
0c94a8282c9042b02f022302a3d987746140eab9vboxsync start1 = (unsigned long)remR3TlbGCPhys2Ptr(first_cpu, start, 1 /*fWritable*/); /** @todo this can be harmful with VBOX_WITH_NEW_PHYS_CODE, fix interface/whatever. */
0c94a8282c9042b02f022302a3d987746140eab9vboxsync for(env = first_cpu; env != NULL; env = env->next_cpu) {
0c94a8282c9042b02f022302a3d987746140eab9vboxsync for(i = 0; i < CPU_TLB_SIZE; i++)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
0c94a8282c9042b02f022302a3d987746140eab9vboxsync for(i = 0; i < CPU_TLB_SIZE; i++)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
0c94a8282c9042b02f022302a3d987746140eab9vboxsync for(i = 0; i < CPU_TLB_SIZE; i++)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(i = 0; i < CPU_TLB_SIZE; i++)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
#ifndef VBOX
int cpu_physical_memory_get_dirty_tracking(void)
return in_migration;
#ifndef VBOX
ram_addr = remR3HCVirt2GCPhys(first_cpu, (void*)((tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend));
for(i = 0; i < CPU_TLB_SIZE; i++)
for(i = 0; i < CPU_TLB_SIZE; i++)
for(i = 0; i < CPU_TLB_SIZE; i++)
for(i = 0; i < CPU_TLB_SIZE; i++)
#ifndef VBOX
#ifndef VBOX
PhysPageDesc *p;
unsigned long pd;
unsigned int index;
int ret;
#if defined(DEBUG_TLB)
ret = 0;
#ifdef VBOX
# if !defined(REM_PHYS_ADDR_IN_TLB)
#ifdef VBOX
return ret;
#if !defined(CONFIG_SOFTMMU)
#if defined(DEBUG_TLB)
if (!vp)
#if defined(DEBUG_TLB)
#ifndef VBOX
PageDesc *p;
prot = 0;
for(i = 0; i <= L1_SIZE; i++) {
if (i < L1_SIZE)
p = l1_map[i];
p = NULL;
for(j = 0;j < L2_SIZE; j++) {
prot1 = 0;
if (prot1 != 0)
PageDesc *p;
return p->flags;
PageDesc *p;
#ifdef VBOX
AssertMsgFailed(("We shouldn't be here, and if we should, we must have an env to do the proper locking!\n"));
p->first_tb) {
PageDesc *p;
mmap_lock();
if (!p1) {
mmap_unlock();
p = p1;
prot = 0;
#ifdef DEBUG_TB_CHECK
mmap_unlock();
mmap_unlock();
#if !defined(CONFIG_USER_ONLY)
need_subpage) \
start_addr2 = 0; \
if (start_addr2 > 0) \
unsigned long size,
unsigned long phys_offset)
PhysPageDesc *p;
void *subpage;
#ifdef USE_KQEMU
int need_subpage = 0;
>> IO_MEM_SHIFT];
int need_subpage = 0;
PhysPageDesc *p;
return IO_MEM_UNASSIGNED;
return p->phys_offset;
#ifndef VBOX
abort();
return addr;
#ifdef DEBUG_UNASSIGNED
#ifdef DEBUG_UNASSIGNED
#ifdef DEBUG_UNASSIGNED
#ifdef DEBUG_UNASSIGNED
#ifdef DEBUG_UNASSIGNED
#ifdef DEBUG_UNASSIGNED
unsigned long ram_addr;
int dirty_flags;
#if defined(VBOX)
#elif
#ifdef VBOX
#if !defined(CONFIG_USER_ONLY)
# ifdef VBOX
#ifdef USE_KQEMU
#ifdef VBOX
unsigned long ram_addr;
int dirty_flags;
#if defined(VBOX)
#ifdef VBOX
#if !defined(CONFIG_USER_ONLY)
# ifdef VBOX
#ifdef USE_KQEMU
#ifdef VBOX
unsigned long ram_addr;
int dirty_flags;
#if defined(VBOX)
#ifdef VBOX
#if !defined(CONFIG_USER_ONLY)
# ifdef VBOX
#ifdef USE_KQEMU
#ifdef VBOX
unsigned int len)
unsigned int idx;
#if defined(DEBUG_SUBPAGE)
return ret;
unsigned int idx;
#if defined(DEBUG_SUBPAGE)
#if defined(DEBUG_SUBPAGE)
#if defined(DEBUG_SUBPAGE)
#if defined(DEBUG_SUBPAGE)
#if defined(DEBUG_SUBPAGE)
#if defined(DEBUG_SUBPAGE)
#if defined(DEBUG_SUBPAGE)
#if defined(DEBUG_SUBPAGE)
int subpage_memory;
#if defined(DEBUG_SUBPAGE)
return mmio;
static void io_mem_init(void)
cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
cpu_register_io_memory(IO_MEM_RAM_MISSING >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
void *opaque)
int i, subwidth = 0;
if (io_index <= 0) {
#if defined(CONFIG_USER_ONLY)
int l, flags;
while (len > 0) {
if (l > len)
l = len;
if (is_write) {
len -= l;
buf += l;
addr += l;
int l, io_index;
unsigned long pd;
PhysPageDesc *p;
while (len > 0) {
if (l > len)
l = len;
if (is_write) {
unsigned long addr1;
#ifdef VBOX
#ifdef VBOX
#ifdef VBOX
len -= l;
buf += l;
addr += l;
#ifndef VBOX
unsigned long pd;
PhysPageDesc *p;
while (len > 0) {
if (l > len)
l = len;
unsigned long addr1;
len -= l;
buf += l;
addr += l;
int io_index;
unsigned long pd;
PhysPageDesc *p;
#ifndef VBOX
return val;
int io_index;
unsigned long pd;
PhysPageDesc *p;
#ifdef TARGET_WORDS_BIGENDIAN
#ifndef VBOX
return val;
return val;
int io_index;
unsigned long pd;
PhysPageDesc *p;
#ifndef VBOX
#ifndef VBOX
int io_index;
unsigned long pd;
PhysPageDesc *p;
#ifdef TARGET_WORDS_BIGENDIAN
#ifndef VBOX
int io_index;
unsigned long pd;
PhysPageDesc *p;
unsigned long addr1;
#ifndef VBOX
#ifdef VBOX
while (len > 0) {
if (l > len)
l = len;
len -= l;
buf += l;
addr += l;
if (!tb) {
retaddr);
#if defined(TARGET_MIPS)
if (n > CF_COUNT_MASK)
#ifndef VBOX
target_code_size = 0;
max_target_code_size = 0;
cross_page = 0;
direct_jmp_count = 0;
direct_jmp2_count = 0;
for(i = 0; i < nb_tbs; i++) {
cross_page++;
#if !defined(CONFIG_USER_ONLY)
#define SOFTMMU_CODE_ACCESS
#define SHIFT 0
#include "softmmu_template.h"
#include "softmmu_template.h"
#include "softmmu_template.h"
#include "softmmu_template.h"