exec.c revision 2856f125faa24fa9173360af74346df4736ca53f
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync/*
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * virtual page mapping and translated block handling
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync *
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync * Copyright (c) 2003 Fabrice Bellard
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync *
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 *
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 *
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
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync/*
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.
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#include "config.h"
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#ifndef VBOX
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#ifdef _WIN32
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#include <windows.h>
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#else
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#include <sys/types.h>
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#include <sys/mman.h>
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#include <stdlib.h>
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#include <stdio.h>
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#include <stdarg.h>
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#include <string.h>
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#include <errno.h>
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#include <unistd.h>
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#include <inttypes.h>
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else /* VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync# include <stdlib.h>
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync# include <stdio.h>
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync# include <iprt/alloc.h>
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync# include <iprt/string.h>
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync# include <iprt/param.h>
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync# include <VBox/pgm.h> /* PGM_DYNAMIC_RAM_ALLOC */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif /* VBOX */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#include "cpu.h"
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#include "exec-all.h"
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#if defined(CONFIG_USER_ONLY)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#include <qemu.h>
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync//#define DEBUG_TB_INVALIDATE
0c94a8282c9042b02f022302a3d987746140eab9vboxsync//#define DEBUG_FLUSH
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync//#define DEBUG_TLB
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync//#define DEBUG_UNASSIGNED
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* make various TB consistency checks */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync//#define DEBUG_TB_CHECK
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync//#define DEBUG_TLB_CHECK
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync#if !defined(CONFIG_USER_ONLY)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* TB consistency checks only implemented for usermode emulation. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#undef DEBUG_TB_CHECK
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#define SMC_BITMAP_USE_THRESHOLD 10
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#define MMAP_AREA_START 0x00000000
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#define MMAP_AREA_END 0xa8000000
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if defined(TARGET_SPARC64)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#define TARGET_PHYS_ADDR_SPACE_BITS 41
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#elif defined(TARGET_SPARC)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#define TARGET_PHYS_ADDR_SPACE_BITS 36
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#elif defined(TARGET_ALPHA)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#define TARGET_PHYS_ADDR_SPACE_BITS 42
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#define TARGET_VIRT_ADDR_SPACE_BITS 42
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#elif defined(TARGET_PPC64)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#define TARGET_PHYS_ADDR_SPACE_BITS 42
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#elif defined(TARGET_X86_64) && !defined(USE_KQEMU)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#define TARGET_PHYS_ADDR_SPACE_BITS 42
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#elif defined(TARGET_I386) && !defined(USE_KQEMU)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#define TARGET_PHYS_ADDR_SPACE_BITS 36
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* Note: for compatibility with kqemu, we use 32 bits for x86_64 */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#define TARGET_PHYS_ADDR_SPACE_BITS 32
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#endif
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncstatic TranslationBlock *tbs;
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncint code_gen_max_blocks;
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncTranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncstatic int nb_tbs;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync/* any access to the tbs or the page table must use this lock */
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncspinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#ifndef VBOX
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#if defined(__arm__) || defined(__sparc_v9__)
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#define code_gen_section \
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync __attribute__((__section__(".gen_code"))) \
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync __attribute__((aligned (32)))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#define code_gen_section \
0c94a8282c9042b02f022302a3d987746140eab9vboxsync __attribute__((aligned (32)))
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#endif
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncuint8_t code_gen_prologue[1024] code_gen_section;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else /* VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncextern uint8_t* code_gen_prologue;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic uint8_t *code_gen_buffer;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic unsigned long code_gen_buffer_size;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* threshold to flush the translated code buffer */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic unsigned long code_gen_buffer_max_size;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncuint8_t *code_gen_ptr;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifndef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if !defined(CONFIG_USER_ONLY)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncram_addr_t phys_ram_size;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncint phys_ram_fd;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncuint8_t *phys_ram_base;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncuint8_t *phys_ram_dirty;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic int in_migration;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic ram_addr_t phys_ram_alloc_offset = 0;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else /* VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncRTGCPHYS phys_ram_size;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* we have memory ranges (the high PC-BIOS mapping) which
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync causes some pages to fall outside the dirty map here. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncuint32_t phys_ram_dirty_size;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if !defined(VBOX)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncuint8_t *phys_ram_base;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsyncuint8_t *phys_ram_dirty;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncCPUState *first_cpu;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* current CPU in the current thread. It is only valid inside
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cpu_exec() */
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsyncCPUState *cpu_single_env;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* 0 = Do not count executed instructions.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 1 = Precise instruction counting.
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync 2 = Adaptive rate instruction counting. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncint use_icount = 0;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync/* Current instruction counter. While executing translated code this may
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync include some instructions that have not yet been executed. */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncint64_t qemu_icount;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsynctypedef struct PageDesc {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* list of TBs intersecting this ram page */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync TranslationBlock *first_tb;
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 */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync unsigned int code_write_count;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync uint8_t *code_bitmap;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if defined(CONFIG_USER_ONLY)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync unsigned long flags;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#endif
0c94a8282c9042b02f022302a3d987746140eab9vboxsync} PageDesc;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsynctypedef struct PhysPageDesc {
0c94a8282c9042b02f022302a3d987746140eab9vboxsync /* offset in host memory of the page + io_index in the low 12 bits */
0c94a8282c9042b02f022302a3d987746140eab9vboxsync ram_addr_t phys_offset;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync} PhysPageDesc;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#define L2_BITS 10
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 */
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#else
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#endif
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#define L1_SIZE (1 << L1_BITS)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#define L2_SIZE (1 << L2_BITS)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncstatic void io_mem_init(void);
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncunsigned long qemu_real_host_page_size;
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncunsigned long qemu_host_page_bits;
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncunsigned long qemu_host_page_size;
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncunsigned long qemu_host_page_mask;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsync/* XXX: for system emulation, it could just be an array */
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncstatic PageDesc *l1_map[L1_SIZE];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic PhysPageDesc **l1_phys_map;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#if !defined(CONFIG_USER_ONLY)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void io_mem_init(void);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync/* io memory support */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncCPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncCPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncvoid *io_mem_opaque[IO_MEM_NB_ENTRIES];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic int io_mem_nb;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic int io_mem_watch;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#ifndef VBOX
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync/* log support */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncstatic const char *logfilename = "/tmp/qemu.log";
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#endif /* !VBOX */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncFILE *logfile;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncint loglevel;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#ifndef VBOX
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncstatic int log_append = 0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync/* statistics */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic int tlb_flush_count;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic int tb_flush_count;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#ifndef VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic int tb_phys_invalidate_count;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif /* !VBOX */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsynctypedef struct subpage_t {
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync target_phys_addr_t base;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE][4];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE][4];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync void *opaque[TARGET_PAGE_SIZE][2][4];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync} subpage_t;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#ifndef VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#ifdef _WIN32
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void map_exec(void *addr, long size)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync{
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync DWORD old_protect;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync VirtualProtect(addr, size,
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync PAGE_EXECUTE_READWRITE, &old_protect);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync}
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void map_exec(void *addr, long size)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync{
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync unsigned long start, end, page_size;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync page_size = getpagesize();
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync start = (unsigned long)addr;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync start &= ~(page_size - 1);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync end = (unsigned long)addr + size;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync end += page_size - 1;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync end &= ~(page_size - 1);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync mprotect((void *)start, end - start,
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync PROT_READ | PROT_WRITE | PROT_EXEC);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync}
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else // VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void map_exec(void *addr, long size)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync{
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync RTMemProtect(addr, size,
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync}
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void page_init(void)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync{
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* NOTE: we can always suppose that qemu_host_page_size >=
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync TARGET_PAGE_SIZE */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#ifdef VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync RTMemProtect(code_gen_buffer, sizeof(code_gen_buffer),
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync RTMEM_PROT_EXEC | RTMEM_PROT_READ | RTMEM_PROT_WRITE);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync qemu_real_host_page_size = PAGE_SIZE;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else /* !VBOX */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#ifdef _WIN32
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync {
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync SYSTEM_INFO system_info;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync DWORD old_protect;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync GetSystemInfo(&system_info);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync qemu_real_host_page_size = system_info.dwPageSize;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync }
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync qemu_real_host_page_size = getpagesize();
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* !VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if (qemu_host_page_size == 0)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync qemu_host_page_size = qemu_real_host_page_size;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if (qemu_host_page_size < TARGET_PAGE_SIZE)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync qemu_host_page_size = TARGET_PAGE_SIZE;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync qemu_host_page_bits = 0;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#ifndef VBOX
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync while ((1 << qemu_host_page_bits) < qemu_host_page_size)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#else
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync while ((1 << qemu_host_page_bits) < (int)qemu_host_page_size)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync qemu_host_page_bits++;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync qemu_host_page_mask = ~(qemu_host_page_size - 1);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync l1_phys_map = qemu_vmalloc(L1_SIZE * sizeof(void *));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync memset(l1_phys_map, 0, L1_SIZE * sizeof(void *));
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#ifdef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* We use other means to set reserved bit on our pages */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync long long startaddr, endaddr;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync FILE *f;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int n;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync mmap_lock();
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync last_brk = (unsigned long)sbrk(0);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync f = fopen("/proc/self/maps", "r");
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (f) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync do {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync n = fscanf (f, "%llx-%llx %*[^\n]\n", &startaddr, &endaddr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (n == 2) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync startaddr = MIN(startaddr,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync endaddr = MIN(endaddr,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync (1ULL << TARGET_PHYS_ADDR_SPACE_BITS) - 1);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync page_set_flags(startaddr & TARGET_PAGE_MASK,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync TARGET_PAGE_ALIGN(endaddr),
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync PAGE_RESERVED);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync } while (!feof(f));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync fclose(f);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync mmap_unlock();
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifndef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic inline PageDesc **page_l1_map(target_ulong index)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#else
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncDECLINLINE(PageDesc **) page_l1_map(target_ulong index)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#endif
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync{
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#if TARGET_LONG_BITS > 32
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync /* Host memory outside guest VM. For 32-bit targets we have already
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync excluded high addresses. */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if (index > ((target_ulong)L2_SIZE * L1_SIZE))
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync return NULL;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#endif
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync return &l1_map[index >> L2_BITS];
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync}
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#ifndef VBOX
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncstatic inline PageDesc *page_find_alloc(target_ulong index)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#else
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncDECLINLINE(PageDesc *) page_find_alloc(target_ulong index)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#endif
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync{
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync PageDesc **lp, *p;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync lp = page_l1_map(index);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if (!lp)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync return NULL;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p = *lp;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if (!p) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync /* allocate if not found */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#if defined(CONFIG_USER_ONLY)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync unsigned long addr;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync size_t len = sizeof(PageDesc) * L2_SIZE;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync /* Don't use qemu_malloc because it may recurse. */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p = mmap(0, len, PROT_READ | PROT_WRITE,
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync *lp = p;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync addr = h2g(p);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if (addr == (target_ulong)addr) {
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync page_set_flags(addr & TARGET_PAGE_MASK,
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync TARGET_PAGE_ALIGN(addr + len),
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync PAGE_RESERVED);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#else
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync *lp = p;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c94a8282c9042b02f022302a3d987746140eab9vboxsync }
0c94a8282c9042b02f022302a3d987746140eab9vboxsync return p + (index & (L2_SIZE - 1));
0c94a8282c9042b02f022302a3d987746140eab9vboxsync}
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#ifndef VBOX
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncstatic inline PageDesc *page_find(target_ulong index)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#else
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncDECLINLINE(PageDesc *) page_find(target_ulong index)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#endif
0c94a8282c9042b02f022302a3d987746140eab9vboxsync{
0c94a8282c9042b02f022302a3d987746140eab9vboxsync PageDesc **lp, *p;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync lp = page_l1_map(index);
0c94a8282c9042b02f022302a3d987746140eab9vboxsync if (!lp)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync return NULL;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsync p = *lp;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync if (!p)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync return 0;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync return p + (index & (L2_SIZE - 1));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync}
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncstatic PhysPageDesc *phys_page_find_alloc(target_phys_addr_t index, int alloc)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync{
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync void **lp, **p;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync PhysPageDesc *pd;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p = (void **)l1_phys_map;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if TARGET_PHYS_ADDR_SPACE_BITS > 32
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#if TARGET_PHYS_ADDR_SPACE_BITS > (32 + L1_BITS)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#error unsupported TARGET_PHYS_ADDR_SPACE_BITS
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#endif
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync lp = p + ((index >> (L1_BITS + L2_BITS)) & (L1_SIZE - 1));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p = *lp;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (!p) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* allocate if not found */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if (!alloc)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync return NULL;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p = qemu_vmalloc(sizeof(void *) * L1_SIZE);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync memset(p, 0, sizeof(void *) * L1_SIZE);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync *lp = p;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#endif
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync lp = p + ((index >> L2_BITS) & (L1_SIZE - 1));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync pd = *lp;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if (!pd) {
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync int i;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* allocate if not found */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if (!alloc)
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync return NULL;
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync pd = qemu_vmalloc(sizeof(PhysPageDesc) * L2_SIZE);
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync *lp = pd;
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync for (i = 0; i < L2_SIZE; i++)
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync pd[i].phys_offset = IO_MEM_UNASSIGNED;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync }
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 pd;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync return ((PhysPageDesc *)pd) + (index & (L2_SIZE - 1));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync}
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#ifndef VBOX
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncstatic inline PhysPageDesc *phys_page_find(target_phys_addr_t index)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncDECLINLINE(PhysPageDesc *) phys_page_find(target_phys_addr_t index)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync{
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync return phys_page_find_alloc(index, 0);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync}
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#if !defined(CONFIG_USER_ONLY)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void tlb_protect_code(ram_addr_t ram_addr);
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsyncstatic void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync target_ulong vaddr);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#define mmap_lock() do { } while(0)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#define mmap_unlock() do { } while(0)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#endif
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync#ifdef VBOX
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync/** @todo nike: isn't 32M too much ? */
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync#endif
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync#define DEFAULT_CODE_GEN_BUFFER_SIZE (32 * 1024 * 1024)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#if defined(CONFIG_USER_ONLY)
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 */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#define USE_STATIC_CODE_GEN_BUFFER
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync/* VBox allocates codegen buffer dynamically */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#ifndef VBOX
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#ifdef USE_STATIC_CODE_GEN_BUFFER
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncstatic uint8_t static_code_gen_buffer[DEFAULT_CODE_GEN_BUFFER_SIZE];
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#endif
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#endif
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncstatic void code_gen_alloc(unsigned long tb_size)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync{
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#ifdef USE_STATIC_CODE_GEN_BUFFER
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync code_gen_buffer = static_code_gen_buffer;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync map_exec(code_gen_buffer, code_gen_buffer_size);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#else
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync code_gen_buffer_size = tb_size;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync if (code_gen_buffer_size == 0) {
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#if defined(CONFIG_USER_ONLY)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync /* in user mode, phys_ram_size is not meaningful */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync code_gen_buffer_size = DEFAULT_CODE_GEN_BUFFER_SIZE;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* XXX: needs ajustments */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_buffer_size = (unsigned long)(phys_ram_size / 4);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync if (code_gen_buffer_size < MIN_CODE_GEN_BUFFER_SIZE)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync 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#ifdef VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_buffer = RTMemExecAlloc(code_gen_buffer_size);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if (!code_gen_buffer) {
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync LogRel(("REM: failed allocate codegen buffer %lld\n",
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_buffer_size));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync return;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync }
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else //!VBOX
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#if defined(__linux__)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync {
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync int flags;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync void *start = NULL;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync flags = MAP_PRIVATE | MAP_ANONYMOUS;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#if defined(__x86_64__)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync flags |= MAP_32BIT;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync /* Cannot map more than that */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if (code_gen_buffer_size > (800 * 1024 * 1024))
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_buffer_size = (800 * 1024 * 1024);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#elif defined(__sparc_v9__)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync // Map the buffer below 2G, so we can use direct calls and branches
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync flags |= MAP_FIXED;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync start = (void *) 0x60000000UL;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if (code_gen_buffer_size > (512 * 1024 * 1024))
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_buffer_size = (512 * 1024 * 1024);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
0c94a8282c9042b02f022302a3d987746140eab9vboxsync code_gen_buffer = mmap(start, code_gen_buffer_size,
0c94a8282c9042b02f022302a3d987746140eab9vboxsync PROT_WRITE | PROT_READ | PROT_EXEC,
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync flags, -1, 0);
0c94a8282c9042b02f022302a3d987746140eab9vboxsync if (code_gen_buffer == MAP_FAILED) {
0c94a8282c9042b02f022302a3d987746140eab9vboxsync fprintf(stderr, "Could not allocate dynamic translator buffer\n");
0c94a8282c9042b02f022302a3d987746140eab9vboxsync exit(1);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync }
0c94a8282c9042b02f022302a3d987746140eab9vboxsync }
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#elif defined(__FreeBSD__)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync {
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync int flags;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync void *addr = NULL;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync flags = MAP_PRIVATE | MAP_ANONYMOUS;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#if defined(__x86_64__)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* FreeBSD doesn't have MAP_32BIT, use MAP_FIXED and assume
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync * 0x40000000 is free */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync flags |= MAP_FIXED;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync addr = (void *)0x40000000;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync /* Cannot map more than that */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if (code_gen_buffer_size > (800 * 1024 * 1024))
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync code_gen_buffer_size = (800 * 1024 * 1024);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync code_gen_buffer = mmap(addr, code_gen_buffer_size,
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync PROT_WRITE | PROT_READ | PROT_EXEC,
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync flags, -1, 0);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if (code_gen_buffer == MAP_FAILED) {
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync fprintf(stderr, "Could not allocate dynamic translator buffer\n");
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync exit(1);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync }
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync }
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync code_gen_buffer = qemu_malloc(code_gen_buffer_size);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if (!code_gen_buffer) {
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync fprintf(stderr, "Could not allocate dynamic translator buffer\n");
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync exit(1);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync }
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync map_exec(code_gen_buffer, code_gen_buffer_size);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync map_exec(code_gen_prologue, sizeof(code_gen_prologue));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif /* !VBOX */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif /* !USE_STATIC_CODE_GEN_BUFFER */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#ifndef VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync map_exec(code_gen_prologue, sizeof(code_gen_prologue));
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync map_exec(code_gen_prologue, _1K);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_buffer_max_size = code_gen_buffer_size -
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_max_block_size();
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}
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
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 size. */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncvoid cpu_exec_init_all(unsigned long tb_size)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync{
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync cpu_gen_init();
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_alloc(tb_size);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync code_gen_ptr = code_gen_buffer;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync page_init();
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#if !defined(CONFIG_USER_ONLY)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync io_mem_init();
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync}
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#ifndef VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#define CPU_COMMON_SAVE_VERSION 1
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic void cpu_common_save(QEMUFile *f, void *opaque)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync{
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync CPUState *env = opaque;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync qemu_put_be32s(f, &env->halted);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync qemu_put_be32s(f, &env->interrupt_request);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync}
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncstatic int cpu_common_load(QEMUFile *f, void *opaque, int version_id)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync{
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync CPUState *env = opaque;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if (version_id != CPU_COMMON_SAVE_VERSION)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync return -EINVAL;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync qemu_get_be32s(f, &env->halted);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync qemu_get_be32s(f, &env->interrupt_request);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync tlb_flush(env, 1);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync return 0;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync}
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#endif
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#endif //!VBOX
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncvoid cpu_exec_init(CPUState *env)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync{
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync CPUState **penv;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync int cpu_index;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync env->next_cpu = NULL;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync penv = &first_cpu;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync cpu_index = 0;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync while (*penv != NULL) {
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync penv = (CPUState **)&(*penv)->next_cpu;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync cpu_index++;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync }
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync env->cpu_index = cpu_index;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync env->nb_watchpoints = 0;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync *penv = env;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#ifndef VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#if defined(CPU_SAVE_VERSION) && !defined(CONFIG_USER_ONLY)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync register_savevm("cpu_common", cpu_index, CPU_COMMON_SAVE_VERSION,
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync cpu_common_save, cpu_common_load, env);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync register_savevm("cpu", cpu_index, CPU_SAVE_VERSION,
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync cpu_save, cpu_load, env);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif // !VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync}
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#ifndef VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic inline void invalidate_page_bitmap(PageDesc *p)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncDECLINLINE(void) invalidate_page_bitmap(PageDesc *p)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync{
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync if (p->code_bitmap) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync qemu_free(p->code_bitmap);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p->code_bitmap = NULL;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync }
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync p->code_write_count = 0;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync}
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync/* set to NULL all the 'first_tb' fields in all PageDescs */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncstatic void page_flush_tb(void)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync{
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync int i, j;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync PageDesc *p;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync for(i = 0; i < L1_SIZE; i++) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p = l1_map[i];
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync if (p) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync for(j = 0; j < L2_SIZE; j++) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p->first_tb = NULL;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync invalidate_page_bitmap(p);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync p++;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync }
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync }
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync }
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync}
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync/* flush all the translation blocks */
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync/* XXX: tb_flush is currently not thread safe */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncvoid tb_flush(CPUState *env1)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync{
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync CPUState *env;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#if defined(DEBUG_FLUSH)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync printf("qemu: flush code_size=%ld nb_tbs=%d avg_tb_size=%ld\n",
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync (unsigned long)(code_gen_ptr - code_gen_buffer),
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync nb_tbs, nb_tbs > 0 ?
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync ((unsigned long)(code_gen_ptr - code_gen_buffer)) / nb_tbs : 0);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#endif
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if ((unsigned long)(code_gen_ptr - code_gen_buffer) > code_gen_buffer_size)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync cpu_abort(env1, "Internal error: code buffer overflow\n");
9c9db71d639cf066ed41d49629d46d48bff4be2fvboxsync
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync nb_tbs = 0;
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync
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 }
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync page_flush_tb();
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync code_gen_ptr = code_gen_buffer;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync /* XXX: flush processor icache at this point if cache flush is
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync expensive */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync tb_flush_count++;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync}
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#ifdef DEBUG_TB_CHECK
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncstatic void tb_invalidate_check(target_ulong address)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync{
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync TranslationBlock *tb;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync int i;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync address &= TARGET_PAGE_MASK;
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 (!(address + TARGET_PAGE_SIZE <= tb->pc ||
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync address >= tb->pc + tb->size)) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync printf("ERROR invalidate: address=%08lx PC=%08lx size=%04x\n",
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync address, (long)tb->pc, tb->size);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync }
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync }
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync }
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync}
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync/* verify that all the pages have correct rights for code */
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsyncstatic void tb_page_check(void)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync{
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync TranslationBlock *tb;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync int i, flags1, flags2;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
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 flags1 = page_get_flags(tb->pc);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync flags2 = page_get_flags(tb->pc + tb->size - 1);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync (long)tb->pc, tb->size, flags1, flags2);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync }
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync }
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync }
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync}
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync
9c9db71d639cf066ed41d49629d46d48bff4be2fvboxsyncstatic void tb_jmp_check(TranslationBlock *tb)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync{
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync TranslationBlock *tb1;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync unsigned int n1;
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync /* suppress any remaining jumps to this TB */
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync tb1 = tb->jmp_first;
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync for(;;) {
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync n1 = (long)tb1 & 3;
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync tb1 = (TranslationBlock *)((long)tb1 & ~3);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if (n1 == 2)
9c9db71d639cf066ed41d49629d46d48bff4be2fvboxsync break;
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync tb1 = tb1->jmp_next[n1];
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync }
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync /* check end of list */
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync if (tb1 != tb) {
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync printf("ERROR: jmp_list from 0x%08lx\n", (long)tb);
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync }
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync}
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#endif // DEBUG_TB_CHECK
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync/* invalidate one TB */
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync#ifndef VBOX
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsyncstatic inline void tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync int next_offset)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#else
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsyncDECLINLINE(void) tb_remove(TranslationBlock **ptb, TranslationBlock *tb,
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync int next_offset)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync#endif
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync{
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync TranslationBlock *tb1;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync for(;;) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync tb1 = *ptb;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if (tb1 == tb) {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync *ptb = *(TranslationBlock **)((char *)tb1 + next_offset);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync break;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ptb = (TranslationBlock **)((char *)tb1 + next_offset);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifndef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic inline void tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncDECLINLINE(void) tb_page_remove(TranslationBlock **ptb, TranslationBlock *tb)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync TranslationBlock *tb1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync unsigned int n1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(;;) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb1 = *ptb;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync n1 = (long)tb1 & 3;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb1 = (TranslationBlock *)((long)tb1 & ~3);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (tb1 == tb) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync *ptb = tb1->page_next[n1];
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync break;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ptb = &tb1->page_next[n1];
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync}
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#ifndef VBOX
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncstatic inline void tb_jmp_remove(TranslationBlock *tb, int n)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#else
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncDECLINLINE(void) tb_jmp_remove(TranslationBlock *tb, int n)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#endif
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync{
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync TranslationBlock *tb1, **ptb;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync unsigned int n1;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync ptb = &tb->jmp_next[n];
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb1 = *ptb;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if (tb1) {
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* find tb(n) in circular list */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync for(;;) {
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb1 = *ptb;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync n1 = (long)tb1 & 3;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb1 = (TranslationBlock *)((long)tb1 & ~3);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if (n1 == n && tb1 == tb)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync break;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (n1 == 2) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ptb = &tb1->jmp_first;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync } else {
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync ptb = &tb1->jmp_next[n1];
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* now we can suppress tb(n) from the list */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync *ptb = tb->jmp_next[n];
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb->jmp_next[n] = NULL;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync}
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync/* reset the jump entry 'n' of a TB so that it is not chained to
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync another TB */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#ifndef VBOX
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncstatic inline void tb_reset_jump(TranslationBlock *tb, int n)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#else
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncDECLINLINE(void) tb_reset_jump(TranslationBlock *tb, int n)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#endif
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync{
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb_set_jmp_target(tb, n, (unsigned long)(tb->tc_ptr + tb->tb_next_offset[n]));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync}
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncvoid tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync{
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync CPUState *env;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync PageDesc *p;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync unsigned int h, n1;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync target_phys_addr_t phys_pc;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync TranslationBlock *tb1, *tb2;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* remove the TB from the hash list */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync h = tb_phys_hash_func(phys_pc);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync tb_remove(&tb_phys_hash[h], tb,
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync offsetof(TranslationBlock, phys_hash_next));
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* remove the TB from the page list */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync if (tb->page_addr[0] != page_addr) {
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync p = page_find(tb->page_addr[0] >> TARGET_PAGE_BITS);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb_page_remove(&p->first_tb, tb);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync invalidate_page_bitmap(p);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
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 tb_page_remove(&p->first_tb, tb);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync invalidate_page_bitmap(p);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync tb_invalidated_flag = 1;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* remove the TB from the hash list */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync h = tb_jmp_cache_hash_func(tb->pc);
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync for(env = first_cpu; env != NULL; env = env->next_cpu) {
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if (env->tb_jmp_cache[h] == tb)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync env->tb_jmp_cache[h] = NULL;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync /* suppress this TB from the two jump lists */
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync tb_jmp_remove(tb, 0);
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync tb_jmp_remove(tb, 1);
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync /* suppress any remaining jumps to this TB */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb1 = tb->jmp_first;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync for(;;) {
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync n1 = (long)tb1 & 3;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync if (n1 == 2)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync break;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb1 = (TranslationBlock *)((long)tb1 & ~3);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync tb2 = tb1->jmp_next[n1];
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb_reset_jump(tb1, n1);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync tb1->jmp_next[n1] = NULL;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb1 = tb2;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync }
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb->jmp_first = (TranslationBlock *)((long)tb | 2); /* fail safe */
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#ifndef VBOX
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb_phys_invalidate_count++;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#endif
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync}
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync#ifdef VBOX
66b58af085e22ee26be57f98127fb49ee2e91790vboxsyncvoid tb_invalidate_virt(CPUState *env, uint32_t eip)
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync{
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync# if 1
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb_flush(env);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync# else
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync uint8_t *cs_base, *pc;
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync unsigned int flags, h, phys_pc;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync TranslationBlock *tb, **ptb;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync flags = env->hflags;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync cs_base = env->segs[R_CS].base;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync pc = cs_base + eip;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync flags);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync if(tb)
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync {
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync# ifdef DEBUG
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync printf("invalidating TB (%08X) at %08X\n", tb, eip);
f9cdd92d151d9c28eb0f1aed25863fc04f85691dvboxsync# endif
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync tb_invalidate(tb);
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync //Note: this will leak TBs, but the whole cache will be flushed
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync // when it happens too often
c66c4413faa5a72ce047742f9acfa85e94dec8afvboxsync tb->pc = 0;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb->cs_base = 0;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync tb->flags = 0;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync# endif
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync}
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync# ifdef VBOX_STRICT
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync/**
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync * Gets the page offset.
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncunsigned long get_phys_page_offset(target_ulong addr)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync{
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync PhysPageDesc *p = phys_page_find(addr >> TARGET_PAGE_BITS);
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync return p ? p->phys_offset : 0;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync}
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync# endif /* VBOX_STRICT */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#endif /* VBOX */
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#ifndef VBOX
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncstatic inline void set_bits(uint8_t *tab, int start, int len)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#else
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsyncDECLINLINE(void) set_bits(uint8_t *tab, int start, int len)
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync#endif
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync{
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync int end, mask, end1;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync end = start + len;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync tab += start >> 3;
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync mask = 0xff << (start & 7);
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync if ((start & ~7) == (end & ~7)) {
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync if (start < end) {
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync mask &= ~(0xff << (end & 7));
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync *tab |= mask;
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync }
66b58af085e22ee26be57f98127fb49ee2e91790vboxsync } else {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync *tab++ |= mask;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync start = (start + 8) & ~7;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync end1 = end & ~7;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync while (start < end1) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync *tab++ = 0xff;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync start += 8;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (start < end) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync mask = ~(0xff << (end & 7));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync *tab |= mask;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic void build_page_bitmap(PageDesc *p)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int n, tb_start, tb_end;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync TranslationBlock *tb;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (!p->code_bitmap)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync memset(p->code_bitmap, 0, TARGET_PAGE_SIZE / 8);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb = p->first_tb;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync while (tb != NULL) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync n = (long)tb & 3;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb = (TranslationBlock *)((long)tb & ~3);
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_start = tb->pc & ~TARGET_PAGE_MASK;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb_end = tb_start + tb->size;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (tb_end > TARGET_PAGE_SIZE)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb_end = TARGET_PAGE_SIZE;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync } else {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb_start = 0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb_end = ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync set_bits(p->code_bitmap, tb_start, tb_end - tb_start);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb = tb->page_next[n];
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncTranslationBlock *tb_gen_code(CPUState *env,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync target_ulong pc, target_ulong cs_base,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int flags, int cflags)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync TranslationBlock *tb;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync uint8_t *tc_ptr;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync target_ulong phys_pc, phys_page2, virt_page2;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int code_gen_size;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync phys_pc = get_phys_addr_code(env, pc);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb = tb_alloc(pc);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (!tb) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* flush must be done */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb_flush(env);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* cannot fail at this point */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb = tb_alloc(pc);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* Don't forget to invalidate previous TB info. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb_invalidated_flag = 1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tc_ptr = code_gen_ptr;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb->tc_ptr = tc_ptr;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb->cs_base = cs_base;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb->flags = flags;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb->cflags = cflags;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cpu_gen_code(env, tb, &code_gen_size);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* check next page if needed */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync phys_page2 = -1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if ((pc & TARGET_PAGE_MASK) != virt_page2) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync phys_page2 = get_phys_addr_code(env, virt_page2);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb_link_phys(tb, phys_pc, phys_page2);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return tb;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
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 is_cpu_write_access)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int n, current_tb_modified, current_tb_not_found, current_flags;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync CPUState *env = cpu_single_env;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync PageDesc *p;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync TranslationBlock *tb, *tb_next, *current_tb, *saved_tb;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync target_ulong tb_start, tb_end;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync target_ulong current_pc, current_cs_base;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync p = page_find(start >> TARGET_PAGE_BITS);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if (!p)
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync return;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if (!p->code_bitmap &&
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync is_cpu_write_access) {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* build code bitmap */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync build_page_bitmap(p);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync }
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
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 current_tb_not_found = is_cpu_write_access;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync current_tb_modified = 0;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync current_tb = NULL; /* avoid warning */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync current_pc = 0; /* avoid warning */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync current_cs_base = 0; /* avoid warning */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync current_flags = 0; /* avoid warning */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync tb = p->first_tb;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync while (tb != NULL) {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync n = (long)tb & 3;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync tb = (TranslationBlock *)((long)tb & ~3);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync tb_next = tb->page_next[n];
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->size;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync } else {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync tb_start = tb->page_addr[1];
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync tb_end = tb_start + ((tb->pc + tb->size) & ~TARGET_PAGE_MASK);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync }
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if (!(tb_end <= start || tb_start >= end)) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef TARGET_HAS_PRECISE_SMC
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (current_tb_not_found) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync current_tb_not_found = 0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync current_tb = NULL;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (env->mem_io_pc) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* now we have a real cpu fault */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync current_tb = tb_find_pc(env->mem_io_pc);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (current_tb == tb &&
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync (current_tb->cflags & CF_COUNT_MASK) != 1) {
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
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync current_tb_modified = 1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync cpu_restore_state(current_tb, env,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync env->mem_io_pc, NULL);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if defined(TARGET_I386)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync current_flags = env->hflags;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync current_cs_base = (target_ulong)env->segs[R_CS].base;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync current_pc = current_cs_base + env->eip;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#error unsupported CPU
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
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() */
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync saved_tb = NULL;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync if (env) {
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync saved_tb = env->current_tb;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync env->current_tb = NULL;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync }
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync tb_phys_invalidate(tb, -1);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync if (env) {
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync env->current_tb = saved_tb;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync if (env->interrupt_request && env->current_tb)
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync cpu_interrupt(env, env->interrupt_request);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync }
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync }
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync tb = tb_next;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if !defined(CONFIG_USER_ONLY)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* if no code remaining, no need to continue to use slow writes */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (!p->first_tb) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync invalidate_page_bitmap(p);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (is_cpu_write_access) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_unprotect_code_phys(env, start, env->mem_io_vaddr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef TARGET_HAS_PRECISE_SMC
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (current_tb_modified) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* we generate a block containing just the instruction
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync modifying the memory. It will ensure that it cannot modify
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync itself */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync env->current_tb = NULL;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cpu_resume_from_signal(env, NULL);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* len must be <= 8 and start must be a multiple of len */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifndef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic inline void tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncDECLINLINE(void) tb_invalidate_phys_page_fast(target_phys_addr_t start, int len)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync PageDesc *p;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int offset, b;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if 0
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (1) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (loglevel) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cpu_single_env->mem_io_vaddr, len,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cpu_single_env->eip,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p = page_find(start >> TARGET_PAGE_BITS);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (!p)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (p->code_bitmap) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync offset = start & ~TARGET_PAGE_MASK;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync b = p->code_bitmap[offset >> 3] >> (offset & 7);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (b & ((1 << len) - 1))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync goto do_invalidate;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync } else {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync do_invalidate:
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_invalidate_phys_page_range(start, start + len, 1);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if !defined(CONFIG_SOFTMMU)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic void tb_invalidate_phys_page(target_phys_addr_t addr,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync unsigned long pc, void *puc)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int n, current_flags, current_tb_modified;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync target_ulong current_pc, current_cs_base;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync PageDesc *p;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync TranslationBlock *tb, *current_tb;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef TARGET_HAS_PRECISE_SMC
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync CPUState *env = cpu_single_env;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync addr &= TARGET_PAGE_MASK;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p = page_find(addr >> TARGET_PAGE_BITS);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (!p)
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync return;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync tb = p->first_tb;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_tb_modified = 0;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_tb = NULL;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_pc = 0; /* avoid warning */
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_cs_base = 0; /* avoid warning */
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_flags = 0; /* avoid warning */
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync#ifdef TARGET_HAS_PRECISE_SMC
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync if (tb && pc != 0) {
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_tb = tb_find_pc(pc);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync }
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync#endif
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync while (tb != NULL) {
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync n = (long)tb & 3;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync tb = (TranslationBlock *)((long)tb & ~3);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync#ifdef TARGET_HAS_PRECISE_SMC
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync if (current_tb == tb &&
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync (current_tb->cflags & CF_COUNT_MASK) != 1) {
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
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_tb_modified = 1;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync cpu_restore_state(current_tb, env, pc, puc);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync#if defined(TARGET_I386)
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_flags = env->hflags;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_cs_base = (target_ulong)env->segs[R_CS].base;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync current_pc = current_cs_base + env->eip;
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync#else
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync#error unsupported CPU
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif /* TARGET_HAS_PRECISE_SMC */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_phys_invalidate(tb, addr);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb = tb->page_next[n];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync p->first_tb = NULL;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#ifdef TARGET_HAS_PRECISE_SMC
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (current_tb_modified) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* we generate a block containing just the instruction
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync modifying the memory. It will ensure that it cannot modify
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync itself */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync env->current_tb = NULL;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_gen_code(env, current_pc, current_cs_base, current_flags, 1);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync cpu_resume_from_signal(env, puc);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync}
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* add the tb in the target page and protect it if necessary */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#ifndef VBOX
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncstatic inline void tb_alloc_page(TranslationBlock *tb,
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync unsigned int n, target_ulong page_addr)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#else
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncDECLINLINE(void) tb_alloc_page(TranslationBlock *tb,
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync unsigned int n, target_ulong page_addr)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync PageDesc *p;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync TranslationBlock *last_first_tb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb->page_addr[n] = page_addr;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync p = page_find_alloc(page_addr >> TARGET_PAGE_BITS);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb->page_next[n] = p->first_tb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync last_first_tb = p->first_tb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync p->first_tb = (TranslationBlock *)((long)tb | n);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync invalidate_page_bitmap(p);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#if defined(TARGET_HAS_SMC) || 1
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#if defined(CONFIG_USER_ONLY)
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if (p->flags & PAGE_WRITE) {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync target_ulong addr;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync PageDesc *p2;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync int prot;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* force the host page as non writable (writes will have a
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync page fault + mprotect overhead) */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync page_addr &= qemu_host_page_mask;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync prot = 0;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync for(addr = page_addr; addr < page_addr + qemu_host_page_size;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync addr += TARGET_PAGE_SIZE) {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p2 = page_find (addr >> TARGET_PAGE_BITS);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if (!p2)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync continue;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync prot |= p2->flags;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync p2->flags &= ~PAGE_WRITE;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync page_get_flags(addr);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync mprotect(g2h(page_addr), qemu_host_page_size,
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync (prot & PAGE_BITS) & ~PAGE_WRITE);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#ifdef DEBUG_TB_INVALIDATE
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync printf("protecting code page: 0x" TARGET_FMT_lx "\n",
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync page_addr);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#else
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 if (!last_first_tb) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tlb_protect_code(page_addr);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif /* TARGET_HAS_SMC */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync}
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* Allocate a new translation block. Flush the translation buffer if
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync too many translation blocks or too much generated code. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncTranslationBlock *tb_alloc(target_ulong pc)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync TranslationBlock *tb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (nb_tbs >= code_gen_max_blocks ||
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#ifndef VBOX
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync (code_gen_ptr - code_gen_buffer) >= code_gen_buffer_max_size)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#else
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync (code_gen_ptr - code_gen_buffer) >= (int)code_gen_buffer_max_size)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return NULL;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb = &tbs[nb_tbs++];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb->pc = pc;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb->cflags = 0;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return tb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync}
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncvoid tb_free(TranslationBlock *tb)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
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 if (nb_tbs > 0 && tb == &tbs[nb_tbs - 1]) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync code_gen_ptr = tb->tc_ptr;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync nb_tbs--;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync}
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
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. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncvoid tb_link_phys(TranslationBlock *tb,
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync target_ulong phys_pc, target_ulong phys_page2)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync unsigned int h;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync TranslationBlock **ptb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* Grab the mmap lock to stop another thread invalidating this TB
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync before we are done. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync mmap_lock();
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* add in the physical hash table */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync h = tb_phys_hash_func(phys_pc);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ptb = &tb_phys_hash[h];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb->phys_hash_next = *ptb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync *ptb = tb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* add in the page list */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_alloc_page(tb, 0, phys_pc & TARGET_PAGE_MASK);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (phys_page2 != -1)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_alloc_page(tb, 1, phys_page2);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync else
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb->page_addr[1] = -1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb->jmp_first = (TranslationBlock *)((long)tb | 2);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb->jmp_next[0] = NULL;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb->jmp_next[1] = NULL;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* init original jump addresses */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (tb->tb_next_offset[0] != 0xffff)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_reset_jump(tb, 0);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (tb->tb_next_offset[1] != 0xffff)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_reset_jump(tb, 1);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#ifdef DEBUG_TB_CHECK
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_page_check();
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync mmap_unlock();
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync}
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb[1].tc_ptr. Return NULL if not found */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncTranslationBlock *tb_find_pc(unsigned long tc_ptr)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync int m_min, m_max, m;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync unsigned long v;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync TranslationBlock *tb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (nb_tbs <= 0)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return NULL;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (tc_ptr < (unsigned long)code_gen_buffer ||
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tc_ptr >= (unsigned long)code_gen_ptr)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return NULL;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* binary search (cf Knuth) */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync m_min = 0;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync m_max = nb_tbs - 1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync while (m_min <= m_max) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync m = (m_min + m_max) >> 1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb = &tbs[m];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync v = (unsigned long)tb->tc_ptr;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (v == tc_ptr)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return tb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync else if (tc_ptr < v) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync m_max = m - 1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync } else {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync m_min = m + 1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return &tbs[m_max];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync}
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncstatic void tb_reset_jump_recursive(TranslationBlock *tb);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#ifndef VBOX
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncstatic inline void tb_reset_jump_recursive2(TranslationBlock *tb, int n)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#else
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncDECLINLINE(void) tb_reset_jump_recursive2(TranslationBlock *tb, int n)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync TranslationBlock *tb1, *tb_next, **ptb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync unsigned int n1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb1 = tb->jmp_next[n];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (tb1 != NULL) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* find head of list */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync for(;;) {
661bfa5aae55ac2f94fa1cb131ea2323e5f6e633vboxsync n1 = (long)tb1 & 3;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb1 = (TranslationBlock *)((long)tb1 & ~3);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (n1 == 2)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync break;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb1 = tb1->jmp_next[n1];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* we are now sure now that tb jumps to tb1 */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_next = tb1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* remove tb from the jmp_first list */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ptb = &tb_next->jmp_first;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync for(;;) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb1 = *ptb;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync n1 = (long)tb1 & 3;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb1 = (TranslationBlock *)((long)tb1 & ~3);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (n1 == n && tb1 == tb)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync break;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ptb = &tb1->jmp_next[n1];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync *ptb = tb->jmp_next[n];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb->jmp_next[n] = NULL;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* suppress the jump to next tb in generated code */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_reset_jump(tb, n);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync /* suppress jumps in the tb on which we could have jumped */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_reset_jump_recursive(tb_next);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync}
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncstatic void tb_reset_jump_recursive(TranslationBlock *tb)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_reset_jump_recursive2(tb, 0);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_reset_jump_recursive2(tb, 1);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync}
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#if defined(TARGET_HAS_ICE)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncstatic void breakpoint_invalidate(CPUState *env, target_ulong pc)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync target_ulong addr, pd;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ram_addr_t ram_addr;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync PhysPageDesc *p;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync addr = cpu_get_phys_page_debug(env, pc);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync p = phys_page_find(addr >> TARGET_PAGE_BITS);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (!p) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync pd = IO_MEM_UNASSIGNED;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync } else {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync pd = p->phys_offset;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync ram_addr = (pd & TARGET_PAGE_MASK) | (pc & ~TARGET_PAGE_MASK);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync tb_invalidate_phys_page_range(ram_addr, ram_addr + 1, 0);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync}
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* Add a watchpoint. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncint cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync int i;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync for (i = 0; i < env->nb_watchpoints; i++) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (addr == env->watchpoint[i].vaddr)
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync return 0;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync }
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync if (env->nb_watchpoints >= MAX_WATCHPOINTS)
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync return -1;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync i = env->nb_watchpoints++;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync env->watchpoint[i].vaddr = addr;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync env->watchpoint[i].type = type;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync tlb_flush_page(env, addr);
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 tb_flush(env);
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync return i;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync}
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync/* Remove a watchpoint. */
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsyncint cpu_watchpoint_remove(CPUState *env, target_ulong addr)
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync{
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync int i;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync for (i = 0; i < env->nb_watchpoints; i++) {
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync if (addr == env->watchpoint[i].vaddr) {
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync env->nb_watchpoints--;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync tlb_flush_page(env, addr);
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync return 0;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync }
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync }
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync return -1;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync}
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync/* Remove all watchpoints. */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsyncvoid cpu_watchpoint_remove_all(CPUState *env) {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync int i;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync for (i = 0; i < env->nb_watchpoints; i++) {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync tlb_flush_page(env, env->watchpoint[i].vaddr);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync }
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync env->nb_watchpoints = 0;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync}
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
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)
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync{
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#if defined(TARGET_HAS_ICE)
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync int i;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync for(i = 0; i < env->nb_breakpoints; i++) {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if (env->breakpoints[i] == pc)
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync return 0;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync }
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if (env->nb_breakpoints >= MAX_BREAKPOINTS)
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync return -1;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync env->breakpoints[env->nb_breakpoints++] = pc;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync breakpoint_invalidate(env, pc);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync return 0;
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync#else
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync return -1;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#endif
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync}
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsync/* remove all breakpoints */
fdb40b7d2efa84fc6f03b7a695cb4b2e035c30c7vboxsyncvoid cpu_breakpoint_remove_all(CPUState *env) {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#if defined(TARGET_HAS_ICE)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync int i;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync for(i = 0; i < env->nb_breakpoints; i++) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync breakpoint_invalidate(env, env->breakpoints[i]);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync }
0c94a8282c9042b02f022302a3d987746140eab9vboxsync env->nb_breakpoints = 0;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#endif
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync}
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync/* remove a breakpoint */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsyncint cpu_breakpoint_remove(CPUState *env, target_ulong pc)
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync{
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#if defined(TARGET_HAS_ICE)
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync int i;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync for(i = 0; i < env->nb_breakpoints; i++) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (env->breakpoints[i] == pc)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync goto found;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync return -1;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync found:
9c9db71d639cf066ed41d49629d46d48bff4be2fvboxsync env->nb_breakpoints--;
9c9db71d639cf066ed41d49629d46d48bff4be2fvboxsync if (i < env->nb_breakpoints)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync env->breakpoints[i] = env->breakpoints[env->nb_breakpoints];
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsync breakpoint_invalidate(env, pc);
0c94a8282c9042b02f022302a3d987746140eab9vboxsync return 0;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#else
0c94a8282c9042b02f022302a3d987746140eab9vboxsync return -1;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#endif
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync}
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* enable or disable single step mode. EXCP_DEBUG is returned by the
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync CPU loop after each instruction */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncvoid cpu_single_step(CPUState *env, int enabled)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#if defined(TARGET_HAS_ICE)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (env->singlestep_enabled != enabled) {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync env->singlestep_enabled = enabled;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* must flush all the translated code to avoid inconsistancies */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync /* XXX: only flush what is necessary */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync tb_flush(env);
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync }
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#endif
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync}
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#ifndef VBOX
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync/* enable or disable low levels log */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncvoid cpu_set_log(int log_flags)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync loglevel = log_flags;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (loglevel && !logfile) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync logfile = fopen(logfilename, "w");
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync if (!logfile) {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync perror(logfilename);
0c94a8282c9042b02f022302a3d987746140eab9vboxsync _exit(1);
0c94a8282c9042b02f022302a3d987746140eab9vboxsync }
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#if !defined(CONFIG_SOFTMMU)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync /* must avoid mmap() usage of glibc by setting a buffer "by hand" */
0c94a8282c9042b02f022302a3d987746140eab9vboxsync {
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync static uint8_t logfile_buf[4096];
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync }
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#else
0c94a8282c9042b02f022302a3d987746140eab9vboxsync setvbuf(logfile, NULL, _IOLBF, 0);
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#endif
0c94a8282c9042b02f022302a3d987746140eab9vboxsync }
0c94a8282c9042b02f022302a3d987746140eab9vboxsync}
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsyncvoid cpu_set_log_filename(const char *filename)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync logfilename = strdup(filename);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync}
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#endif /* !VBOX */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync/* mask must never be zero, except for A20 change call */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsyncvoid cpu_interrupt(CPUState *env, int mask)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#if !defined(USE_NPTL)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync TranslationBlock *tb;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync static spinlock_t interrupt_lock = SPIN_LOCK_UNLOCKED;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#endif
0c94a8282c9042b02f022302a3d987746140eab9vboxsync int old_mask;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync
0c94a8282c9042b02f022302a3d987746140eab9vboxsync old_mask = env->interrupt_request;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync#ifdef VBOX
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync VM_ASSERT_EMT(env->pVM);
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 env->interrupt_request |= mask;
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#endif /* !VBOX */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#if defined(USE_NPTL)
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. */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#else
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if (use_icount) {
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync env->icount_decr.u16.high = 0xffff;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifndef CONFIG_USER_ONLY
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* CPU_INTERRUPT_EXIT isn't a real interrupt. It just means
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync an async event happened and we need to process it. */
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if (!can_do_io(env)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync && (mask & ~(old_mask | CPU_INTERRUPT_EXIT)) != 0) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cpu_abort(env, "Raised interrupt while not in I/O function");
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync } else {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb = env->current_tb;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* if the cpu is currently executing code, we must unlink it and
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync all the potentially executing TB */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (tb && !testandset(&interrupt_lock)) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync env->current_tb = NULL;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tb_reset_jump_recursive(tb);
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync resetlock(&interrupt_lock);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncvoid cpu_reset_interrupt(CPUState *env, int mask)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /*
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync * Note: the current implementation can be executed by another thread without problems; make sure this remains true
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync * for future changes!
0c94a8282c9042b02f022302a3d987746140eab9vboxsync */
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync ASMAtomicAndS32((int32_t volatile *)&env->interrupt_request, ~mask);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else /* !VBOX */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync env->interrupt_request &= ~mask;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#endif /* !VBOX */
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync}
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync#ifndef VBOX
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsyncCPULogItem cpu_log_items[] = {
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync { CPU_LOG_TB_OUT_ASM, "out_asm",
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show generated host assembly code for each compiled TB" },
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync { CPU_LOG_TB_IN_ASM, "in_asm",
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show target assembly code for each compiled TB" },
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync { CPU_LOG_TB_OP, "op",
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync#ifdef TARGET_I386
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync { CPU_LOG_TB_OP_OPT, "op_opt",
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show micro ops after optimization for each compiled TB" },
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync#endif
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync { CPU_LOG_INT, "int",
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show interrupts/exceptions in short format" },
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync { CPU_LOG_EXEC, "exec",
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show trace before each executed TB (lots of logs)" },
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync { CPU_LOG_TB_CPU, "cpu",
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync "show CPU state before bloc translation" },
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync#ifdef TARGET_I386
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync { CPU_LOG_PCALL, "pcall",
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync "show protected mode far calls/returns/exceptions" },
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync#ifdef DEBUG_IOPORT
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync { CPU_LOG_IOPORT, "ioport",
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync "show all i/o ports accesses" },
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync { 0, NULL, NULL },
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync};
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsyncstatic int cmp1(const char *s1, int n, const char *s2)
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync{
88e56f700a3b8dfdf1646f96320f335e22339caavboxsync if (strlen(s2) != n)
49a6b09abb20015b0af3e618a1f92b7e26785e90vboxsync return 0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return memcmp(s1, s2, n) == 0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* takes a comma separated list of log masks. Return 0 if error. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncint cpu_str_to_log_mask(const char *str)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync CPULogItem *item;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int mask;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync const char *p, *p1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p = str;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync mask = 0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(;;) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p1 = strchr(p, ',');
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (!p1)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p1 = p + strlen(p);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if(cmp1(p,p1-p,"all")) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(item = cpu_log_items; item->mask != 0; item++) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync mask |= item->mask;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync } else {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(item = cpu_log_items; item->mask != 0; item++) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (cmp1(p, p1 - p, item->name))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync goto found;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return 0;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync found:
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync mask |= item->mask;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (*p1 != ',')
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync break;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p = p1 + 1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return mask;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* !VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifndef VBOX /* VBOX: we have our own routine. */
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsyncvoid cpu_abort(CPUState *env, const char *fmt, ...)
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync{
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync va_list ap;
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync va_start(ap, fmt);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync fprintf(stderr, "qemu: fatal: ");
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync vfprintf(stderr, fmt, ap);
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync fprintf(stderr, "\n");
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef TARGET_I386
5c4d7e2aae42bbf39793dfa686925f076a56b4d5vboxsync cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync cpu_dump_state(env, stderr, fprintf, 0);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync va_end(ap);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync abort();
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* !VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifndef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncCPUState *cpu_copy(CPUState *env)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync CPUState *new_env = cpu_init(env->cpu_model_str);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* preserve chaining and index */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync CPUState *next_cpu = new_env->next_cpu;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int cpu_index = new_env->cpu_index;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync memcpy(new_env, env, sizeof(CPUState));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync new_env->next_cpu = next_cpu;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync new_env->cpu_index = cpu_index;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return new_env;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#if !defined(CONFIG_USER_ONLY)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#ifndef VBOX
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncstatic inline void tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#else
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsyncDECLINLINE(void) tlb_flush_jmp_cache(CPUState *env, target_ulong addr)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync{
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync unsigned int i;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync
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);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync memset (&env->tb_jmp_cache[i], 0,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync i = tb_jmp_cache_hash_page(addr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync memset (&env->tb_jmp_cache[i], 0,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync TB_JMP_PAGE_SIZE * sizeof(TranslationBlock *));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync#ifdef VBOX
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync /* inform raw mode about TLB page flush */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync remR3FlushPage(env, addr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif /* VBOX */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync/* NOTE: if flush_global is true, also flush global entries (not
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync implemented yet) */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncvoid tlb_flush(CPUState *env, int flush_global)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync int i;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#if defined(DEBUG_TLB)
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync printf("tlb_flush:\n");
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* must reset current TB so that interrupts cannot modify the
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync links while we are modifying them */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync env->current_tb = NULL;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync for(i = 0; i < CPU_TLB_SIZE; i++) {
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync env->tlb_table[0][i].addr_read = -1;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync env->tlb_table[0][i].addr_write = -1;
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync env->tlb_table[0][i].addr_code = -1;
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync env->tlb_table[1][i].addr_read = -1;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync env->tlb_table[1][i].addr_write = -1;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync env->tlb_table[1][i].addr_code = -1;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#if (NB_MMU_MODES >= 3)
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync env->tlb_table[2][i].addr_read = -1;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync env->tlb_table[2][i].addr_write = -1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync env->tlb_table[2][i].addr_code = -1;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#if (NB_MMU_MODES == 4)
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync env->tlb_table[3][i].addr_read = -1;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync env->tlb_table[3][i].addr_write = -1;
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync env->tlb_table[3][i].addr_code = -1;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#endif
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#endif
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync }
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* inform raw mode about TLB flush */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync remR3FlushTLB(env, flush_global);
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef USE_KQEMU
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (env->kqemu_enabled) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync kqemu_flush(env, flush_global);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
19320d55d1417c39b3b5673a53aaa5ef177242c8vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_flush_count++;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifndef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncDECLINLINE(void) tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (addr == (tlb_entry->addr_read &
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync addr == (tlb_entry->addr_write &
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync addr == (tlb_entry->addr_code &
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_entry->addr_read = -1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_entry->addr_write = -1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_entry->addr_code = -1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncvoid tlb_flush_page(CPUState *env, target_ulong addr)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int i;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if defined(DEBUG_TLB)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync printf("tlb_flush_page: " TARGET_FMT_lx "\n", addr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* must reset current TB so that interrupts cannot modify the
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync links while we are modifying them */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync env->current_tb = NULL;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync addr &= TARGET_PAGE_MASK;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_flush_entry(&env->tlb_table[0][i], addr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_flush_entry(&env->tlb_table[1][i], addr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if (NB_MMU_MODES >= 3)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_flush_entry(&env->tlb_table[2][i], addr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if (NB_MMU_MODES == 4)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_flush_entry(&env->tlb_table[3][i], addr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_flush_jmp_cache(env, addr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef USE_KQEMU
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (env->kqemu_enabled) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync kqemu_flush_page(env, addr);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync/* update the TLBs so that writes to code in the virtual page 'addr'
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync can be detected */
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsyncstatic void tlb_protect_code(ram_addr_t ram_addr)
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync{
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync cpu_physical_memory_reset_dirty(ram_addr,
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync ram_addr + TARGET_PAGE_SIZE,
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync CODE_DIRTY_FLAG);
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#if defined(VBOX) && defined(REM_MONITOR_CODE_PAGES)
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync /** @todo Retest this? This function has changed... */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync remR3ProtectCode(cpu_single_env, ram_addr);
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync#endif
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync}
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync
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,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync target_ulong vaddr)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef VBOX
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync if (RT_LIKELY((ram_addr >> TARGET_PAGE_BITS) < phys_ram_dirty_size))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync}
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifndef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncstatic inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync unsigned long start, unsigned long length)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#else
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsyncDECLINLINE(void) tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync unsigned long start, unsigned long length)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync{
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync unsigned long addr;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (start & 3)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync return;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
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 if ((addr - start) < length) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_entry->addr_write = (tlb_entry->addr_write & TARGET_PAGE_MASK) | IO_MEM_NOTDIRTY;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
9c9db71d639cf066ed41d49629d46d48bff4be2fvboxsync }
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync}
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsyncvoid cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end,
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync int dirty_flags)
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync{
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync CPUState *env;
44372afb953dc9f1f1ec71943f5f561a607c0307vboxsync unsigned long length, start1;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync int i, mask, len;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync uint8_t *p;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync start &= TARGET_PAGE_MASK;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync end = TARGET_PAGE_ALIGN(end);
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync length = end - start;
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync if (length == 0)
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync return;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync len = length >> TARGET_PAGE_BITS;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef USE_KQEMU
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* XXX: should not depend on cpu context */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync env = first_cpu;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (env->kqemu_enabled) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync ram_addr_t addr;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync addr = start;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(i = 0; i < len; i++) {
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync kqemu_set_notdirty(env, addr);
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync addr += TARGET_PAGE_SIZE;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync }
29099c2d04b11e614f1fa399fab9e9162f2788b9vboxsync }
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync mask = ~dirty_flags;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p = phys_ram_dirty + (start >> TARGET_PAGE_BITS);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#ifdef VBOX
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync if (RT_LIKELY((start >> TARGET_PAGE_BITS) < phys_ram_dirty_size))
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(i = 0; i < len; i++)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync p[i] &= mask;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync /* we modify the TLB cache so that the dirty bit will be set again
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync when accessing the range */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if defined(VBOX) && defined(REM_PHYS_ADDR_IN_TLB)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync start1 = start;
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#elif !defined(VBOX)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync start1 = start + (unsigned long)phys_ram_base;
0c94a8282c9042b02f022302a3d987746140eab9vboxsync#else
0c94a8282c9042b02f022302a3d987746140eab9vboxsync start1 = (unsigned long)remR3TlbGCPhys2Ptr(first_cpu, start, 1 /*fWritable*/); /** @todo this can be harmful with VBOX_WITH_NEW_PHYS_CODE, fix interface/whatever. */
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
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#if (NB_MMU_MODES >= 3)
0c94a8282c9042b02f022302a3d987746140eab9vboxsync for(i = 0; i < CPU_TLB_SIZE; i++)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#if (NB_MMU_MODES == 4)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync for(i = 0; i < CPU_TLB_SIZE; i++)
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
0c69348b58bb8eabb1bea8867ee932b667bd0d34vboxsync#endif
}
}
#ifndef VBOX
int cpu_physical_memory_set_dirty_tracking(int enable)
{
in_migration = enable;
return 0;
}
int cpu_physical_memory_get_dirty_tracking(void)
{
return in_migration;
}
#endif
#ifndef VBOX
static inline void tlb_update_dirty(CPUTLBEntry *tlb_entry)
#else
DECLINLINE(void) tlb_update_dirty(CPUTLBEntry *tlb_entry)
#endif
{
ram_addr_t ram_addr;
if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
/* RAM case */
#if defined(VBOX) && defined(REM_PHYS_ADDR_IN_TLB)
ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend;
#elif !defined(VBOX)
ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
tlb_entry->addend - (unsigned long)phys_ram_base;
#else
ram_addr = remR3HCVirt2GCPhys(first_cpu, (void*)((tlb_entry->addr_write & TARGET_PAGE_MASK) + tlb_entry->addend));
#endif
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(CPUState *env)
{
int i;
for(i = 0; i < CPU_TLB_SIZE; i++)
tlb_update_dirty(&env->tlb_table[0][i]);
for(i = 0; i < CPU_TLB_SIZE; i++)
tlb_update_dirty(&env->tlb_table[1][i]);
#if (NB_MMU_MODES >= 3)
for(i = 0; i < CPU_TLB_SIZE; i++)
tlb_update_dirty(&env->tlb_table[2][i]);
#if (NB_MMU_MODES == 4)
for(i = 0; i < CPU_TLB_SIZE; i++)
tlb_update_dirty(&env->tlb_table[3][i]);
#endif
#endif
}
#ifndef VBOX
static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
#else
DECLINLINE(void) tlb_set_dirty1(CPUTLBEntry *tlb_entry, target_ulong vaddr)
#endif
{
if (tlb_entry->addr_write == (vaddr | TLB_NOTDIRTY))
tlb_entry->addr_write = vaddr;
}
/* update the TLB corresponding to virtual page vaddr and phys addr
addr so that it is no longer dirty */
#ifndef VBOX
static inline void tlb_set_dirty(CPUState *env,
unsigned long addr, target_ulong vaddr)
#else
DECLINLINE(void) tlb_set_dirty(CPUState *env,
unsigned long addr, target_ulong vaddr)
#endif
{
int i;
addr &= TARGET_PAGE_MASK;
i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
tlb_set_dirty1(&env->tlb_table[0][i], addr);
tlb_set_dirty1(&env->tlb_table[1][i], addr);
#if (NB_MMU_MODES >= 3)
tlb_set_dirty1(&env->tlb_table[2][i], vaddr);
#if (NB_MMU_MODES == 4)
tlb_set_dirty1(&env->tlb_table[3][i], vaddr);
#endif
#endif
}
/* add a new TLB entry. At most one entry for a given virtual address
is permitted. Return 0 if OK or 2 if the page could not be mapped
(can only happen in non SOFTMMU mode for I/O pages or pages
conflicting with the host address space). */
int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
target_phys_addr_t paddr, int prot,
int mmu_idx, int is_softmmu)
{
PhysPageDesc *p;
unsigned long pd;
unsigned int index;
target_ulong address;
target_ulong code_address;
target_phys_addr_t addend;
int ret;
CPUTLBEntry *te;
int i;
target_phys_addr_t iotlb;
p = phys_page_find(paddr >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
} else {
pd = p->phys_offset;
}
#if defined(DEBUG_TLB)
printf("tlb_set_page: vaddr=" TARGET_FMT_lx " paddr=0x%08x prot=%x idx=%d smmu=%d pd=0x%08lx\n",
vaddr, (int)paddr, prot, mmu_idx, is_softmmu, pd);
#endif
ret = 0;
address = vaddr;
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
/* IO memory case (romd handled later) */
address |= TLB_MMIO;
}
#if defined(VBOX) && defined(REM_PHYS_ADDR_IN_TLB)
addend = pd & TARGET_PAGE_MASK;
#elif !defined(VBOX)
addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
#else
/** @todo this is racing the phys_page_find call above since it may register
* a new chunk of memory... */
addend = (unsigned long)remR3TlbGCPhys2Ptr(env,
pd & TARGET_PAGE_MASK,
!!(prot & PAGE_WRITE));
#endif
if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
/* Normal RAM. */
iotlb = pd & TARGET_PAGE_MASK;
if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM)
iotlb |= IO_MEM_NOTDIRTY;
else
iotlb |= IO_MEM_ROM;
} else {
/* IO handlers are currently passed a phsical address.
It would be nice to pass an offset from the base address
of that region. This would avoid having to special case RAM,
and avoid full address decoding in every device.
We can't use the high bits of pd for this because
IO_MEM_ROMD uses these as a ram address. */
iotlb = (pd & ~TARGET_PAGE_MASK) + paddr;
}
code_address = address;
#ifdef VBOX
# if !defined(REM_PHYS_ADDR_IN_TLB)
if (addend & 0x2)
{
/* catch write */
addend &= ~(target_ulong)0x3;
if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
{
/** @todo improve this, it's only avoid code reads right now! */
address |= TLB_MMIO;
iotlb = env->pVM->rem.s.iHandlerMemType + paddr;
}
}
else if (addend & 0x1)
{
/* catch all */
addend &= ~(target_ulong)0x3;
if ((pd & ~TARGET_PAGE_MASK) <= IO_MEM_ROM)
{
address |= TLB_MMIO;
code_address |= TLB_MMIO;
iotlb = env->pVM->rem.s.iHandlerMemType + paddr;
}
}
# endif
#endif
/* Make accesses to pages with watchpoints go via the
watchpoint trap routines. */
for (i = 0; i < env->nb_watchpoints; i++) {
if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
iotlb = io_mem_watch + paddr;
/* TODO: The memory case can be optimized by not trapping
reads of pages with a write breakpoint. */
address |= TLB_MMIO;
}
}
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 ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
(pd & IO_MEM_ROMD)) {
/* Write access calls the I/O callback. */
te->addr_write = address | TLB_MMIO;
} else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
!cpu_physical_memory_is_dirty(pd)) {
te->addr_write = address | TLB_NOTDIRTY;
} else {
te->addr_write = address;
}
} else {
te->addr_write = -1;
}
#ifdef VBOX
/* inform raw mode about TLB page change */
remR3FlushPage(env, vaddr);
#endif
return ret;
}
#if 0
/* called from signal handler: invalidate the code and unprotect the
page. Return TRUE if the fault was succesfully handled. */
int page_unprotect(target_ulong addr, unsigned long pc, void *puc)
{
#if !defined(CONFIG_SOFTMMU)
VirtPageDesc *vp;
#if defined(DEBUG_TLB)
printf("page_unprotect: addr=0x%08x\n", addr);
#endif
addr &= TARGET_PAGE_MASK;
/* if it is not mapped, no need to worry here */
if (addr >= MMAP_AREA_END)
return 0;
vp = virt_page_find(addr >> TARGET_PAGE_BITS);
if (!vp)
return 0;
/* NOTE: in this case, validate_tag is _not_ tested as it
validates only the code TLB */
if (vp->valid_tag != virt_valid_tag)
return 0;
if (!(vp->prot & PAGE_WRITE))
return 0;
#if defined(DEBUG_TLB)
printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
addr, vp->phys_addr, vp->prot);
#endif
if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
cpu_abort(cpu_single_env, "error mprotect addr=0x%lx prot=%d\n",
(unsigned long)addr, vp->prot);
/* set the dirty bit */
phys_ram_dirty[vp->phys_addr >> TARGET_PAGE_BITS] = 0xff;
/* flush the code inside */
tb_invalidate_phys_page(vp->phys_addr, pc, puc);
return 1;
#elif defined(VBOX)
addr &= TARGET_PAGE_MASK;
/* if it is not mapped, no need to worry here */
if (addr >= MMAP_AREA_END)
return 0;
return 1;
#else
return 0;
#endif
}
#endif /* 0 */
#else
void tlb_flush(CPUState *env, int flush_global)
{
}
void tlb_flush_page(CPUState *env, target_ulong addr)
{
}
int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
target_phys_addr_t paddr, int prot,
int mmu_idx, int is_softmmu)
{
return 0;
}
#ifndef VBOX
/* dump memory mappings */
void page_dump(FILE *f)
{
unsigned long start, end;
int i, j, prot, prot1;
PageDesc *p;
fprintf(f, "%-8s %-8s %-8s %s\n",
"start", "end", "size", "prot");
start = -1;
end = -1;
prot = 0;
for(i = 0; i <= L1_SIZE; i++) {
if (i < L1_SIZE)
p = l1_map[i];
else
p = NULL;
for(j = 0;j < L2_SIZE; j++) {
if (!p)
prot1 = 0;
else
prot1 = p[j].flags;
if (prot1 != prot) {
end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
if (start != -1) {
fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
start, end, end - start,
prot & PAGE_READ ? 'r' : '-',
prot & PAGE_WRITE ? 'w' : '-',
prot & PAGE_EXEC ? 'x' : '-');
}
if (prot1 != 0)
start = end;
else
start = -1;
prot = prot1;
}
if (!p)
break;
}
}
}
#endif /* !VBOX */
int page_get_flags(target_ulong address)
{
PageDesc *p;
p = page_find(address >> TARGET_PAGE_BITS);
if (!p)
return 0;
return p->flags;
}
/* modify the flags of a page and invalidate the code if
necessary. The flag PAGE_WRITE_ORG is positionned automatically
depending on PAGE_WRITE */
void page_set_flags(target_ulong start, target_ulong end, int flags)
{
PageDesc *p;
target_ulong addr;
start = start & TARGET_PAGE_MASK;
end = TARGET_PAGE_ALIGN(end);
if (flags & PAGE_WRITE)
flags |= PAGE_WRITE_ORG;
#ifdef VBOX
AssertMsgFailed(("We shouldn't be here, and if we should, we must have an env to do the proper locking!\n"));
#endif
spin_lock(&tb_lock);
for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
p = page_find_alloc(addr >> TARGET_PAGE_BITS);
/* if the write protection is set, then we invalidate the code
inside */
if (!(p->flags & PAGE_WRITE) &&
(flags & PAGE_WRITE) &&
p->first_tb) {
tb_invalidate_phys_page(addr, 0, NULL);
}
p->flags = flags;
}
spin_unlock(&tb_lock);
}
int page_check_range(target_ulong start, target_ulong len, int flags)
{
PageDesc *p;
target_ulong end;
target_ulong addr;
end = TARGET_PAGE_ALIGN(start+len); /* must do before we loose bits in the next step */
start = start & TARGET_PAGE_MASK;
if( end < start )
/* we've wrapped around */
return -1;
for(addr = start; addr < end; addr += TARGET_PAGE_SIZE) {
p = page_find(addr >> TARGET_PAGE_BITS);
if( !p )
return -1;
if( !(p->flags & PAGE_VALID) )
return -1;
if ((flags & PAGE_READ) && !(p->flags & PAGE_READ))
return -1;
if (flags & PAGE_WRITE) {
if (!(p->flags & PAGE_WRITE_ORG))
return -1;
/* unprotect the page if it was put read-only because it
contains translated code */
if (!(p->flags & PAGE_WRITE)) {
if (!page_unprotect(addr, 0, NULL))
return -1;
}
return 0;
}
}
return 0;
}
/* called from signal handler: invalidate the code and unprotect the
page. Return TRUE if the fault was succesfully handled. */
int page_unprotect(target_ulong address, unsigned long pc, void *puc)
{
unsigned int page_index, prot, pindex;
PageDesc *p, *p1;
target_ulong host_start, host_end, addr;
/* Technically this isn't safe inside a signal handler. However we
know this only ever happens in a synchronous SEGV handler, so in
practice it seems to be ok. */
mmap_lock();
host_start = address & qemu_host_page_mask;
page_index = host_start >> TARGET_PAGE_BITS;
p1 = page_find(page_index);
if (!p1) {
mmap_unlock();
return 0;
}
host_end = host_start + qemu_host_page_size;
p = p1;
prot = 0;
for(addr = host_start;addr < host_end; addr += TARGET_PAGE_SIZE) {
prot |= p->flags;
p++;
}
/* if the page was really writable, then we change its
protection back to writable */
if (prot & PAGE_WRITE_ORG) {
pindex = (address - host_start) >> TARGET_PAGE_BITS;
if (!(p1[pindex].flags & PAGE_WRITE)) {
mprotect((void *)g2h(host_start), qemu_host_page_size,
(prot & PAGE_BITS) | PAGE_WRITE);
p1[pindex].flags |= PAGE_WRITE;
/* and since the content will be modified, we must invalidate
the corresponding translated code. */
tb_invalidate_phys_page(address, pc, puc);
#ifdef DEBUG_TB_CHECK
tb_invalidate_check(address);
#endif
mmap_unlock();
return 1;
}
}
mmap_unlock();
return 0;
}
static inline void tlb_set_dirty(CPUState *env,
unsigned long addr, target_ulong vaddr)
{
}
#endif /* defined(CONFIG_USER_ONLY) */
#if !defined(CONFIG_USER_ONLY)
static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
ram_addr_t memory);
static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
ram_addr_t orig_memory);
#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
need_subpage) \
do { \
if (addr > start_addr) \
start_addr2 = 0; \
else { \
start_addr2 = start_addr & ~TARGET_PAGE_MASK; \
if (start_addr2 > 0) \
need_subpage = 1; \
} \
\
if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE) \
end_addr2 = TARGET_PAGE_SIZE - 1; \
else { \
end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
if (end_addr2 < TARGET_PAGE_SIZE - 1) \
need_subpage = 1; \
} \
} while (0)
/* register physical memory. 'size' must be a multiple of the target
page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
io memory page */
void cpu_register_physical_memory(target_phys_addr_t start_addr,
unsigned long size,
unsigned long phys_offset)
{
target_phys_addr_t addr, end_addr;
PhysPageDesc *p;
CPUState *env;
ram_addr_t orig_size = size;
void *subpage;
#ifdef USE_KQEMU
/* XXX: should not depend on cpu context */
env = first_cpu;
if (env->kqemu_enabled) {
kqemu_set_phys_mem(start_addr, size, phys_offset);
}
#endif
size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
end_addr = start_addr + (target_phys_addr_t)size;
for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
ram_addr_t orig_memory = p->phys_offset;
target_phys_addr_t start_addr2, end_addr2;
int need_subpage = 0;
CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
need_subpage);
if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
if (!(orig_memory & IO_MEM_SUBPAGE)) {
subpage = subpage_init((addr & TARGET_PAGE_MASK),
&p->phys_offset, orig_memory);
} else {
subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
>> IO_MEM_SHIFT];
}
subpage_register(subpage, start_addr2, end_addr2, phys_offset);
} else {
p->phys_offset = phys_offset;
#if !defined(VBOX) || defined(VBOX_WITH_NEW_PHYS_CODE)
if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
(phys_offset & IO_MEM_ROMD))
#else
if ( (phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM
|| (phys_offset & IO_MEM_ROMD)
|| (phys_offset & ~TARGET_PAGE_MASK) == IO_MEM_RAM_MISSING)
#endif
phys_offset += TARGET_PAGE_SIZE;
}
} else {
p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
p->phys_offset = phys_offset;
#if !defined(VBOX) || defined(VBOX_WITH_NEW_PHYS_CODE)
if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
(phys_offset & IO_MEM_ROMD))
#else
if ( (phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM
|| (phys_offset & IO_MEM_ROMD)
|| (phys_offset & ~TARGET_PAGE_MASK) == IO_MEM_RAM_MISSING)
#endif
phys_offset += TARGET_PAGE_SIZE;
else {
target_phys_addr_t start_addr2, end_addr2;
int need_subpage = 0;
CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
end_addr2, need_subpage);
if (need_subpage || phys_offset & IO_MEM_SUBWIDTH) {
subpage = subpage_init((addr & TARGET_PAGE_MASK),
&p->phys_offset, IO_MEM_UNASSIGNED);
subpage_register(subpage, start_addr2, end_addr2,
phys_offset);
}
}
}
}
/* since each CPU stores ram addresses in its TLB cache, we must
reset the modified entries */
/* XXX: slow ! */
for(env = first_cpu; env != NULL; env = env->next_cpu) {
tlb_flush(env, 1);
}
}
/* XXX: temporary until new memory mapping API */
uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr)
{
PhysPageDesc *p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!p)
return IO_MEM_UNASSIGNED;
return p->phys_offset;
}
#ifndef VBOX
/* XXX: better than nothing */
ram_addr_t qemu_ram_alloc(ram_addr_t size)
{
ram_addr_t addr;
if ((phys_ram_alloc_offset + size) > phys_ram_size) {
fprintf(stderr, "Not enough memory (requested_size = %" PRIu64 ", max memory = %" PRIu64 ")\n",
(uint64_t)size, (uint64_t)phys_ram_size);
abort();
}
addr = phys_ram_alloc_offset;
phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
return addr;
}
void qemu_ram_free(ram_addr_t addr)
{
}
#endif
static uint32_t unassigned_mem_readb(void *opaque, target_phys_addr_t addr)
{
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read 0x%08x\n", (int)addr);
#endif
#if defined(TARGET_SPARC) || defined(TARGET_CRIS)
do_unassigned_access(addr, 0, 0, 0, 1);
#endif
return 0;
}
static uint32_t unassigned_mem_readw(void *opaque, target_phys_addr_t addr)
{
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
#endif
#if defined(TARGET_SPARC) || defined(TARGET_CRIS)
do_unassigned_access(addr, 0, 0, 0, 2);
#endif
return 0;
}
static uint32_t unassigned_mem_readl(void *opaque, target_phys_addr_t addr)
{
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem read " TARGET_FMT_plx "\n", addr);
#endif
#if defined(TARGET_SPARC) || defined(TARGET_CRIS)
do_unassigned_access(addr, 0, 0, 0, 4);
#endif
return 0;
}
static void unassigned_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);
#endif
}
static void unassigned_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
#endif
#if defined(TARGET_SPARC) || defined(TARGET_CRIS)
do_unassigned_access(addr, 1, 0, 0, 2);
#endif
}
static void unassigned_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write " TARGET_FMT_plx " = 0x%x\n", addr, val);
#endif
#if defined(TARGET_SPARC) || defined(TARGET_CRIS)
do_unassigned_access(addr, 1, 0, 0, 4);
#endif
}
static CPUReadMemoryFunc *unassigned_mem_read[3] = {
unassigned_mem_readb,
unassigned_mem_readw,
unassigned_mem_readl,
};
static CPUWriteMemoryFunc *unassigned_mem_write[3] = {
unassigned_mem_writeb,
unassigned_mem_writew,
unassigned_mem_writel,
};
static void notdirty_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
{
unsigned long ram_addr;
int dirty_flags;
#if defined(VBOX)
ram_addr = addr;
#elif
ram_addr = addr - (unsigned long)phys_ram_base;
#endif
#ifdef VBOX
if (RT_UNLIKELY((ram_addr >> TARGET_PAGE_BITS) >= phys_ram_dirty_size))
dirty_flags = 0xff;
else
#endif /* VBOX */
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
if (!(dirty_flags & CODE_DIRTY_FLAG)) {
#if !defined(CONFIG_USER_ONLY)
tb_invalidate_phys_page_fast(ram_addr, 1);
# ifdef VBOX
if (RT_UNLIKELY((ram_addr >> TARGET_PAGE_BITS) >= phys_ram_dirty_size))
dirty_flags = 0xff;
else
# endif /* VBOX */
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
#endif
}
#if defined(VBOX) && !defined(REM_PHYS_ADDR_IN_TLB)
remR3PhysWriteU8(addr, val);
#else
stb_p((uint8_t *)(long)addr, val);
#endif
#ifdef USE_KQEMU
if (cpu_single_env->kqemu_enabled &&
(dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
kqemu_modify_page(cpu_single_env, ram_addr);
#endif
dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
#ifdef VBOX
if (RT_LIKELY((ram_addr >> TARGET_PAGE_BITS) < phys_ram_dirty_size))
#endif /* !VBOX */
phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
/* we remove the notdirty callback only if the code has been
flushed */
if (dirty_flags == 0xff)
tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_io_vaddr);
}
static void notdirty_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
unsigned long ram_addr;
int dirty_flags;
#if defined(VBOX)
ram_addr = addr;
#else
ram_addr = addr - (unsigned long)phys_ram_base;
#endif
#ifdef VBOX
if (RT_UNLIKELY((ram_addr >> TARGET_PAGE_BITS) >= phys_ram_dirty_size))
dirty_flags = 0xff;
else
#endif /* VBOX */
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
if (!(dirty_flags & CODE_DIRTY_FLAG)) {
#if !defined(CONFIG_USER_ONLY)
tb_invalidate_phys_page_fast(ram_addr, 2);
# ifdef VBOX
if (RT_UNLIKELY((ram_addr >> TARGET_PAGE_BITS) >= phys_ram_dirty_size))
dirty_flags = 0xff;
else
# endif /* VBOX */
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
#endif
}
#if defined(VBOX) && !defined(REM_PHYS_ADDR_IN_TLB)
remR3PhysWriteU16(addr, val);
#else
stw_p((uint8_t *)(long)addr, val);
#endif
#ifdef USE_KQEMU
if (cpu_single_env->kqemu_enabled &&
(dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
kqemu_modify_page(cpu_single_env, ram_addr);
#endif
dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
#ifdef VBOX
if (RT_LIKELY((ram_addr >> TARGET_PAGE_BITS) < phys_ram_dirty_size))
#endif
phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
/* we remove the notdirty callback only if the code has been
flushed */
if (dirty_flags == 0xff)
tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_io_vaddr);
}
static void notdirty_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
unsigned long ram_addr;
int dirty_flags;
#if defined(VBOX)
ram_addr = addr;
#else
ram_addr = addr - (unsigned long)phys_ram_base;
#endif
#ifdef VBOX
if (RT_UNLIKELY((ram_addr >> TARGET_PAGE_BITS) >= phys_ram_dirty_size))
dirty_flags = 0xff;
else
#endif /* VBOX */
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
if (!(dirty_flags & CODE_DIRTY_FLAG)) {
#if !defined(CONFIG_USER_ONLY)
tb_invalidate_phys_page_fast(ram_addr, 4);
# ifdef VBOX
if (RT_UNLIKELY((ram_addr >> TARGET_PAGE_BITS) >= phys_ram_dirty_size))
dirty_flags = 0xff;
else
# endif /* VBOX */
dirty_flags = phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS];
#endif
}
#if defined(VBOX) && !defined(REM_PHYS_ADDR_IN_TLB)
remR3PhysWriteU32(addr, val);
#else
stl_p((uint8_t *)(long)addr, val);
#endif
#ifdef USE_KQEMU
if (cpu_single_env->kqemu_enabled &&
(dirty_flags & KQEMU_MODIFY_PAGE_MASK) != KQEMU_MODIFY_PAGE_MASK)
kqemu_modify_page(cpu_single_env, ram_addr);
#endif
dirty_flags |= (0xff & ~CODE_DIRTY_FLAG);
#ifdef VBOX
if (RT_LIKELY((ram_addr >> TARGET_PAGE_BITS) < phys_ram_dirty_size))
#endif
phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] = dirty_flags;
/* we remove the notdirty callback only if the code has been
flushed */
if (dirty_flags == 0xff)
tlb_set_dirty(cpu_single_env, addr, cpu_single_env->mem_io_vaddr);
}
static CPUReadMemoryFunc *error_mem_read[3] = {
NULL, /* never used */
NULL, /* never used */
NULL, /* never used */
};
static CPUWriteMemoryFunc *notdirty_mem_write[3] = {
notdirty_mem_writeb,
notdirty_mem_writew,
notdirty_mem_writel,
};
/* Generate a debug exception if a watchpoint has been hit. */
static void check_watchpoint(int offset, int flags)
{
CPUState *env = cpu_single_env;
target_ulong vaddr;
int i;
vaddr = (env->mem_io_vaddr & TARGET_PAGE_MASK) + offset;
for (i = 0; i < env->nb_watchpoints; i++) {
if (vaddr == env->watchpoint[i].vaddr
&& (env->watchpoint[i].type & flags)) {
env->watchpoint_hit = i + 1;
cpu_interrupt(env, CPU_INTERRUPT_DEBUG);
break;
}
}
}
/* Watchpoint access routines. Watchpoints are inserted using TLB tricks,
so these check for a hit then pass through to the normal out-of-line
phys routines. */
static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
{
check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
return ldub_phys(addr);
}
static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
{
check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
return lduw_phys(addr);
}
static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
{
check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_READ);
return ldl_phys(addr);
}
static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
stb_phys(addr, val);
}
static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
stw_phys(addr, val);
}
static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
check_watchpoint(addr & ~TARGET_PAGE_MASK, PAGE_WRITE);
stl_phys(addr, val);
}
static CPUReadMemoryFunc *watch_mem_read[3] = {
watch_mem_readb,
watch_mem_readw,
watch_mem_readl,
};
static CPUWriteMemoryFunc *watch_mem_write[3] = {
watch_mem_writeb,
watch_mem_writew,
watch_mem_writel,
};
static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
unsigned int len)
{
uint32_t ret;
unsigned int idx;
idx = SUBPAGE_IDX(addr - mmio->base);
#if defined(DEBUG_SUBPAGE)
printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
mmio, len, addr, idx);
#endif
ret = (**mmio->mem_read[idx][len])(mmio->opaque[idx][0][len], addr);
return ret;
}
static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
uint32_t value, unsigned int len)
{
unsigned int idx;
idx = SUBPAGE_IDX(addr - mmio->base);
#if defined(DEBUG_SUBPAGE)
printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
mmio, len, addr, idx, value);
#endif
(**mmio->mem_write[idx][len])(mmio->opaque[idx][1][len], addr, value);
}
static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
{
#if defined(DEBUG_SUBPAGE)
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
return subpage_readlen(opaque, addr, 0);
}
static void subpage_writeb (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
#if defined(DEBUG_SUBPAGE)
printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
#endif
subpage_writelen(opaque, addr, value, 0);
}
static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
{
#if defined(DEBUG_SUBPAGE)
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
return subpage_readlen(opaque, addr, 1);
}
static void subpage_writew (void *opaque, target_phys_addr_t addr,
uint32_t value)
{
#if defined(DEBUG_SUBPAGE)
printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
#endif
subpage_writelen(opaque, addr, value, 1);
}
static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
{
#if defined(DEBUG_SUBPAGE)
printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
#endif
return subpage_readlen(opaque, addr, 2);
}
static void subpage_writel (void *opaque,
target_phys_addr_t addr, uint32_t value)
{
#if defined(DEBUG_SUBPAGE)
printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
#endif
subpage_writelen(opaque, addr, value, 2);
}
static CPUReadMemoryFunc *subpage_read[] = {
&subpage_readb,
&subpage_readw,
&subpage_readl,
};
static CPUWriteMemoryFunc *subpage_write[] = {
&subpage_writeb,
&subpage_writew,
&subpage_writel,
};
static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
ram_addr_t memory)
{
int idx, eidx;
unsigned int i;
if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
return -1;
idx = SUBPAGE_IDX(start);
eidx = SUBPAGE_IDX(end);
#if defined(DEBUG_SUBPAGE)
printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
mmio, start, end, idx, eidx, memory);
#endif
memory >>= IO_MEM_SHIFT;
for (; idx <= eidx; idx++) {
for (i = 0; i < 4; i++) {
if (io_mem_read[memory][i]) {
mmio->mem_read[idx][i] = &io_mem_read[memory][i];
mmio->opaque[idx][0][i] = io_mem_opaque[memory];
}
if (io_mem_write[memory][i]) {
mmio->mem_write[idx][i] = &io_mem_write[memory][i];
mmio->opaque[idx][1][i] = io_mem_opaque[memory];
}
}
}
return 0;
}
static void *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
ram_addr_t orig_memory)
{
subpage_t *mmio;
int subpage_memory;
mmio = qemu_mallocz(sizeof(subpage_t));
if (mmio != NULL) {
mmio->base = base;
subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
#if defined(DEBUG_SUBPAGE)
printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
mmio, base, TARGET_PAGE_SIZE, subpage_memory);
#endif
*phys = subpage_memory | IO_MEM_SUBPAGE;
subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
}
return mmio;
}
static void io_mem_init(void)
{
cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
cpu_register_io_memory(IO_MEM_UNASSIGNED >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
#if defined(VBOX) && !defined(VBOX_WITH_NEW_PHYS_CODE)
cpu_register_io_memory(IO_MEM_RAM_MISSING >> IO_MEM_SHIFT, unassigned_mem_read, unassigned_mem_write, NULL);
io_mem_nb = 6;
#else
io_mem_nb = 5;
#endif
io_mem_watch = cpu_register_io_memory(0, watch_mem_read,
watch_mem_write, NULL);
#ifndef VBOX /* VBOX: we do this later when the RAM is allocated. */
/* alloc dirty bits array */
phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
#endif /* !VBOX */
}
/* mem_read and mem_write are arrays of functions containing the
function to access byte (index 0), word (index 1) and dword (index
2). Functions can be omitted with a NULL function pointer. The
registered functions may be modified dynamically later.
If io_index is non zero, the corresponding io zone is
modified. If it is zero, a new io zone is allocated. The return
value can be used with cpu_register_physical_memory(). (-1) is
returned if error. */
int cpu_register_io_memory(int io_index,
CPUReadMemoryFunc **mem_read,
CPUWriteMemoryFunc **mem_write,
void *opaque)
{
int i, subwidth = 0;
if (io_index <= 0) {
if (io_mem_nb >= IO_MEM_NB_ENTRIES)
return -1;
io_index = io_mem_nb++;
} else {
if (io_index >= IO_MEM_NB_ENTRIES)
return -1;
}
for(i = 0;i < 3; i++) {
if (!mem_read[i] || !mem_write[i])
subwidth = IO_MEM_SUBWIDTH;
io_mem_read[io_index][i] = mem_read[i];
io_mem_write[io_index][i] = mem_write[i];
}
io_mem_opaque[io_index] = opaque;
return (io_index << IO_MEM_SHIFT) | subwidth;
}
CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index)
{
return io_mem_write[io_index >> IO_MEM_SHIFT];
}
CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index)
{
return io_mem_read[io_index >> IO_MEM_SHIFT];
}
#endif /* !defined(CONFIG_USER_ONLY) */
/* physical memory access (slow version, mainly for debug) */
#if defined(CONFIG_USER_ONLY)
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
int len, int is_write)
{
int l, flags;
target_ulong page;
void * p;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len)
l = len;
flags = page_get_flags(page);
if (!(flags & PAGE_VALID))
return;
if (is_write) {
if (!(flags & PAGE_WRITE))
return;
/* XXX: this code should not depend on lock_user */
if (!(p = lock_user(VERIFY_WRITE, addr, l, 0)))
/* FIXME - should this return an error rather than just fail? */
return;
memcpy(p, buf, len);
unlock_user(p, addr, len);
} else {
if (!(flags & PAGE_READ))
return;
if (!(p = lock_user(VERIFY_READ, addr, l, 1)))
/* FIXME - should this return an error rather than just fail? */
return;
memcpy(buf, p, len);
unlock_user(p, addr, 0);
}
len -= l;
buf += l;
addr += l;
}
}
#else
void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
int len, int is_write)
{
int l, io_index;
uint8_t *ptr;
uint32_t val;
target_phys_addr_t page;
unsigned long pd;
PhysPageDesc *p;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len)
l = len;
p = phys_page_find(page >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
} else {
pd = p->phys_offset;
}
if (is_write) {
if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
/* XXX: could force cpu_single_env to NULL to avoid
potential bugs */
if (l >= 4 && ((addr & 3) == 0)) {
/* 32 bit write access */
#if !defined(VBOX) || !defined(REM_PHYS_ADDR_IN_TLB)
val = ldl_p(buf);
#else
val = *(const uint32_t *)buf;
#endif
io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
l = 4;
} else if (l >= 2 && ((addr & 1) == 0)) {
/* 16 bit write access */
#if !defined(VBOX) || !defined(REM_PHYS_ADDR_IN_TLB)
val = lduw_p(buf);
#else
val = *(const uint16_t *)buf;
#endif
io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
l = 2;
} else {
/* 8 bit write access */
#if !defined(VBOX) || !defined(REM_PHYS_ADDR_IN_TLB)
val = ldub_p(buf);
#else
val = *(const uint8_t *)buf;
#endif
io_mem_write[io_index][0](io_mem_opaque[io_index], addr, val);
l = 1;
}
} else {
unsigned long addr1;
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
/* RAM case */
#ifdef VBOX
remR3PhysWrite(addr1, buf, l); NOREF(ptr);
#else
ptr = phys_ram_base + addr1;
memcpy(ptr, buf, l);
#endif
if (!cpu_physical_memory_is_dirty(addr1)) {
/* invalidate code */
tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
/* set dirty bit */
#ifdef VBOX
if (RT_LIKELY((addr1 >> TARGET_PAGE_BITS) < phys_ram_dirty_size))
#endif
phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
(0xff & ~CODE_DIRTY_FLAG);
}
}
} else {
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
!(pd & IO_MEM_ROMD)) {
/* I/O case */
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
if (l >= 4 && ((addr & 3) == 0)) {
/* 32 bit read access */
val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
#if !defined(VBOX) || !defined(REM_PHYS_ADDR_IN_TLB)
stl_p(buf, val);
#else
*(uint32_t *)buf = val;
#endif
l = 4;
} else if (l >= 2 && ((addr & 1) == 0)) {
/* 16 bit read access */
val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
#if !defined(VBOX) || !defined(REM_PHYS_ADDR_IN_TLB)
stw_p(buf, val);
#else
*(uint16_t *)buf = val;
#endif
l = 2;
} else {
/* 8 bit read access */
val = io_mem_read[io_index][0](io_mem_opaque[io_index], addr);
#if !defined(VBOX) || !defined(REM_PHYS_ADDR_IN_TLB)
stb_p(buf, val);
#else
*(uint8_t *)buf = val;
#endif
l = 1;
}
} else {
/* RAM case */
#ifdef VBOX
remR3PhysRead((pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK), buf, l); NOREF(ptr);
#else
ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
(addr & ~TARGET_PAGE_MASK);
memcpy(buf, ptr, l);
#endif
}
}
len -= l;
buf += l;
addr += l;
}
}
#ifndef VBOX
/* used for ROM loading : can write in RAM and ROM */
void cpu_physical_memory_write_rom(target_phys_addr_t addr,
const uint8_t *buf, int len)
{
int l;
uint8_t *ptr;
target_phys_addr_t page;
unsigned long pd;
PhysPageDesc *p;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len)
l = len;
p = phys_page_find(page >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
} else {
pd = p->phys_offset;
}
if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
(pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
!(pd & IO_MEM_ROMD)) {
/* do nothing */
} else {
unsigned long addr1;
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
/* ROM/RAM case */
ptr = phys_ram_base + addr1;
memcpy(ptr, buf, l);
}
len -= l;
buf += l;
addr += l;
}
}
#endif /* !VBOX */
/* warning: addr must be aligned */
uint32_t ldl_phys(target_phys_addr_t addr)
{
int io_index;
uint8_t *ptr;
uint32_t val;
unsigned long pd;
PhysPageDesc *p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
} else {
pd = p->phys_offset;
}
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
!(pd & IO_MEM_ROMD)) {
/* I/O case */
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
} else {
/* RAM case */
#ifndef VBOX
ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
(addr & ~TARGET_PAGE_MASK);
val = ldl_p(ptr);
#else
val = remR3PhysReadU32((pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK)); NOREF(ptr);
#endif
}
return val;
}
/* warning: addr must be aligned */
uint64_t ldq_phys(target_phys_addr_t addr)
{
int io_index;
uint8_t *ptr;
uint64_t val;
unsigned long pd;
PhysPageDesc *p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
} else {
pd = p->phys_offset;
}
if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
!(pd & IO_MEM_ROMD)) {
/* I/O case */
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
#ifdef TARGET_WORDS_BIGENDIAN
val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
#else
val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
val |= (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4) << 32;
#endif
} else {
/* RAM case */
#ifndef VBOX
ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
(addr & ~TARGET_PAGE_MASK);
val = ldq_p(ptr);
#else
val = remR3PhysReadU64((pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK)); NOREF(ptr);
#endif
}
return val;
}
/* XXX: optimize */
uint32_t ldub_phys(target_phys_addr_t addr)
{
uint8_t val;
cpu_physical_memory_read(addr, &val, 1);
return val;
}
/* XXX: optimize */
uint32_t lduw_phys(target_phys_addr_t addr)
{
uint16_t val;
cpu_physical_memory_read(addr, (uint8_t *)&val, 2);
return tswap16(val);
}
/* warning: addr must be aligned. The ram page is not masked as dirty
and the code inside is not invalidated. It is useful if the dirty
bits are used to track modified PTEs */
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val)
{
int io_index;
uint8_t *ptr;
unsigned long pd;
PhysPageDesc *p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
} else {
pd = p->phys_offset;
}
if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
} else {
#ifndef VBOX
ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
(addr & ~TARGET_PAGE_MASK);
stl_p(ptr, val);
#else
remR3PhysWriteU32((pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK), val); NOREF(ptr);
#endif
#ifndef VBOX
if (unlikely(in_migration)) {
if (!cpu_physical_memory_is_dirty(addr1)) {
/* invalidate code */
tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
/* set dirty bit */
phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
(0xff & ~CODE_DIRTY_FLAG);
}
}
#endif
}
}
void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
{
int io_index;
uint8_t *ptr;
unsigned long pd;
PhysPageDesc *p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
} else {
pd = p->phys_offset;
}
if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
#ifdef TARGET_WORDS_BIGENDIAN
io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
#else
io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
#endif
} else {
#ifndef VBOX
ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
(addr & ~TARGET_PAGE_MASK);
stq_p(ptr, val);
#else
remR3PhysWriteU64((pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK), val); NOREF(ptr);
#endif
}
}
/* warning: addr must be aligned */
void stl_phys(target_phys_addr_t addr, uint32_t val)
{
int io_index;
uint8_t *ptr;
unsigned long pd;
PhysPageDesc *p;
p = phys_page_find(addr >> TARGET_PAGE_BITS);
if (!p) {
pd = IO_MEM_UNASSIGNED;
} else {
pd = p->phys_offset;
}
if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
} else {
unsigned long addr1;
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
/* RAM case */
#ifndef VBOX
ptr = phys_ram_base + addr1;
stl_p(ptr, val);
#else
remR3PhysWriteU32((pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK), val); NOREF(ptr);
#endif
if (!cpu_physical_memory_is_dirty(addr1)) {
/* invalidate code */
tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
/* set dirty bit */
#ifdef VBOX
if (RT_LIKELY((addr1 >> TARGET_PAGE_BITS) < phys_ram_dirty_size))
#endif
phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
(0xff & ~CODE_DIRTY_FLAG);
}
}
}
/* XXX: optimize */
void stb_phys(target_phys_addr_t addr, uint32_t val)
{
uint8_t v = val;
cpu_physical_memory_write(addr, &v, 1);
}
/* XXX: optimize */
void stw_phys(target_phys_addr_t addr, uint32_t val)
{
uint16_t v = tswap16(val);
cpu_physical_memory_write(addr, (const uint8_t *)&v, 2);
}
/* XXX: optimize */
void stq_phys(target_phys_addr_t addr, uint64_t val)
{
val = tswap64(val);
cpu_physical_memory_write(addr, (const uint8_t *)&val, 8);
}
#endif
/* virtual memory access for debug */
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
uint8_t *buf, int len, int is_write)
{
int l;
target_ulong page, phys_addr;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
phys_addr = cpu_get_phys_page_debug(env, page);
/* if no physical page mapped, return an error */
if (phys_addr == -1)
return -1;
l = (page + TARGET_PAGE_SIZE) - addr;
if (l > len)
l = len;
cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
buf, l, is_write);
len -= l;
buf += l;
addr += l;
}
return 0;
}
/* in deterministic execution mode, instructions doing device I/Os
must be at the end of the TB */
void cpu_io_recompile(CPUState *env, void *retaddr)
{
TranslationBlock *tb;
uint32_t n, cflags;
target_ulong pc, cs_base;
uint64_t flags;
tb = tb_find_pc((unsigned long)retaddr);
if (!tb) {
cpu_abort(env, "cpu_io_recompile: could not find TB for pc=%p",
retaddr);
}
n = env->icount_decr.u16.low + tb->icount;
cpu_restore_state(tb, env, (unsigned long)retaddr, NULL);
/* Calculate how many instructions had been executed before the fault
occurred. */
n = n - env->icount_decr.u16.low;
/* Generate a new TB ending on the I/O insn. */
n++;
/* On MIPS and SH, delay slot instructions can only be restarted if
they were already the first instruction in the TB. If this is not
the first instruction in a TB then re-execute the preceding
branch. */
#if defined(TARGET_MIPS)
if ((env->hflags & MIPS_HFLAG_BMASK) != 0 && n > 1) {
env->active_tc.PC -= 4;
env->icount_decr.u16.low++;
env->hflags &= ~MIPS_HFLAG_BMASK;
}
#elif defined(TARGET_SH4)
if ((env->flags & ((DELAY_SLOT | DELAY_SLOT_CONDITIONAL))) != 0
&& n > 1) {
env->pc -= 2;
env->icount_decr.u16.low++;
env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
}
#endif
/* This should never happen. */
if (n > CF_COUNT_MASK)
cpu_abort(env, "TB too big during recompile");
cflags = n | CF_LAST_IO;
pc = tb->pc;
cs_base = tb->cs_base;
flags = tb->flags;
tb_phys_invalidate(tb, -1);
/* FIXME: In theory this could raise an exception. In practice
we have already translated the block once so it's probably ok. */
tb_gen_code(env, pc, cs_base, flags, cflags);
/* TODO: If env->pc != tb->pc (i.e. the faulting instruction was not
the first in the TB) then we end up generating a whole new TB and
repeating the fault, which is horribly inefficient.
Better would be to execute just this insn uncached, or generate a
second new TB. */
cpu_resume_from_signal(env, NULL);
}
#ifndef VBOX
void dump_exec_info(FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
{
int i, target_code_size, max_target_code_size;
int direct_jmp_count, direct_jmp2_count, cross_page;
TranslationBlock *tb;
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++) {
tb = &tbs[i];
target_code_size += tb->size;
if (tb->size > max_target_code_size)
max_target_code_size = tb->size;
if (tb->page_addr[1] != -1)
cross_page++;
if (tb->tb_next_offset[0] != 0xffff) {
direct_jmp_count++;
if (tb->tb_next_offset[1] != 0xffff) {
direct_jmp2_count++;
}
}
}
/* XXX: avoid using doubles ? */
cpu_fprintf(f, "Translation buffer state:\n");
cpu_fprintf(f, "gen code size %ld/%ld\n",
code_gen_ptr - code_gen_buffer, code_gen_buffer_max_size);
cpu_fprintf(f, "TB count %d/%d\n",
nb_tbs, code_gen_max_blocks);
cpu_fprintf(f, "TB avg target size %d max=%d bytes\n",
nb_tbs ? target_code_size / nb_tbs : 0,
max_target_code_size);
cpu_fprintf(f, "TB avg host size %d bytes (expansion ratio: %0.1f)\n",
nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
cross_page,
nb_tbs ? (cross_page * 100) / nb_tbs : 0);
cpu_fprintf(f, "direct jump count %d (%d%%) (2 jumps=%d %d%%)\n",
direct_jmp_count,
nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
direct_jmp2_count,
nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
cpu_fprintf(f, "\nStatistics:\n");
cpu_fprintf(f, "TB flush count %d\n", tb_flush_count);
cpu_fprintf(f, "TB invalidate count %d\n", tb_phys_invalidate_count);
cpu_fprintf(f, "TLB flush count %d\n", tlb_flush_count);
tcg_dump_info(f, cpu_fprintf);
}
#endif /* !VBOX */
#if !defined(CONFIG_USER_ONLY)
#define MMUSUFFIX _cmmu
#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"
#define SHIFT 3
#include "softmmu_template.h"
#undef env
#endif