X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=exec-all.h;h=f91e6460c34230dba7864aad0f810b322dce7b97;hb=ade406775d3795141927bdd581edee2cb44da864;hp=d98b91d3f3573caf17a45e1e6b1fd4de3e09d614;hpb=d2856f1ad4c259e5766847c49acbb4e390731bd4;p=qemu diff --git a/exec-all.h b/exec-all.h index d98b91d..f91e646 100644 --- a/exec-all.h +++ b/exec-all.h @@ -15,9 +15,14 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA */ +#ifndef _EXEC_ALL_H_ +#define _EXEC_ALL_H_ + +#include "qemu-common.h" + /* allow to see translation results - the slowdown should be negligible, so we leave it */ #define DEBUG_DISAS @@ -27,10 +32,10 @@ #define DISAS_UPDATE 2 /* cpu state was modified dynamically */ #define DISAS_TB_JUMP 3 /* only pc was modified statically */ -struct TranslationBlock; +typedef struct TranslationBlock TranslationBlock; /* XXX: make safe guess about sizes */ -#define MAX_OP_PER_INSTR 32 +#define MAX_OP_PER_INSTR 64 /* A Call op needs up to 6 + 2N parameters (N = number of arguments). */ #define MAX_OPC_PARAM 10 #define OPC_BUF_SIZE 512 @@ -48,25 +53,14 @@ extern target_ulong gen_opc_pc[OPC_BUF_SIZE]; extern target_ulong gen_opc_npc[OPC_BUF_SIZE]; extern uint8_t gen_opc_cc_op[OPC_BUF_SIZE]; extern uint8_t gen_opc_instr_start[OPC_BUF_SIZE]; +extern uint16_t gen_opc_icount[OPC_BUF_SIZE]; extern target_ulong gen_opc_jump_pc[2]; extern uint32_t gen_opc_hflags[OPC_BUF_SIZE]; -typedef void (GenOpFunc)(void); -typedef void (GenOpFunc1)(long); -typedef void (GenOpFunc2)(long, long); -typedef void (GenOpFunc3)(long, long, long); - -#if defined(TARGET_I386) - -void optimize_flags_init(void); +#include "qemu-log.h" -#endif - -extern FILE *logfile; -extern int loglevel; - -int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); -int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); +void gen_intermediate_code(CPUState *env, struct TranslationBlock *tb); +void gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb); void gen_pc_load(CPUState *env, struct TranslationBlock *tb, unsigned long searched_pc, int pc_pos, void *puc); @@ -77,13 +71,16 @@ int cpu_gen_code(CPUState *env, struct TranslationBlock *tb, int cpu_restore_state(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc); -int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb, - int max_code_size, int *gen_code_size_ptr); int cpu_restore_state_copy(struct TranslationBlock *tb, CPUState *env, unsigned long searched_pc, void *puc); void cpu_resume_from_signal(CPUState *env1, void *puc); +void cpu_io_recompile(CPUState *env, void *retaddr); +TranslationBlock *tb_gen_code(CPUState *env, + target_ulong pc, target_ulong cs_base, int flags, + int cflags); void cpu_exec_init(CPUState *env); +void QEMU_NORETURN cpu_loop_exit(void); int page_unprotect(target_ulong address, unsigned long pc, void *puc); void tb_invalidate_phys_page_range(target_phys_addr_t start, target_phys_addr_t end, int is_cpu_write_access); @@ -93,13 +90,13 @@ void tlb_flush(CPUState *env, int flush_global); int tlb_set_page_exec(CPUState *env, target_ulong vaddr, target_phys_addr_t paddr, int prot, int mmu_idx, int is_softmmu); -static inline int tlb_set_page(CPUState *env, target_ulong vaddr, +static inline int tlb_set_page(CPUState *env1, target_ulong vaddr, target_phys_addr_t paddr, int prot, int mmu_idx, int is_softmmu) { if (prot & PAGE_READ) prot |= PAGE_EXEC; - return tlb_set_page_exec(env, vaddr, paddr, prot, mmu_idx, is_softmmu); + return tlb_set_page_exec(env1, vaddr, paddr, prot, mmu_idx, is_softmmu); } #define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ @@ -107,31 +104,7 @@ static inline int tlb_set_page(CPUState *env, target_ulong vaddr, #define CODE_GEN_PHYS_HASH_BITS 15 #define CODE_GEN_PHYS_HASH_SIZE (1 << CODE_GEN_PHYS_HASH_BITS) -/* maximum total translate dcode allocated */ - -/* NOTE: the translated code area cannot be too big because on some - archs the range of "fast" function calls is limited. Here is a - summary of the ranges: - - i386 : signed 32 bits - arm : signed 26 bits - ppc : signed 24 bits - sparc : signed 32 bits - alpha : signed 23 bits -*/ - -#if defined(__alpha__) -#define CODE_GEN_BUFFER_SIZE (2 * 1024 * 1024) -#elif defined(__ia64) -#define CODE_GEN_BUFFER_SIZE (4 * 1024 * 1024) /* range of addl */ -#elif defined(__powerpc__) -#define CODE_GEN_BUFFER_SIZE (6 * 1024 * 1024) -#else -/* XXX: make it dynamic on x86 */ -#define CODE_GEN_BUFFER_SIZE (16 * 1024 * 1024) -#endif - -//#define CODE_GEN_BUFFER_SIZE (128 * 1024) +#define MIN_CODE_GEN_BUFFER_SIZE (1024 * 1024) /* estimated block size for TB allocation */ /* XXX: use a per code average code fragment size and modulate it @@ -142,26 +115,22 @@ static inline int tlb_set_page(CPUState *env, target_ulong vaddr, #define CODE_GEN_AVG_BLOCK_SIZE 64 #endif -#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE) - -#if defined(__powerpc__) || defined(__x86_64__) +#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) #define USE_DIRECT_JUMP #endif #if defined(__i386__) && !defined(_WIN32) #define USE_DIRECT_JUMP #endif -typedef struct TranslationBlock { +struct TranslationBlock { target_ulong pc; /* simulated PC corresponding to this block (EIP + CS base) */ target_ulong cs_base; /* CS base for this block */ uint64_t flags; /* flags defining in which context the code was generated */ uint16_t size; /* size of target code for this block (1 <= size <= TARGET_PAGE_SIZE) */ uint16_t cflags; /* compile flags */ -#define CF_CODE_COPY 0x0001 /* block was generated in code copy mode */ -#define CF_TB_FP_USED 0x0002 /* fp ops are used in the TB */ -#define CF_FP_USED 0x0004 /* fp ops are used in the TB or in a chained TB */ -#define CF_SINGLE_INSN 0x0008 /* compile only a single instruction */ +#define CF_COUNT_MASK 0x7fff +#define CF_LAST_IO 0x8000 /* Last insn may be an IO access. */ uint8_t *tc_ptr; /* pointer to the translated code */ /* next matching tb for physical address. */ @@ -185,21 +154,22 @@ typedef struct TranslationBlock { jmp_first */ struct TranslationBlock *jmp_next[2]; struct TranslationBlock *jmp_first; -} TranslationBlock; + uint32_t icount; +}; static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc) { target_ulong tmp; tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); - return (tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK; + return (tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK; } static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc) { target_ulong tmp; tmp = pc ^ (pc >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)); - return (((tmp >> TB_JMP_PAGE_BITS) & TB_JMP_PAGE_MASK) | - (tmp & TB_JMP_ADDR_MASK)); + return (((tmp >> (TARGET_PAGE_BITS - TB_JMP_PAGE_BITS)) & TB_JMP_PAGE_MASK) + | (tmp & TB_JMP_ADDR_MASK)); } static inline unsigned int tb_phys_hash_func(unsigned long pc) @@ -208,40 +178,51 @@ static inline unsigned int tb_phys_hash_func(unsigned long pc) } TranslationBlock *tb_alloc(target_ulong pc); +void tb_free(TranslationBlock *tb); void tb_flush(CPUState *env); void tb_link_phys(TranslationBlock *tb, target_ulong phys_pc, target_ulong phys_page2); +void tb_phys_invalidate(TranslationBlock *tb, target_ulong page_addr); extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE]; - -extern uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; extern uint8_t *code_gen_ptr; +extern int code_gen_max_blocks; #if defined(USE_DIRECT_JUMP) -#if defined(__powerpc__) +#if defined(_ARCH_PPC) +extern void ppc_tb_set_jmp_target(unsigned long jmp_addr, unsigned long addr); +#define tb_set_jmp_target1 ppc_tb_set_jmp_target +#elif defined(__i386__) || defined(__x86_64__) static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) { - uint32_t val, *ptr; - /* patch the branch destination */ - ptr = (uint32_t *)jmp_addr; - val = *ptr; - val = (val & ~0x03fffffc) | ((addr - jmp_addr) & 0x03fffffc); - *ptr = val; - /* flush icache */ - asm volatile ("dcbst 0,%0" : : "r"(ptr) : "memory"); - asm volatile ("sync" : : : "memory"); - asm volatile ("icbi 0,%0" : : "r"(ptr) : "memory"); - asm volatile ("sync" : : : "memory"); - asm volatile ("isync" : : : "memory"); + *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); + /* no need to flush icache explicitly */ } -#elif defined(__i386__) || defined(__x86_64__) +#elif defined(__arm__) static inline void tb_set_jmp_target1(unsigned long jmp_addr, unsigned long addr) { - /* patch the branch destination */ - *(uint32_t *)jmp_addr = addr - (jmp_addr + 4); - /* no need to flush icache explicitely */ +#if QEMU_GNUC_PREREQ(4, 1) + void __clear_cache(char *beg, char *end); +#else + register unsigned long _beg __asm ("a1"); + register unsigned long _end __asm ("a2"); + register unsigned long _flg __asm ("a3"); +#endif + + /* we could use a ldr pc, [pc, #-4] kind of branch and avoid the flush */ + *(uint32_t *)jmp_addr |= ((addr - (jmp_addr + 8)) >> 2) & 0xffffff; + +#if QEMU_GNUC_PREREQ(4, 1) + __clear_cache((char *) jmp_addr, (char *) jmp_addr + 4); +#else + /* flush icache */ + _beg = jmp_addr; + _end = jmp_addr + 4; + _flg = 0; + __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); +#endif } #endif @@ -284,239 +265,11 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, TranslationBlock *tb_find_pc(unsigned long pc_ptr); -#ifndef offsetof -#define offsetof(type, field) ((size_t) &((type *)0)->field) -#endif - -#if defined(_WIN32) -#define ASM_DATA_SECTION ".section \".data\"\n" -#define ASM_PREVIOUS_SECTION ".section .text\n" -#elif defined(__APPLE__) -#define ASM_DATA_SECTION ".data\n" -#define ASM_PREVIOUS_SECTION ".text\n" -#else -#define ASM_DATA_SECTION ".section \".data\"\n" -#define ASM_PREVIOUS_SECTION ".previous\n" -#endif - -#define ASM_OP_LABEL_NAME(n, opname) \ - ASM_NAME(__op_label) #n "." ASM_NAME(opname) - extern CPUWriteMemoryFunc *io_mem_write[IO_MEM_NB_ENTRIES][4]; extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4]; extern void *io_mem_opaque[IO_MEM_NB_ENTRIES]; -#if defined(__hppa__) - -typedef int spinlock_t[4]; - -#define SPIN_LOCK_UNLOCKED { 1, 1, 1, 1 } - -static inline void resetlock (spinlock_t *p) -{ - (*p)[0] = (*p)[1] = (*p)[2] = (*p)[3] = 1; -} - -#else - -typedef int spinlock_t; - -#define SPIN_LOCK_UNLOCKED 0 - -static inline void resetlock (spinlock_t *p) -{ - *p = SPIN_LOCK_UNLOCKED; -} - -#endif - -#if defined(__powerpc__) -static inline int testandset (int *p) -{ - int ret; - __asm__ __volatile__ ( - "0: lwarx %0,0,%1\n" - " xor. %0,%3,%0\n" - " bne 1f\n" - " stwcx. %2,0,%1\n" - " bne- 0b\n" - "1: " - : "=&r" (ret) - : "r" (p), "r" (1), "r" (0) - : "cr0", "memory"); - return ret; -} -#elif defined(__i386__) -static inline int testandset (int *p) -{ - long int readval = 0; - - __asm__ __volatile__ ("lock; cmpxchgl %2, %0" - : "+m" (*p), "+a" (readval) - : "r" (1) - : "cc"); - return readval; -} -#elif defined(__x86_64__) -static inline int testandset (int *p) -{ - long int readval = 0; - - __asm__ __volatile__ ("lock; cmpxchgl %2, %0" - : "+m" (*p), "+a" (readval) - : "r" (1) - : "cc"); - return readval; -} -#elif defined(__s390__) -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__ ("0: cs %0,%1,0(%2)\n" - " jl 0b" - : "=&d" (ret) - : "r" (1), "a" (p), "0" (*p) - : "cc", "memory" ); - return ret; -} -#elif defined(__alpha__) -static inline int testandset (int *p) -{ - int ret; - unsigned long one; - - __asm__ __volatile__ ("0: mov 1,%2\n" - " ldl_l %0,%1\n" - " stl_c %2,%1\n" - " beq %2,1f\n" - ".subsection 2\n" - "1: br 0b\n" - ".previous" - : "=r" (ret), "=m" (*p), "=r" (one) - : "m" (*p)); - return ret; -} -#elif defined(__sparc__) -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__("ldstub [%1], %0" - : "=r" (ret) - : "r" (p) - : "memory"); - - return (ret ? 1 : 0); -} -#elif defined(__arm__) -static inline int testandset (int *spinlock) -{ - register unsigned int ret; - __asm__ __volatile__("swp %0, %1, [%2]" - : "=r"(ret) - : "0"(1), "r"(spinlock)); - - return ret; -} -#elif defined(__mc68000) -static inline int testandset (int *p) -{ - char ret; - __asm__ __volatile__("tas %1; sne %0" - : "=r" (ret) - : "m" (p) - : "cc","memory"); - return ret; -} -#elif defined(__hppa__) - -/* Because malloc only guarantees 8-byte alignment for malloc'd data, - and GCC only guarantees 8-byte alignment for stack locals, we can't - be assured of 16-byte alignment for atomic lock data even if we - specify "__attribute ((aligned(16)))" in the type declaration. So, - we use a struct containing an array of four ints for the atomic lock - type and dynamically select the 16-byte aligned int from the array - for the semaphore. */ -#define __PA_LDCW_ALIGNMENT 16 -static inline void *ldcw_align (void *p) { - unsigned long a = (unsigned long)p; - a = (a + __PA_LDCW_ALIGNMENT - 1) & ~(__PA_LDCW_ALIGNMENT - 1); - return (void *)a; -} - -static inline int testandset (spinlock_t *p) -{ - unsigned int ret; - p = ldcw_align(p); - __asm__ __volatile__("ldcw 0(%1),%0" - : "=r" (ret) - : "r" (p) - : "memory" ); - return !ret; -} - -#elif defined(__ia64) - -#include - -static inline int testandset (int *p) -{ - return __sync_lock_test_and_set (p, 1); -} -#elif defined(__mips__) -static inline int testandset (int *p) -{ - int ret; - - __asm__ __volatile__ ( - " .set push \n" - " .set noat \n" - " .set mips2 \n" - "1: li $1, 1 \n" - " ll %0, %1 \n" - " sc $1, %1 \n" - " beqz $1, 1b \n" - " .set pop " - : "=r" (ret), "+R" (*p) - : - : "memory"); - - return ret; -} -#else -#error unimplemented CPU support -#endif - -#if defined(CONFIG_USER_ONLY) -static inline void spin_lock(spinlock_t *lock) -{ - while (testandset(lock)); -} - -static inline void spin_unlock(spinlock_t *lock) -{ - resetlock(lock); -} - -static inline int spin_trylock(spinlock_t *lock) -{ - return !testandset(lock); -} -#else -static inline void spin_lock(spinlock_t *lock) -{ -} - -static inline void spin_unlock(spinlock_t *lock) -{ -} - -static inline int spin_trylock(spinlock_t *lock) -{ - return 1; -} -#endif +#include "qemu-lock.h" extern spinlock_t tb_lock; @@ -527,6 +280,8 @@ extern int tb_invalidated_flag; void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr); +#include "softmmu_defs.h" + #define ACCESS_TYPE (NB_MMU_MODES + 1) #define MEMSUFFIX _code #define env cpu_single_env @@ -550,7 +305,7 @@ void tlb_fill(target_ulong addr, int is_write, int mmu_idx, #endif #if defined(CONFIG_USER_ONLY) -static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) +static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) { return addr; } @@ -558,40 +313,66 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) /* NOTE: this function can trigger an exception */ /* NOTE2: the returned address is not exactly the physical address: it is the offset relative to phys_ram_base */ -static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr) +static inline target_ulong get_phys_addr_code(CPUState *env1, target_ulong addr) { - int mmu_idx, index, pd; + int mmu_idx, page_index, pd; + void *p; - index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); - mmu_idx = cpu_mmu_index(env); - if (__builtin_expect(env->tlb_table[mmu_idx][index].addr_code != - (addr & TARGET_PAGE_MASK), 0)) { + page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); + mmu_idx = cpu_mmu_index(env1); + if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code != + (addr & TARGET_PAGE_MASK))) { ldub_code(addr); } - pd = env->tlb_table[mmu_idx][index].addr_code & ~TARGET_PAGE_MASK; + pd = env1->tlb_table[mmu_idx][page_index].addr_code & ~TARGET_PAGE_MASK; if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) { #if defined(TARGET_SPARC) || defined(TARGET_MIPS) - do_unassigned_access(addr, 0, 1, 0); + do_unassigned_access(addr, 0, 1, 0, 4); #else - cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); + cpu_abort(env1, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr); #endif } - return addr + env->tlb_table[mmu_idx][index].addend - (unsigned long)phys_ram_base; + p = (void *)(unsigned long)addr + + env1->tlb_table[mmu_idx][page_index].addend; + return qemu_ram_addr_from_host(p); +} + +/* Deterministic execution requires that IO only be performed on the last + instruction of a TB so that interrupts take effect immediately. */ +static inline int can_do_io(CPUState *env) +{ + if (!use_icount) + return 1; + + /* If not executing code then assume we are ok. */ + if (!env->current_tb) + return 1; + + return env->can_do_io != 0; } #endif -#ifdef USE_KQEMU +#ifdef CONFIG_KQEMU #define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG)) +#define MSR_QPI_COMMBASE 0xfabe0010 + int kqemu_init(CPUState *env); int kqemu_cpu_exec(CPUState *env); void kqemu_flush_page(CPUState *env, target_ulong addr); void kqemu_flush(CPUState *env, int global); void kqemu_set_notdirty(CPUState *env, ram_addr_t ram_addr); void kqemu_modify_page(CPUState *env, ram_addr_t ram_addr); +void kqemu_set_phys_mem(uint64_t start_addr, ram_addr_t size, + ram_addr_t phys_offset); void kqemu_cpu_interrupt(CPUState *env); void kqemu_record_dump(void); +extern uint32_t kqemu_comm_base; + +extern ram_addr_t kqemu_phys_ram_size; +extern uint8_t *kqemu_phys_ram_base; + static inline int kqemu_is_ok(CPUState *env) { return(env->kqemu_enabled && @@ -605,3 +386,12 @@ static inline int kqemu_is_ok(CPUState *env) } #endif + +typedef void (CPUDebugExcpHandler)(CPUState *env); + +CPUDebugExcpHandler *cpu_set_debug_excp_handler(CPUDebugExcpHandler *handler); + +/* vl.c */ +extern int singlestep; + +#endif