X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=cpu-all.h;h=e8391009a36e4de3accd1ac2feb0a2ac28cb18de;hb=88ca9f047bf8df20ae0a6305d99cbad1e893777f;hp=5db290356e99376f25932640fe0906ae9cf8a9e7;hpb=db7b5426a4b424249b4aba3496bf14da69a6625b;p=qemu.git diff --git a/cpu-all.h b/cpu-all.h index 5db290356..e8391009a 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -1,6 +1,6 @@ /* * defines common to all virtual CPUs - * + * * Copyright (c) 2003 Fabrice Bellard * * This library is free software; you can redistribute it and/or @@ -14,32 +14,30 @@ * Lesser General Public License for more details. * * 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 + * License along with this library; if not, see . */ #ifndef CPU_ALL_H #define CPU_ALL_H -#if defined(__arm__) || defined(__sparc__) || defined(__mips__) -#define WORDS_ALIGNED -#endif +#include "qemu-common.h" +#include "cpu-common.h" -/* some important defines: - * +/* some important defines: + * * WORDS_ALIGNED : if defined, the host cpu can only make word aligned * memory accesses. - * - * WORDS_BIGENDIAN : if defined, the host cpu is big endian and + * + * HOST_WORDS_BIGENDIAN : if defined, the host cpu is big endian and * otherwise little endian. - * + * * (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet)) - * + * * TARGET_WORDS_BIGENDIAN : same for target cpu */ -#include "bswap.h" +#include "softfloat.h" -#if defined(WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) +#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN) #define BSWAP_NEEDED #endif @@ -116,12 +114,16 @@ static inline void tswap64s(uint64_t *s) #define bswaptls(s) bswap64s(s) #endif +typedef union { + float32 f; + uint32_t l; +} CPU_FloatU; + /* NOTE: arm FPA is horrible as double 32 bit words are stored in big endian ! */ typedef union { float64 d; -#if defined(WORDS_BIGENDIAN) \ - || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT)) +#if defined(HOST_WORDS_BIGENDIAN) struct { uint32_t upper; uint32_t lower; @@ -135,6 +137,41 @@ typedef union { uint64_t ll; } CPU_DoubleU; +typedef union { + floatx80 d; + struct { + uint64_t lower; + uint16_t upper; + } l; +} CPU_LDoubleU; + +typedef union { + float128 q; +#if defined(HOST_WORDS_BIGENDIAN) + struct { + uint32_t upmost; + uint32_t upper; + uint32_t lower; + uint32_t lowest; + } l; + struct { + uint64_t upper; + uint64_t lower; + } ll; +#else + struct { + uint32_t lowest; + uint32_t lower; + uint32_t upper; + uint32_t upmost; + } l; + struct { + uint64_t lower; + uint64_t upper; + } ll; +#endif +} CPU_QuadU; + /* CPU memory access without any memory or io remapping */ /* @@ -147,7 +184,7 @@ typedef union { * type is: * (empty): integer access * f : float access - * + * * sign is: * (empty): for floats or 32 bit size * u : unsigned @@ -158,7 +195,7 @@ typedef union { * w: 16 bits * l: 32 bits * q: 64 bits - * + * * endian is: * (empty): target cpu endianness or 8 bit access * r : reversed target cpu endianness (not implemented yet) @@ -170,12 +207,12 @@ typedef union { * user : user mode access using soft MMU * kernel : kernel mode access using soft MMU */ -static inline int ldub_p(void *ptr) +static inline int ldub_p(const void *ptr) { return *(uint8_t *)ptr; } -static inline int ldsb_p(void *ptr) +static inline int ldsb_p(const void *ptr) { return *(int8_t *)ptr; } @@ -188,48 +225,48 @@ static inline void stb_p(void *ptr, int v) /* NOTE: on arm, putting 2 in /proc/sys/debug/alignment so that the kernel handles unaligned load/stores may give better results, but it is a system wide setting : bad */ -#if defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) +#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) /* conservative code for little endian unaligned accesses */ -static inline int lduw_le_p(void *ptr) +static inline int lduw_le_p(const void *ptr) { -#ifdef __powerpc__ +#ifdef _ARCH_PPC int val; __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); return val; #else - uint8_t *p = ptr; + const uint8_t *p = ptr; return p[0] | (p[1] << 8); #endif } -static inline int ldsw_le_p(void *ptr) +static inline int ldsw_le_p(const void *ptr) { -#ifdef __powerpc__ +#ifdef _ARCH_PPC int val; __asm__ __volatile__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (ptr)); return (int16_t)val; #else - uint8_t *p = ptr; + const uint8_t *p = ptr; return (int16_t)(p[0] | (p[1] << 8)); #endif } -static inline int ldl_le_p(void *ptr) +static inline int ldl_le_p(const void *ptr) { -#ifdef __powerpc__ +#ifdef _ARCH_PPC int val; __asm__ __volatile__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (ptr)); return val; #else - uint8_t *p = ptr; + const uint8_t *p = ptr; return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24); #endif } -static inline uint64_t ldq_le_p(void *ptr) +static inline uint64_t ldq_le_p(const void *ptr) { - uint8_t *p = ptr; + const uint8_t *p = ptr; uint32_t v1, v2; v1 = ldl_le_p(p); v2 = ldl_le_p(p + 4); @@ -238,7 +275,7 @@ static inline uint64_t ldq_le_p(void *ptr) static inline void stw_le_p(void *ptr, int v) { -#ifdef __powerpc__ +#ifdef _ARCH_PPC __asm__ __volatile__ ("sthbrx %1,0,%2" : "=m" (*(uint16_t *)ptr) : "r" (v), "r" (ptr)); #else uint8_t *p = ptr; @@ -249,7 +286,7 @@ static inline void stw_le_p(void *ptr, int v) static inline void stl_le_p(void *ptr, int v) { -#ifdef __powerpc__ +#ifdef _ARCH_PPC __asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*(uint32_t *)ptr) : "r" (v), "r" (ptr)); #else uint8_t *p = ptr; @@ -269,7 +306,7 @@ static inline void stq_le_p(void *ptr, uint64_t v) /* float access */ -static inline float32 ldfl_le_p(void *ptr) +static inline float32 ldfl_le_p(const void *ptr) { union { float32 f; @@ -289,7 +326,7 @@ static inline void stfl_le_p(void *ptr, float32 v) stl_le_p(ptr, u.i); } -static inline float64 ldfq_le_p(void *ptr) +static inline float64 ldfq_le_p(const void *ptr) { CPU_DoubleU u; u.l.lower = ldl_le_p(ptr); @@ -307,22 +344,22 @@ static inline void stfq_le_p(void *ptr, float64 v) #else -static inline int lduw_le_p(void *ptr) +static inline int lduw_le_p(const void *ptr) { return *(uint16_t *)ptr; } -static inline int ldsw_le_p(void *ptr) +static inline int ldsw_le_p(const void *ptr) { return *(int16_t *)ptr; } -static inline int ldl_le_p(void *ptr) +static inline int ldl_le_p(const void *ptr) { return *(uint32_t *)ptr; } -static inline uint64_t ldq_le_p(void *ptr) +static inline uint64_t ldq_le_p(const void *ptr) { return *(uint64_t *)ptr; } @@ -344,12 +381,12 @@ static inline void stq_le_p(void *ptr, uint64_t v) /* float access */ -static inline float32 ldfl_le_p(void *ptr) +static inline float32 ldfl_le_p(const void *ptr) { return *(float32 *)ptr; } -static inline float64 ldfq_le_p(void *ptr) +static inline float64 ldfq_le_p(const void *ptr) { return *(float64 *)ptr; } @@ -365,9 +402,9 @@ static inline void stfq_le_p(void *ptr, float64 v) } #endif -#if !defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) +#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) -static inline int lduw_be_p(void *ptr) +static inline int lduw_be_p(const void *ptr) { #if defined(__i386__) int val; @@ -377,12 +414,12 @@ static inline int lduw_be_p(void *ptr) : "m" (*(uint16_t *)ptr)); return val; #else - uint8_t *b = (uint8_t *) ptr; + const uint8_t *b = ptr; return ((b[0] << 8) | b[1]); #endif } -static inline int ldsw_be_p(void *ptr) +static inline int ldsw_be_p(const void *ptr) { #if defined(__i386__) int val; @@ -392,12 +429,12 @@ static inline int ldsw_be_p(void *ptr) : "m" (*(uint16_t *)ptr)); return (int16_t)val; #else - uint8_t *b = (uint8_t *) ptr; + const uint8_t *b = ptr; return (int16_t)((b[0] << 8) | b[1]); #endif } -static inline int ldl_be_p(void *ptr) +static inline int ldl_be_p(const void *ptr) { #if defined(__i386__) || defined(__x86_64__) int val; @@ -407,16 +444,16 @@ static inline int ldl_be_p(void *ptr) : "m" (*(uint32_t *)ptr)); return val; #else - uint8_t *b = (uint8_t *) ptr; + const uint8_t *b = ptr; return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; #endif } -static inline uint64_t ldq_be_p(void *ptr) +static inline uint64_t ldq_be_p(const void *ptr) { uint32_t a,b; a = ldl_be_p(ptr); - b = ldl_be_p(ptr+4); + b = ldl_be_p((uint8_t *)ptr + 4); return (((uint64_t)a<<32)|b); } @@ -453,12 +490,12 @@ static inline void stl_be_p(void *ptr, int v) static inline void stq_be_p(void *ptr, uint64_t v) { stl_be_p(ptr, v >> 32); - stl_be_p(ptr + 4, v); + stl_be_p((uint8_t *)ptr + 4, v); } /* float access */ -static inline float32 ldfl_be_p(void *ptr) +static inline float32 ldfl_be_p(const void *ptr) { union { float32 f; @@ -478,11 +515,11 @@ static inline void stfl_be_p(void *ptr, float32 v) stl_be_p(ptr, u.i); } -static inline float64 ldfq_be_p(void *ptr) +static inline float64 ldfq_be_p(const void *ptr) { CPU_DoubleU u; u.l.upper = ldl_be_p(ptr); - u.l.lower = ldl_be_p(ptr + 4); + u.l.lower = ldl_be_p((uint8_t *)ptr + 4); return u.d; } @@ -491,27 +528,27 @@ static inline void stfq_be_p(void *ptr, float64 v) CPU_DoubleU u; u.d = v; stl_be_p(ptr, u.l.upper); - stl_be_p(ptr + 4, u.l.lower); + stl_be_p((uint8_t *)ptr + 4, u.l.lower); } #else -static inline int lduw_be_p(void *ptr) +static inline int lduw_be_p(const void *ptr) { return *(uint16_t *)ptr; } -static inline int ldsw_be_p(void *ptr) +static inline int ldsw_be_p(const void *ptr) { return *(int16_t *)ptr; } -static inline int ldl_be_p(void *ptr) +static inline int ldl_be_p(const void *ptr) { return *(uint32_t *)ptr; } -static inline uint64_t ldq_be_p(void *ptr) +static inline uint64_t ldq_be_p(const void *ptr) { return *(uint64_t *)ptr; } @@ -533,12 +570,12 @@ static inline void stq_be_p(void *ptr, uint64_t v) /* float access */ -static inline float32 ldfl_be_p(void *ptr) +static inline float32 ldfl_be_p(const void *ptr) { return *(float32 *)ptr; } -static inline float64 ldfq_be_p(void *ptr) +static inline float64 ldfq_be_p(const void *ptr) { return *(float64 *)ptr; } @@ -585,15 +622,41 @@ static inline void stfq_be_p(void *ptr, float64 v) /* MMU memory access macros */ #if defined(CONFIG_USER_ONLY) +#include +#include "qemu-types.h" + /* On some host systems the guest address space is reserved on the host. * This allows the guest address space to be offset to a convenient location. */ -//#define GUEST_BASE 0x20000000 -#define GUEST_BASE 0 +#if defined(CONFIG_USE_GUEST_BASE) +extern unsigned long guest_base; +extern int have_guest_base; +extern unsigned long reserved_va; +#define GUEST_BASE guest_base +#define RESERVED_VA reserved_va +#else +#define GUEST_BASE 0ul +#define RESERVED_VA 0ul +#endif /* All direct uses of g2h and h2g need to go away for usermode softmmu. */ #define g2h(x) ((void *)((unsigned long)(x) + GUEST_BASE)) -#define h2g(x) ((target_ulong)(x - GUEST_BASE)) + +#if HOST_LONG_BITS <= TARGET_VIRT_ADDR_SPACE_BITS +#define h2g_valid(x) 1 +#else +#define h2g_valid(x) ({ \ + unsigned long __guest = (unsigned long)(x) - GUEST_BASE; \ + __guest < (1ul << TARGET_VIRT_ADDR_SPACE_BITS); \ +}) +#endif + +#define h2g(x) ({ \ + unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \ + /* Check if given address fits target address space */ \ + assert(h2g_valid(x)); \ + (abi_ulong)__ret; \ +}) #define saddr(x) g2h(x) #define laddr(x) g2h(x) @@ -621,7 +684,7 @@ static inline void stfq_be_p(void *ptr, float64 v) #define stfq_raw(p, v) stfq_p(saddr((p)), v) -#if defined(CONFIG_USER_ONLY) +#if defined(CONFIG_USER_ONLY) /* if user mode, no other memory access functions */ #define ldub(p) ldub_raw(p) @@ -685,124 +748,138 @@ extern unsigned long qemu_host_page_mask; #define PAGE_VALID 0x0008 /* original state of the write flag (used when tracking self-modifying code */ -#define PAGE_WRITE_ORG 0x0010 +#define PAGE_WRITE_ORG 0x0010 +#if defined(CONFIG_BSD) && defined(CONFIG_USER_ONLY) +/* FIXME: Code that sets/uses this is broken and needs to go away. */ +#define PAGE_RESERVED 0x0020 +#endif +#if defined(CONFIG_USER_ONLY) void page_dump(FILE *f); -int page_get_flags(target_ulong address); -void page_set_flags(target_ulong start, target_ulong end, int flags); -void page_unprotect_range(target_ulong data, target_ulong data_size); - -#define SINGLE_CPU_DEFINES -#ifdef SINGLE_CPU_DEFINES - -#if defined(TARGET_I386) - -#define CPUState CPUX86State -#define cpu_init cpu_x86_init -#define cpu_exec cpu_x86_exec -#define cpu_gen_code cpu_x86_gen_code -#define cpu_signal_handler cpu_x86_signal_handler - -#elif defined(TARGET_ARM) - -#define CPUState CPUARMState -#define cpu_init cpu_arm_init -#define cpu_exec cpu_arm_exec -#define cpu_gen_code cpu_arm_gen_code -#define cpu_signal_handler cpu_arm_signal_handler - -#elif defined(TARGET_SPARC) - -#define CPUState CPUSPARCState -#define cpu_init cpu_sparc_init -#define cpu_exec cpu_sparc_exec -#define cpu_gen_code cpu_sparc_gen_code -#define cpu_signal_handler cpu_sparc_signal_handler - -#elif defined(TARGET_PPC) - -#define CPUState CPUPPCState -#define cpu_init cpu_ppc_init -#define cpu_exec cpu_ppc_exec -#define cpu_gen_code cpu_ppc_gen_code -#define cpu_signal_handler cpu_ppc_signal_handler - -#elif defined(TARGET_M68K) -#define CPUState CPUM68KState -#define cpu_init cpu_m68k_init -#define cpu_exec cpu_m68k_exec -#define cpu_gen_code cpu_m68k_gen_code -#define cpu_signal_handler cpu_m68k_signal_handler - -#elif defined(TARGET_MIPS) -#define CPUState CPUMIPSState -#define cpu_init cpu_mips_init -#define cpu_exec cpu_mips_exec -#define cpu_gen_code cpu_mips_gen_code -#define cpu_signal_handler cpu_mips_signal_handler - -#elif defined(TARGET_SH4) -#define CPUState CPUSH4State -#define cpu_init cpu_sh4_init -#define cpu_exec cpu_sh4_exec -#define cpu_gen_code cpu_sh4_gen_code -#define cpu_signal_handler cpu_sh4_signal_handler - -#elif defined(TARGET_ALPHA) -#define CPUState CPUAlphaState -#define cpu_init cpu_alpha_init -#define cpu_exec cpu_alpha_exec -#define cpu_gen_code cpu_alpha_gen_code -#define cpu_signal_handler cpu_alpha_signal_handler -#else - -#error unsupported target CPU +typedef int (*walk_memory_regions_fn)(void *, abi_ulong, + abi_ulong, unsigned long); +int walk_memory_regions(void *, walk_memory_regions_fn); +int page_get_flags(target_ulong address); +void page_set_flags(target_ulong start, target_ulong end, int flags); +int page_check_range(target_ulong start, target_ulong len, int flags); #endif -#endif /* SINGLE_CPU_DEFINES */ - CPUState *cpu_copy(CPUState *env); +CPUState *qemu_get_cpu(int cpu); -void cpu_dump_state(CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), +#define CPU_DUMP_CODE 0x00010000 + +void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf, int flags); -void cpu_dump_statistics (CPUState *env, FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...), - int flags); +void cpu_dump_statistics(CPUState *env, FILE *f, fprintf_function cpu_fprintf, + int flags); -void cpu_abort(CPUState *env, const char *fmt, ...) - __attribute__ ((__format__ (__printf__, 2, 3))); +void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...) + GCC_FMT_ATTR(2, 3); extern CPUState *first_cpu; extern CPUState *cpu_single_env; -extern int code_copy_enabled; - -#define CPU_INTERRUPT_EXIT 0x01 /* wants exit from main loop */ -#define CPU_INTERRUPT_HARD 0x02 /* hardware interrupt pending */ -#define CPU_INTERRUPT_EXITTB 0x04 /* exit the current TB (use for x86 a20 case) */ -#define CPU_INTERRUPT_TIMER 0x08 /* internal timer exception pending */ -#define CPU_INTERRUPT_FIQ 0x10 /* Fast interrupt pending. */ -#define CPU_INTERRUPT_HALT 0x20 /* CPU halt wanted */ -#define CPU_INTERRUPT_SMI 0x40 /* (x86 only) SMI interrupt pending */ -#define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */ - -void cpu_interrupt(CPUState *s, int mask); + +/* Flags for use in ENV->INTERRUPT_PENDING. + + The numbers assigned here are non-sequential in order to preserve + binary compatibility with the vmstate dump. Bit 0 (0x0001) was + previously used for CPU_INTERRUPT_EXIT, and is cleared when loading + the vmstate dump. */ + +/* External hardware interrupt pending. This is typically used for + interrupts from devices. */ +#define CPU_INTERRUPT_HARD 0x0002 + +/* Exit the current TB. This is typically used when some system-level device + makes some change to the memory mapping. E.g. the a20 line change. */ +#define CPU_INTERRUPT_EXITTB 0x0004 + +/* Halt the CPU. */ +#define CPU_INTERRUPT_HALT 0x0020 + +/* Debug event pending. */ +#define CPU_INTERRUPT_DEBUG 0x0080 + +/* Several target-specific external hardware interrupts. Each target/cpu.h + should define proper names based on these defines. */ +#define CPU_INTERRUPT_TGT_EXT_0 0x0008 +#define CPU_INTERRUPT_TGT_EXT_1 0x0010 +#define CPU_INTERRUPT_TGT_EXT_2 0x0040 +#define CPU_INTERRUPT_TGT_EXT_3 0x0200 +#define CPU_INTERRUPT_TGT_EXT_4 0x1000 + +/* Several target-specific internal interrupts. These differ from the + preceeding target-specific interrupts in that they are intended to + originate from within the cpu itself, typically in response to some + instruction being executed. These, therefore, are not masked while + single-stepping within the debugger. */ +#define CPU_INTERRUPT_TGT_INT_0 0x0100 +#define CPU_INTERRUPT_TGT_INT_1 0x0400 +#define CPU_INTERRUPT_TGT_INT_2 0x0800 + +/* First unused bit: 0x2000. */ + +/* The set of all bits that should be masked when single-stepping. */ +#define CPU_INTERRUPT_SSTEP_MASK \ + (CPU_INTERRUPT_HARD \ + | CPU_INTERRUPT_TGT_EXT_0 \ + | CPU_INTERRUPT_TGT_EXT_1 \ + | CPU_INTERRUPT_TGT_EXT_2 \ + | CPU_INTERRUPT_TGT_EXT_3 \ + | CPU_INTERRUPT_TGT_EXT_4) + +#ifndef CONFIG_USER_ONLY +typedef void (*CPUInterruptHandler)(CPUState *, int); + +extern CPUInterruptHandler cpu_interrupt_handler; + +static inline void cpu_interrupt(CPUState *s, int mask) +{ + cpu_interrupt_handler(s, mask); +} +#else /* USER_ONLY */ +void cpu_interrupt(CPUState *env, int mask); +#endif /* USER_ONLY */ + void cpu_reset_interrupt(CPUState *env, int mask); -int cpu_watchpoint_insert(CPUState *env, target_ulong addr); -int cpu_watchpoint_remove(CPUState *env, target_ulong addr); -int cpu_breakpoint_insert(CPUState *env, target_ulong pc); -int cpu_breakpoint_remove(CPUState *env, target_ulong pc); +void cpu_exit(CPUState *s); + +bool qemu_cpu_has_work(CPUState *env); + +/* Breakpoint/watchpoint flags */ +#define BP_MEM_READ 0x01 +#define BP_MEM_WRITE 0x02 +#define BP_MEM_ACCESS (BP_MEM_READ | BP_MEM_WRITE) +#define BP_STOP_BEFORE_ACCESS 0x04 +#define BP_WATCHPOINT_HIT 0x08 +#define BP_GDB 0x10 +#define BP_CPU 0x20 + +int cpu_breakpoint_insert(CPUState *env, target_ulong pc, int flags, + CPUBreakpoint **breakpoint); +int cpu_breakpoint_remove(CPUState *env, target_ulong pc, int flags); +void cpu_breakpoint_remove_by_ref(CPUState *env, CPUBreakpoint *breakpoint); +void cpu_breakpoint_remove_all(CPUState *env, int mask); +int cpu_watchpoint_insert(CPUState *env, target_ulong addr, target_ulong len, + int flags, CPUWatchpoint **watchpoint); +int cpu_watchpoint_remove(CPUState *env, target_ulong addr, + target_ulong len, int flags); +void cpu_watchpoint_remove_by_ref(CPUState *env, CPUWatchpoint *watchpoint); +void cpu_watchpoint_remove_all(CPUState *env, int mask); + +#define SSTEP_ENABLE 0x1 /* Enable simulated HW single stepping */ +#define SSTEP_NOIRQ 0x2 /* Do not use IRQ while single stepping */ +#define SSTEP_NOTIMER 0x4 /* Do not Timers while single stepping */ + void cpu_single_step(CPUState *env, int enabled); void cpu_reset(CPUState *s); +int cpu_is_stopped(CPUState *env); +void run_on_cpu(CPUState *env, void (*func)(void *data), void *data); -/* Return the physical page corresponding to a virtual one. Use it - only for debugging because no protection checks are done. Return -1 - if no page found. */ -target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr); - -#define CPU_LOG_TB_OUT_ASM (1 << 0) +#define CPU_LOG_TB_OUT_ASM (1 << 0) #define CPU_LOG_TB_IN_ASM (1 << 1) #define CPU_LOG_TB_OP (1 << 2) #define CPU_LOG_TB_OP_OPT (1 << 3) @@ -811,6 +888,7 @@ target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr); #define CPU_LOG_PCALL (1 << 6) #define CPU_LOG_IOPORT (1 << 7) #define CPU_LOG_TB_CPU (1 << 8) +#define CPU_LOG_RESET (1 << 9) /* define log items */ typedef struct CPULogItem { @@ -819,258 +897,134 @@ typedef struct CPULogItem { const char *help; } CPULogItem; -extern CPULogItem cpu_log_items[]; +extern const CPULogItem cpu_log_items[]; void cpu_set_log(int log_flags); void cpu_set_log_filename(const char *filename); int cpu_str_to_log_mask(const char *str); -/* IO ports API */ - -/* NOTE: as these functions may be even used when there is an isa - brige on non x86 targets, we always defined them */ -#ifndef NO_CPU_IO_DEFS -void cpu_outb(CPUState *env, int addr, int val); -void cpu_outw(CPUState *env, int addr, int val); -void cpu_outl(CPUState *env, int addr, int val); -int cpu_inb(CPUState *env, int addr); -int cpu_inw(CPUState *env, int addr); -int cpu_inl(CPUState *env, int addr); -#endif +#if !defined(CONFIG_USER_ONLY) + +/* Return the physical page corresponding to a virtual one. Use it + only for debugging because no protection checks are done. Return -1 + if no page found. */ +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr); /* memory API */ -extern int phys_ram_size; extern int phys_ram_fd; -extern uint8_t *phys_ram_base; -extern uint8_t *phys_ram_dirty; - -/* physical memory access */ -#define TLB_INVALID_MASK (1 << 3) -#define IO_MEM_SHIFT 4 -#define IO_MEM_NB_ENTRIES (1 << (TARGET_PAGE_BITS - IO_MEM_SHIFT)) - -#define IO_MEM_RAM (0 << IO_MEM_SHIFT) /* hardcoded offset */ -#define IO_MEM_ROM (1 << IO_MEM_SHIFT) /* hardcoded offset */ -#define IO_MEM_UNASSIGNED (2 << IO_MEM_SHIFT) -#define IO_MEM_NOTDIRTY (4 << IO_MEM_SHIFT) /* used internally, never use directly */ -/* acts like a ROM when read and like a device when written. As an - exception, the write memory callback gets the ram offset instead of - the physical address */ -#define IO_MEM_ROMD (1) -#define IO_MEM_SUBPAGE (2) - -typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value); -typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr); - -void cpu_register_physical_memory(target_phys_addr_t start_addr, - unsigned long size, - unsigned long phys_offset); -uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr); -ram_addr_t qemu_ram_alloc(unsigned int size); -void qemu_ram_free(ram_addr_t addr); -int cpu_register_io_memory(int io_index, - CPUReadMemoryFunc **mem_read, - CPUWriteMemoryFunc **mem_write, - void *opaque); -CPUWriteMemoryFunc **cpu_get_io_memory_write(int io_index); -CPUReadMemoryFunc **cpu_get_io_memory_read(int io_index); - -void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, - int len, int is_write); -static inline void cpu_physical_memory_read(target_phys_addr_t addr, - uint8_t *buf, int len) -{ - cpu_physical_memory_rw(addr, buf, len, 0); -} -static inline void cpu_physical_memory_write(target_phys_addr_t addr, - const uint8_t *buf, int len) -{ - cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1); -} -uint32_t ldub_phys(target_phys_addr_t addr); -uint32_t lduw_phys(target_phys_addr_t addr); -uint32_t ldl_phys(target_phys_addr_t addr); -uint64_t ldq_phys(target_phys_addr_t addr); -void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val); -void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val); -void stb_phys(target_phys_addr_t addr, uint32_t val); -void stw_phys(target_phys_addr_t addr, uint32_t val); -void stl_phys(target_phys_addr_t addr, uint32_t val); -void stq_phys(target_phys_addr_t addr, uint64_t val); - -void cpu_physical_memory_write_rom(target_phys_addr_t addr, - const uint8_t *buf, int len); -int cpu_memory_rw_debug(CPUState *env, target_ulong addr, - uint8_t *buf, int len, int is_write); - -#define VGA_DIRTY_FLAG 0x01 -#define CODE_DIRTY_FLAG 0x02 +extern ram_addr_t ram_size; + +/* RAM is pre-allocated and passed into qemu_ram_alloc_from_ptr */ +#define RAM_PREALLOC_MASK (1 << 0) + +typedef struct RAMBlock { + uint8_t *host; + ram_addr_t offset; + ram_addr_t length; + uint32_t flags; + char idstr[256]; + QLIST_ENTRY(RAMBlock) next; +#if defined(__linux__) && !defined(TARGET_S390X) + int fd; +#endif +} RAMBlock; -/* read dirty bit (return 0 or 1) */ -static inline int cpu_physical_memory_is_dirty(ram_addr_t addr) -{ - return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff; -} +typedef struct RAMList { + uint8_t *phys_dirty; + QLIST_HEAD(ram, RAMBlock) blocks; +} RAMList; +extern RAMList ram_list; -static inline int cpu_physical_memory_get_dirty(ram_addr_t addr, - int dirty_flags) -{ - return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags; -} +extern const char *mem_path; +extern int mem_prealloc; -static inline void cpu_physical_memory_set_dirty(ram_addr_t addr) -{ - phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff; -} +/* physical memory access */ -void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, - int dirty_flags); -void cpu_tlb_update_dirty(CPUState *env); +/* MMIO pages are identified by a combination of an IO device index and + 3 flags. The ROMD code stores the page ram offset in iotlb entry, + so only a limited number of ids are avaiable. */ -void dump_exec_info(FILE *f, - int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +#define IO_MEM_NB_ENTRIES (1 << (TARGET_PAGE_BITS - IO_MEM_SHIFT)) -/*******************************************/ -/* host CPU ticks (if available) */ +/* Flags stored in the low bits of the TLB virtual address. These are + defined so that fast path ram access is all zeros. */ +/* Zero if TLB entry is valid. */ +#define TLB_INVALID_MASK (1 << 3) +/* Set if TLB entry references a clean RAM page. The iotlb entry will + contain the page physical address. */ +#define TLB_NOTDIRTY (1 << 4) +/* Set if TLB entry is an IO callback. */ +#define TLB_MMIO (1 << 5) -#if defined(__powerpc__) +#define VGA_DIRTY_FLAG 0x01 +#define CODE_DIRTY_FLAG 0x02 +#define MIGRATION_DIRTY_FLAG 0x08 -static inline uint32_t get_tbl(void) -{ - uint32_t tbl; - asm volatile("mftb %0" : "=r" (tbl)); - return tbl; -} - -static inline uint32_t get_tbu(void) +/* read dirty bit (return 0 or 1) */ +static inline int cpu_physical_memory_is_dirty(ram_addr_t addr) { - uint32_t tbl; - asm volatile("mftbu %0" : "=r" (tbl)); - return tbl; + return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] == 0xff; } -static inline int64_t cpu_get_real_ticks(void) +static inline int cpu_physical_memory_get_dirty_flags(ram_addr_t addr) { - uint32_t l, h, h1; - /* NOTE: we test if wrapping has occurred */ - do { - h = get_tbu(); - l = get_tbl(); - h1 = get_tbu(); - } while (h != h1); - return ((int64_t)h << 32) | l; + return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS]; } -#elif defined(__i386__) - -static inline int64_t cpu_get_real_ticks(void) +static inline int cpu_physical_memory_get_dirty(ram_addr_t addr, + int dirty_flags) { - int64_t val; - asm volatile ("rdtsc" : "=A" (val)); - return val; + return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags; } -#elif defined(__x86_64__) - -static inline int64_t cpu_get_real_ticks(void) +static inline void cpu_physical_memory_set_dirty(ram_addr_t addr) { - uint32_t low,high; - int64_t val; - asm volatile("rdtsc" : "=a" (low), "=d" (high)); - val = high; - val <<= 32; - val |= low; - return val; + ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] = 0xff; } -#elif defined(__ia64) - -static inline int64_t cpu_get_real_ticks(void) +static inline int cpu_physical_memory_set_dirty_flags(ram_addr_t addr, + int dirty_flags) { - int64_t val; - asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); - return val; + return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] |= dirty_flags; } -#elif defined(__s390__) - -static inline int64_t cpu_get_real_ticks(void) +static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start, + int length, + int dirty_flags) { - int64_t val; - asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc"); - return val; -} - -#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) + int i, mask, len; + uint8_t *p; -static inline int64_t cpu_get_real_ticks (void) -{ -#if defined(_LP64) - uint64_t rval; - asm volatile("rd %%tick,%0" : "=r"(rval)); - return rval; -#else - union { - uint64_t i64; - struct { - uint32_t high; - uint32_t low; - } i32; - } rval; - asm volatile("rd %%tick,%1; srlx %1,32,%0" - : "=r"(rval.i32.high), "=r"(rval.i32.low)); - return rval.i64; -#endif + len = length >> TARGET_PAGE_BITS; + mask = ~dirty_flags; + p = ram_list.phys_dirty + (start >> TARGET_PAGE_BITS); + for (i = 0; i < len; i++) { + p[i] &= mask; + } } -#elif defined(__mips__) +void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, + int dirty_flags); +void cpu_tlb_update_dirty(CPUState *env); -static inline int64_t cpu_get_real_ticks(void) -{ -#if __mips_isa_rev >= 2 - uint32_t count; - static uint32_t cyc_per_count = 0; +int cpu_physical_memory_set_dirty_tracking(int enable); - if (!cyc_per_count) - __asm__ __volatile__("rdhwr %0, $3" : "=r" (cyc_per_count)); +int cpu_physical_memory_get_dirty_tracking(void); - __asm__ __volatile__("rdhwr %1, $2" : "=r" (count)); - return (int64_t)(count * cyc_per_count); -#else - /* FIXME */ - static int64_t ticks = 0; - return ticks++; -#endif -} +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr); -#else -/* The host CPU doesn't have an easily accessible cycle counter. - Just return a monotonically increasing value. This will be - totally wrong, but hopefully better than nothing. */ -static inline int64_t cpu_get_real_ticks (void) -{ - static int64_t ticks = 0; - return ticks++; -} -#endif +int cpu_physical_log_start(target_phys_addr_t start_addr, + ram_addr_t size); -/* profiling */ -#ifdef CONFIG_PROFILER -static inline int64_t profile_getclock(void) -{ - return cpu_get_real_ticks(); -} +int cpu_physical_log_stop(target_phys_addr_t start_addr, + ram_addr_t size); -extern int64_t kqemu_time, kqemu_time_start; -extern int64_t qemu_time, qemu_time_start; -extern int64_t tlb_flush_time; -extern int64_t kqemu_exec_count; -extern int64_t dev_time; -extern int64_t kqemu_ret_int_count; -extern int64_t kqemu_ret_excp_count; -extern int64_t kqemu_ret_intr_count; +void dump_exec_info(FILE *f, fprintf_function cpu_fprintf); +#endif /* !CONFIG_USER_ONLY */ -#endif +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write); #endif /* CPU_ALL_H */