exec.c revision 41d6c8425cf40fbef0183f0609f7b6ff8c1129fe
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * virtual page mapping and translated block handling
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * Copyright (c) 2003 Fabrice Bellard
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * This library is free software; you can redistribute it and/or
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync * modify it under the terms of the GNU Lesser General Public
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * License as published by the Free Software Foundation; either
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * version 2 of the License, or (at your option) any later version.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * This library is distributed in the hope that it will be useful,
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * but WITHOUT ANY WARRANTY; without even the implied warranty of
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * Lesser General Public License for more details.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * You should have received a copy of the GNU Lesser General Public
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * License along with this library; if not, write to the Free Software
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * other than GPL or LGPL is available it will apply instead, Sun elects to use only
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * a choice of LGPL license versions is made available with the language indicating
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * that LGPLv2 or any later version may be used, or where a choice of which version
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * of the LGPL is applied is otherwise unspecified.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#else /* VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif /* VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync//#define DEBUG_TB_INVALIDATE
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync//#define DEBUG_FLUSH
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync//#define DEBUG_TLB
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync//#define DEBUG_UNASSIGNED
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync/* make various TB consistency checks */
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync//#define DEBUG_TB_CHECK
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync//#define DEBUG_TLB_CHECK
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync/* TB consistency checks only implemented for usermode emulation. */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncTranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* any access to the tbs or the page table must use this lock */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* The prologue must be reachable with a direct jump. ARM and Sparc64
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync have limited branch ranges (possibly also PPC) so place it in a
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync section close to code segment. */
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync#else /* VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif /* VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic unsigned long code_gen_buffer_size;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* threshold to flush the translated code buffer */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic unsigned long code_gen_buffer_max_size;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#else /* VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* we have memory ranges (the high PC-BIOS mapping) which
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync causes some pages to fall outside the dirty map here. */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif /* VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#if !defined(VBOX)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* current CPU in the current thread. It is only valid inside
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync cpu_exec() */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* 0 = Do not count executed instructions.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync 1 = Precise instruction counting.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync 2 = Adaptive rate instruction counting. */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* Current instruction counter. While executing translated code this may
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync include some instructions that have not yet been executed. */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsynctypedef struct PageDesc {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* list of TBs intersecting this ram page */
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync /* in order to optimize self modifying code, we count the number
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync of lookups we do to a given page to use a bitmap */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync unsigned long flags;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsynctypedef struct PhysPageDesc {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* offset in host memory of the page + io_index in the low 12 bits */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* XXX: this is a temporary hack for alpha target.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * In the future, this is to be replaced by a multi-level table
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * to actually be able to handle the complete 64 bits address space.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic void io_mem_init(void);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* XXX: for system emulation, it could just be an array */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic void io_mem_init(void);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* io memory support */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncCPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncCPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* log support */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif /* !VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic int log_append = 0;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* statistics */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif /* !VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsynctypedef struct subpage_t {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#else // VBOX
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic void page_init(void)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* NOTE: we can always suppose that qemu_host_page_size >=
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync TARGET_PAGE_SIZE */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync RTMemProtect(code_gen_buffer, sizeof(code_gen_buffer),
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#else /* !VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif /* !VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync while ((1 << qemu_host_page_bits) < qemu_host_page_size)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync while ((1 << qemu_host_page_bits) < (int)qemu_host_page_size)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* We use other means to set reserved bit on our pages */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync if (n == 2) {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync } while (!feof(f));
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic inline PageDesc **page_l1_map(target_ulong index)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncDECLINLINE(PageDesc **) page_l1_map(target_ulong index)
822e11c896dd36c9dc3609dff676059576b7d3devboxsync /* Host memory outside guest VM. For 32-bit targets we have already
822e11c896dd36c9dc3609dff676059576b7d3devboxsync excluded high addresses. */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic inline PageDesc *page_find_alloc(target_ulong index)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncDECLINLINE(PageDesc *) page_find_alloc(target_ulong index)
822e11c896dd36c9dc3609dff676059576b7d3devboxsync /* allocate if not found */
822e11c896dd36c9dc3609dff676059576b7d3devboxsync unsigned long addr;
822e11c896dd36c9dc3609dff676059576b7d3devboxsync /* Don't use qemu_malloc because it may recurse. */
822e11c896dd36c9dc3609dff676059576b7d3devboxsyncstatic inline PageDesc *page_find(target_ulong index)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncDECLINLINE(PageDesc *) page_find(target_ulong index)
822e11c896dd36c9dc3609dff676059576b7d3devboxsyncstatic PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync void **lp, **p;
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync p = (void **)l1_phys_map;
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync /* allocate if not found */
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync /* allocate if not found */
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync for (i = 0; i < L2_SIZE; i++)
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync#if defined(VBOX) && !defined(VBOX_WITH_NEW_PHYS_CODE)
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync pd = ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync if (RT_UNLIKELY((pd->phys_offset & ~TARGET_PAGE_MASK) == IO_MEM_RAM_MISSING))
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync remR3GrowDynRange(pd->phys_offset & TARGET_PAGE_MASK);
822e11c896dd36c9dc3609dff676059576b7d3devboxsync return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsyncstatic inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
822e11c896dd36c9dc3609dff676059576b7d3devboxsyncDECLINLINE(PhysPageDesc *) phys_page_find(target_phys_addr_t index)
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsyncstatic void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#define mmap_lock() do { } while(0)
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync#define mmap_unlock() do { } while(0)
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync/** @todo nike: isn't 32M too much ? */
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsync#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync/* Currently it is not recommanded to allocate big chunks of data in
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync user mode. It will change when a dedicated libc will be used */
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync/* VBox allocates codegen buffer dynamically */
a597f00ac8a71003621fe61c58fe32706ca941b3vboxsyncstatic uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* in user mode, phys_ram_size is not meaningful */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* XXX: needs ajustments */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync code_gen_buffer_size = (unsigned long)(phys_ram_size / 4);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* The code gen buffer location may have constraints depending on
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync the host cpu and OS */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync code_gen_buffer = RTMemExecAlloc(code_gen_buffer_size);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync LogRel(("REM: failed allocate codegen buffer %lld\n",
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#else //!VBOX
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* Cannot map more than that */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync // Map the buffer below 2G, so we can use direct calls and branches
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync code_gen_buffer = mmap(start, code_gen_buffer_size,
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync fprintf(stderr, "Could not allocate dynamic translator buffer\n");
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * 0x40000000 is free */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* Cannot map more than that */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync fprintf(stderr, "Could not allocate dynamic translator buffer\n");
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync code_gen_buffer = qemu_malloc(code_gen_buffer_size);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync fprintf(stderr, "Could not allocate dynamic translator buffer\n");
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync map_exec(code_gen_prologue, sizeof(code_gen_prologue));
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif /* !VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif /* !USE_STATIC_CODE_GEN_BUFFER */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync map_exec(code_gen_prologue, sizeof(code_gen_prologue));
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync code_gen_max_blocks = code_gen_buffer_size / CODE_GEN_AVG_BLOCK_SIZE;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync tbs = qemu_malloc(code_gen_max_blocks * sizeof(TranslationBlock));
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync/* Must be called before using the QEMU cpus. 'tb_size' is the size
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync (in bytes) allocated to the translation buffer. Zero means default
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic void cpu_common_save(QEMUFile *f, void *opaque)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif //!VBOX
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif // !VBOX
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsyncstatic inline void invalidate_page_bitmap(PageDesc *p)
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsyncDECLINLINE(void) invalidate_page_bitmap(PageDesc *p)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* set to NULL all the 'first_tb' fields in all PageDescs */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic void page_flush_tb(void)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync for(i = 0; i < L1_SIZE; i++) {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync for(j = 0; j < L2_SIZE; j++) {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* flush all the translation blocks */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* XXX: tb_flush is currently not thread safe */
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync cpu_abort(env1, "Internal error: code buffer overflow\n");
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync for(env = first_cpu; env != NULL; env = env->next_cpu) {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* XXX: flush processor icache at this point if cache flush is
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync expensive */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic void tb_invalidate_check(target_ulong address)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* verify that all the pages have correct rights for code */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic void tb_page_check(void)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
822e11c896dd36c9dc3609dff676059576b7d3devboxsync unsigned int n1;
822e11c896dd36c9dc3609dff676059576b7d3devboxsync /* suppress any remaining jumps to this TB */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* check end of list */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif // DEBUG_TB_CHECK
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* invalidate one TB */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncDECLINLINE(void) tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync ptb = (TranslationBlock **)((char *)tb1 + next_offset);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncDECLINLINE(void) tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync unsigned int n1;
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsyncstatic inline void tb_jmp_remove(TranslationBlock *tb, int n)
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsyncDECLINLINE(void) tb_jmp_remove(TranslationBlock *tb, int n)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync unsigned int n1;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* find tb(n) in circular list */
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync /* now we can suppress tb(n) from the list */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync/* reset the jump entry 'n' of a TB so that it is not chained to
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync another TB */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic inline void tb_reset_jump(TranslationBlock *tb, int n)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncDECLINLINE(void) tb_reset_jump(TranslationBlock *tb, int n)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsyncvoid tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync unsigned int h, n1;
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync /* remove the TB from the hash list */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync /* remove the TB from the page list */
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync if (tb->page_addr[1] != -1 && tb->page_addr[1] != page_addr) {
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync p = page_find(tb->page_addr[1] >> TARGET_PAGE_BITS);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* remove the TB from the hash list */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync for(env = first_cpu; env != NULL; env = env->next_cpu) {
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* suppress this TB from the two jump lists */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* suppress any remaining jumps to this TB */
a3011b448b38c39a7222f2f1eb40c8349023f650vboxsync tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncvoid tb_invalidate_virt(CPUState *env, uint32_t eip)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync printf("invalidating TB (%08X) at %08X\n", tb, eip);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync //Note: this will leak TBs, but the whole cache will be flushed
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync // when it happens too often
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * Gets the page offset.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncunsigned long get_phys_page_offset(target_ulong addr)
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync PhysPageDesc *p = phys_page_find(addr >> TARGET_PAGE_BITS);
99f33ab590a3a65e0cd082dd8d67779efb9cc6c9vboxsync return p ? p->phys_offset : 0;
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync# endif /* VBOX_STRICT */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync#endif /* VBOX */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncstatic inline void set_bits(uint8_t *tab, int start, int len)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsyncDECLINLINE(void) set_bits(uint8_t *tab, int start, int len)
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* NOTE: this is subtle as a TB may span two physical pages */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync if (n == 0) {
a3011b448b38c39a7222f2f1eb40c8349023f650vboxsync /* NOTE: tb_end may be after the end of the page, but
a3011b448b38c39a7222f2f1eb40c8349023f650vboxsync it is not a problem */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* flush must be done */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* cannot fail at this point */
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync /* Don't forget to invalidate previous TB info. */
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
return tb;
int is_cpu_write_access)
PageDesc *p;
if (!p->code_bitmap &&
current_tb_modified = 0;
#ifdef TARGET_HAS_PRECISE_SMC
if (current_tb_not_found) {
current_tb_not_found = 0;
#if defined(TARGET_I386)
if (env) {
if (env) {
#if !defined(CONFIG_USER_ONLY)
if (!p->first_tb) {
if (is_cpu_write_access) {
#ifdef TARGET_HAS_PRECISE_SMC
if (current_tb_modified) {
#ifndef VBOX
PageDesc *p;
int offset, b;
if (loglevel) {
if (p->code_bitmap) {
goto do_invalidate;
#if !defined(CONFIG_SOFTMMU)
PageDesc *p;
#ifdef TARGET_HAS_PRECISE_SMC
current_tb_modified = 0;
#ifdef TARGET_HAS_PRECISE_SMC
#ifdef TARGET_HAS_PRECISE_SMC
#if defined(TARGET_I386)
#ifdef TARGET_HAS_PRECISE_SMC
if (current_tb_modified) {
#ifndef VBOX
PageDesc *p;
#if defined(CONFIG_USER_ONLY)
int prot;
prot = 0;
if (!p2)
#ifdef DEBUG_TB_INVALIDATE
if (!last_first_tb) {
#ifndef VBOX
return NULL;
return tb;
nb_tbs--;
mmap_lock();
#ifdef DEBUG_TB_CHECK
mmap_unlock();
if (nb_tbs <= 0)
return NULL;
return NULL;
m_min = 0;
if (v == tc_ptr)
return tb;
else if (tc_ptr < v) {
#ifndef VBOX
unsigned int n1;
#if defined(TARGET_HAS_ICE)
PhysPageDesc *p;
#if defined(TARGET_HAS_ICE)
#if defined(TARGET_HAS_ICE)
#if defined(TARGET_HAS_ICE)
goto found;
#if defined(TARGET_HAS_ICE)
#ifndef VBOX
if (!logfile) {
#if !defined(CONFIG_SOFTMMU)
#if !defined(USE_NPTL)
int old_mask;
#ifdef VBOX
#if defined(USE_NPTL)
if (use_icount) {
#ifndef CONFIG_USER_ONLY
#ifdef VBOX
* Note: the current implementation can be executed by another thread without problems; make sure this remains true
#ifndef VBOX
#ifdef TARGET_I386
"show interrupts/exceptions in short format" },
#ifdef TARGET_I386
"show protected mode far calls/returns/exceptions" },
#ifdef DEBUG_IOPORT
int mask;
const char *p, *p1;
p = str;
mask = 0;
if (!p1)
goto found;
return mask;
#ifdef TARGET_I386
abort();
#ifndef VBOX
return new_env;
#if !defined(CONFIG_USER_ONLY)
#ifndef VBOX
#ifdef VBOX
#if defined(DEBUG_TLB)
for(i = 0; i < CPU_TLB_SIZE; i++) {
#ifdef VBOX
#ifdef USE_KQEMU
#ifndef VBOX
#if defined(DEBUG_TLB)
#ifdef USE_KQEMU
#ifdef VBOX
#ifndef VBOX
unsigned long addr;
int dirty_flags)
uint8_t *p;
if (length == 0)
#ifdef USE_KQEMU
for(i = 0; i < len; i++) {
#ifdef VBOX
for(i = 0; i < len; i++)
p[i] &= mask;
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
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"