diff options
Diffstat (limited to 'src/recompiler/cpu-all.h')
-rw-r--r-- | src/recompiler/cpu-all.h | 821 |
1 files changed, 262 insertions, 559 deletions
diff --git a/src/recompiler/cpu-all.h b/src/recompiler/cpu-all.h index 42573fea2..4efa84434 100644 --- a/src/recompiler/cpu-all.h +++ b/src/recompiler/cpu-all.h @@ -14,8 +14,7 @@ * 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 <http://www.gnu.org/licenses/>. */ /* @@ -36,18 +35,16 @@ # endif # include <VBox/log.h> # include <VBox/vmm/pgm.h> /* PGM_DYNAMIC_RAM_ALLOC */ -#endif - -#if defined(__arm__) || defined(__sparc__) -#define WORDS_ALIGNED -#endif +#endif /* VBOX */ +#include "qemu-common.h" +#include "cpu-common.h" /* 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)) @@ -55,9 +52,9 @@ * 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 @@ -95,54 +92,30 @@ static inline void tswap64s(uint64_t *s) #else -#ifndef VBOX static inline uint16_t tswap16(uint16_t s) -#else -DECLINLINE(uint16_t) tswap16(uint16_t s) -#endif { return s; } -#ifndef VBOX static inline uint32_t tswap32(uint32_t s) -#else -DECLINLINE(uint32_t) tswap32(uint32_t s) -#endif { return s; } -#ifndef VBOX static inline uint64_t tswap64(uint64_t s) -#else -DECLINLINE(uint64_t) tswap64(uint64_t s) -#endif { return s; } -#ifndef VBOX static inline void tswap16s(uint16_t *s) -#else -DECLINLINE(void) tswap16s(uint16_t *s) -#endif { } -#ifndef VBOX static inline void tswap32s(uint32_t *s) -#else -DECLINLINE(void) tswap32s(uint32_t *s) -#endif { } -#ifndef VBOX static inline void tswap64s(uint64_t *s) -#else -DECLINLINE(void) tswap64s(uint64_t *s) -#endif { } @@ -167,7 +140,7 @@ typedef union { endian ! */ typedef union { float64 d; -#if defined(WORDS_BIGENDIAN) \ +#if defined(HOST_WORDS_BIGENDIAN) \ || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT)) struct { uint32_t upper; @@ -185,7 +158,7 @@ typedef union { #ifdef TARGET_SPARC typedef union { float128 q; -#if defined(WORDS_BIGENDIAN) \ +#if defined(HOST_WORDS_BIGENDIAN) \ || (defined(__arm__) && !defined(__VFP_FP__) && !defined(CONFIG_SOFTFLOAT)) struct { uint32_t upmost; @@ -266,21 +239,21 @@ void remR3PhysWriteU16(RTGCPHYS DstGCPhys, uint16_t val); void remR3PhysWriteU32(RTGCPHYS DstGCPhys, uint32_t val); void remR3PhysWriteU64(RTGCPHYS DstGCPhys, uint64_t val); -#ifndef REM_PHYS_ADDR_IN_TLB +# ifndef REM_PHYS_ADDR_IN_TLB void *remR3TlbGCPhys2Ptr(CPUState *env1, target_ulong physAddr, int fWritable); -#endif +# endif #endif /* VBOX */ #if defined(VBOX) && defined(REM_PHYS_ADDR_IN_TLB) -DECLINLINE(uint8_t) ldub_p(void *ptr) +DECLINLINE(uint8_t) ldub_p(const void *ptr) { VBOX_CHECK_ADDR(ptr); return remR3PhysReadU8((uintptr_t)ptr); } -DECLINLINE(int8_t) ldsb_p(void *ptr) +DECLINLINE(int8_t) ldsb_p(const void *ptr) { VBOX_CHECK_ADDR(ptr); return remR3PhysReadS8((uintptr_t)ptr); @@ -292,13 +265,13 @@ DECLINLINE(void) stb_p(void *ptr, int v) remR3PhysWriteU8((uintptr_t)ptr, v); } -DECLINLINE(uint32_t) lduw_le_p(void *ptr) +DECLINLINE(uint32_t) lduw_le_p(const void *ptr) { VBOX_CHECK_ADDR(ptr); return remR3PhysReadU16((uintptr_t)ptr); } -DECLINLINE(int32_t) ldsw_le_p(void *ptr) +DECLINLINE(int32_t) ldsw_le_p(const void *ptr) { VBOX_CHECK_ADDR(ptr); return remR3PhysReadS16((uintptr_t)ptr); @@ -310,7 +283,7 @@ DECLINLINE(void) stw_le_p(void *ptr, int v) remR3PhysWriteU16((uintptr_t)ptr, v); } -DECLINLINE(uint32_t) ldl_le_p(void *ptr) +DECLINLINE(uint32_t) ldl_le_p(const void *ptr) { VBOX_CHECK_ADDR(ptr); return remR3PhysReadU32((uintptr_t)ptr); @@ -328,17 +301,17 @@ DECLINLINE(void) stq_le_p(void *ptr, uint64_t v) remR3PhysWriteU64((uintptr_t)ptr, v); } -DECLINLINE(uint64_t) ldq_le_p(void *ptr) +DECLINLINE(uint64_t) ldq_le_p(const void *ptr) { VBOX_CHECK_ADDR(ptr); return remR3PhysReadU64((uintptr_t)ptr); } -#undef VBOX_CHECK_ADDR +# undef VBOX_CHECK_ADDR /* float access */ -DECLINLINE(float32) ldfl_le_p(void *ptr) +DECLINLINE(float32) ldfl_le_p(const void *ptr) { union { float32 f; @@ -358,7 +331,7 @@ DECLINLINE(void) stfl_le_p(void *ptr, float32 v) stl_le_p(ptr, u.i); } -DECLINLINE(float64) ldfq_le_p(void *ptr) +DECLINLINE(float64) ldfq_le_p(const void *ptr) { CPU_DoubleU u; u.l.lower = ldl_le_p(ptr); @@ -374,14 +347,14 @@ DECLINLINE(void) stfq_le_p(void *ptr, float64 v) stl_le_p((uint8_t*)ptr + 4, u.l.upper); } -#else /* !(VBOX && REM_PHYS_ADDR_IN_TLB) */ +#else /* !VBOX || !REM_PHYS_ADDR_IN_TLB */ -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; } @@ -394,48 +367,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); @@ -444,7 +417,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; @@ -455,7 +428,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; @@ -475,7 +448,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; @@ -495,7 +468,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); @@ -513,22 +486,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; } @@ -550,12 +523,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; } @@ -570,12 +543,12 @@ static inline void stfq_le_p(void *ptr, float64 v) *(float64 *)ptr = v; } #endif -#endif /* !VBOX */ -#if !defined(WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) +#endif /* !VBOX || !REM_PHYS_ADDR_IN_TLB */ -#ifndef VBOX -static inline int lduw_be_p(void *ptr) +#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED) + +static inline int lduw_be_p(const void *ptr) { #if defined(__i386__) int val; @@ -585,29 +558,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 } -#else /* VBOX */ -DECLINLINE(int) lduw_be_p(void *ptr) -{ -#if defined(__i386__) && !defined(_MSC_VER) - int val; - asm volatile ("movzwl %1, %0\n" - "xchgb %b0, %h0\n" - : "=q" (val) - : "m" (*(uint16_t *)ptr)); - return val; -#else - uint8_t *b = (uint8_t *) ptr; - return ((b[0] << 8) | b[1]); -#endif -} -#endif -#ifndef VBOX -static inline int ldsw_be_p(void *ptr) +static inline int ldsw_be_p(const void *ptr) { #if defined(__i386__) int val; @@ -617,29 +573,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 } -#else -DECLINLINE(int) ldsw_be_p(void *ptr) -{ -#if defined(__i386__) && !defined(_MSC_VER) - int val; - asm volatile ("movzwl %1, %0\n" - "xchgb %b0, %h0\n" - : "=q" (val) - : "m" (*(uint16_t *)ptr)); - return (int16_t)val; -#else - uint8_t *b = (uint8_t *) ptr; - return (int16_t)((b[0] << 8) | b[1]); -#endif -} -#endif -#ifndef VBOX -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; @@ -649,40 +588,19 @@ 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 } -#else -DECLINLINE(int) ldl_be_p(void *ptr) -{ -#if (defined(__i386__) || defined(__x86_64__)) && !defined(_MSC_VER) - int val; - asm volatile ("movl %1, %0\n" - "bswap %0\n" - : "=r" (val) - : "m" (*(uint32_t *)ptr)); - return val; -#else - uint8_t *b = (uint8_t *) ptr; - return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3]; -#endif -} -#endif -#ifndef VBOX -static inline uint64_t ldq_be_p(void *ptr) -#else -DECLINLINE(uint64_t) ldq_be_p(void *ptr) -#endif +static inline uint64_t ldq_be_p(const void *ptr) { uint32_t a,b; a = ldl_be_p(ptr); - b = ldl_be_p((uint8_t*)ptr+4); + b = ldl_be_p((uint8_t *)ptr + 4); return (((uint64_t)a<<32)|b); } -#ifndef VBOX static inline void stw_be_p(void *ptr, int v) { #if defined(__i386__) @@ -696,24 +614,7 @@ static inline void stw_be_p(void *ptr, int v) d[1] = v; #endif } -#else -DECLINLINE(void) stw_be_p(void *ptr, int v) -{ -#if defined(__i386__) && !defined(_MSC_VER) - asm volatile ("xchgb %b0, %h0\n" - "movw %w0, %1\n" - : "=q" (v) - : "m" (*(uint16_t *)ptr), "0" (v)); -#else - uint8_t *d = (uint8_t *) ptr; - d[0] = v >> 8; - d[1] = v; -#endif -} - -#endif /* VBOX */ -#ifndef VBOX static inline void stl_be_p(void *ptr, int v) { #if defined(__i386__) || defined(__x86_64__) @@ -729,40 +630,16 @@ static inline void stl_be_p(void *ptr, int v) d[3] = v; #endif } -#else -DECLINLINE(void) stl_be_p(void *ptr, int v) -{ -#if !defined(_MSC_VER) && (defined(__i386__) || defined(__x86_64__)) - asm volatile ("bswap %0\n" - "movl %0, %1\n" - : "=r" (v) - : "m" (*(uint32_t *)ptr), "0" (v)); -#else - uint8_t *d = (uint8_t *) ptr; - d[0] = v >> 24; - d[1] = v >> 16; - d[2] = v >> 8; - d[3] = v; -#endif -} -#endif /* VBOX */ -#ifndef VBOX static inline void stq_be_p(void *ptr, uint64_t v) -#else -DECLINLINE(void) stq_be_p(void *ptr, uint64_t v) -#endif { stl_be_p(ptr, v >> 32); - stl_be_p((uint8_t*)ptr + 4, v); + stl_be_p((uint8_t *)ptr + 4, v); } /* float access */ -#ifndef VBOX -static inline float32 ldfl_be_p(void *ptr) -#else -DECLINLINE(float32) ldfl_be_p(void *ptr) -#endif + +static inline float32 ldfl_be_p(const void *ptr) { union { float32 f; @@ -772,11 +649,7 @@ DECLINLINE(float32) ldfl_be_p(void *ptr) return u.f; } -#ifndef VBOX static inline void stfl_be_p(void *ptr, float32 v) -#else -DECLINLINE(void) stfl_be_p(void *ptr, float32 v) -#endif { union { float32 f; @@ -786,48 +659,40 @@ DECLINLINE(void) stfl_be_p(void *ptr, float32 v) stl_be_p(ptr, u.i); } -#ifndef VBOX -static inline float64 ldfq_be_p(void *ptr) -#else -DECLINLINE(float64) ldfq_be_p(void *ptr) -#endif +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((uint8_t*)ptr + 4); + u.l.lower = ldl_be_p((uint8_t *)ptr + 4); return u.d; } -#ifndef VBOX static inline void stfq_be_p(void *ptr, float64 v) -#else -DECLINLINE(void) stfq_be_p(void *ptr, float64 v) -#endif { CPU_DoubleU u; u.d = v; stl_be_p(ptr, u.l.upper); - stl_be_p((uint8_t*)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; } @@ -849,12 +714,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; } @@ -901,15 +766,42 @@ static inline void stfq_be_p(void *ptr, float64 v) /* MMU memory access macros */ #if defined(CONFIG_USER_ONLY) +#include <assert.h> +#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) @@ -959,12 +851,14 @@ static inline void stfq_be_p(void *ptr, float64 v) #define lduw_code(p) lduw_raw(p) #define ldsw_code(p) ldsw_raw(p) #define ldl_code(p) ldl_raw(p) +#define ldq_code(p) ldq_raw(p) #define ldub_kernel(p) ldub_raw(p) #define ldsb_kernel(p) ldsb_raw(p) #define lduw_kernel(p) lduw_raw(p) #define ldsw_kernel(p) ldsw_raw(p) #define ldl_kernel(p) ldl_raw(p) +#define ldq_kernel(p) ldq_raw(p) #define ldfl_kernel(p) ldfl_raw(p) #define ldfq_kernel(p) ldfq_raw(p) #define stb_kernel(p, v) stb_raw(p, v) @@ -999,124 +893,100 @@ extern unsigned long qemu_host_page_mask; /* original state of the write flag (used when tracking self-modifying code */ #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); + +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); -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 - -#else - -#error unsupported target CPU - #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, ...), int flags); +void cpu_dump_statistics (CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags); -DECLNORETURN(void) cpu_abort(CPUState *env, const char *fmt, ...); +void QEMU_NORETURN cpu_abort(CPUState *env, const char *fmt, ...) +#ifndef VBOX + __attribute__ ((__format__ (__printf__, 2, 3))); +#else /* VBOX */ + ; +#endif /* VBOX */ extern CPUState *first_cpu; extern CPUState *cpu_single_env; -extern int64_t qemu_icount; -extern int use_icount; -#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 occurred. */ +#define CPU_INTERRUPT_DEBUG 0x80 /* Debug event occured. */ #define CPU_INTERRUPT_VIRQ 0x100 /* virtual interrupt pending. */ #define CPU_INTERRUPT_NMI 0x200 /* NMI pending. */ +#define CPU_INTERRUPT_INIT 0x400 /* INIT pending. */ +#define CPU_INTERRUPT_SIPI 0x800 /* SIPI pending. */ +#define CPU_INTERRUPT_MCE 0x1000 /* (x86 only) MCE pending. */ #ifdef VBOX /** Executes a single instruction. cpu_exec() will normally return EXCP_SINGLE_INSTR. */ -#define CPU_INTERRUPT_SINGLE_INSTR 0x0400 +# define CPU_INTERRUPT_SINGLE_INSTR 0x01000000 /** Executing a CPU_INTERRUPT_SINGLE_INSTR request, quit the cpu_loop. (for exceptions and suchlike) */ -#define CPU_INTERRUPT_SINGLE_INSTR_IN_FLIGHT 0x0800 +# define CPU_INTERRUPT_SINGLE_INSTR_IN_FLIGHT 0x02000000 /** VM execution was interrupted by VMR3Reset, VMR3Suspend or VMR3PowerOff. */ -#define CPU_INTERRUPT_RC 0x1000 -/** Exit current TB to process an external interrupt request (also in op.c!!) */ -#define CPU_INTERRUPT_EXTERNAL_EXIT 0x2000 -/** Exit current TB to process an external interrupt request (also in op.c!!) */ -#define CPU_INTERRUPT_EXTERNAL_HARD 0x4000 -/** Exit current TB to process an external interrupt request (also in op.c!!) */ -#define CPU_INTERRUPT_EXTERNAL_TIMER 0x8000 -/** Exit current TB to process an external interrupt request (also in op.c!!) */ -#define CPU_INTERRUPT_EXTERNAL_DMA 0x10000 +# define CPU_INTERRUPT_RC 0x04000000 +/** Exit current TB to process an external request. */ +# define CPU_INTERRUPT_EXTERNAL_FLUSH_TLB 0x08000000 +/** Exit current TB to process an external request. */ +# define CPU_INTERRUPT_EXTERNAL_EXIT 0x10000000 +/** Exit current TB to process an external interrupt request. */ +# define CPU_INTERRUPT_EXTERNAL_HARD 0x20000000 +/** Exit current TB to process an external timer request. */ +# define CPU_INTERRUPT_EXTERNAL_TIMER 0x40000000 +/** Exit current TB to process an external DMA request. */ +# define CPU_INTERRUPT_EXTERNAL_DMA 0x80000000 #endif /* VBOX */ void cpu_interrupt(CPUState *s, int mask); void cpu_reset_interrupt(CPUState *env, int mask); -int cpu_watchpoint_insert(CPUState *env, target_ulong addr, int type); -int cpu_watchpoint_remove(CPUState *env, target_ulong addr); -void cpu_watchpoint_remove_all(CPUState *env); -int cpu_breakpoint_insert(CPUState *env, target_ulong pc); -int cpu_breakpoint_remove(CPUState *env, target_ulong pc); -void cpu_breakpoint_remove_all(CPUState *env); +void cpu_exit(CPUState *s); + +int 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 */ @@ -1124,11 +994,8 @@ void cpu_breakpoint_remove_all(CPUState *env); void cpu_single_step(CPUState *env, int enabled); void cpu_reset(CPUState *s); - -/* 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); +int cpu_is_stopped(CPUState *env); +void run_on_cpu(CPUState *env, void (*func)(void *data), void *data); #define CPU_LOG_TB_OUT_ASM (1 << 0) #define CPU_LOG_TB_IN_ASM (1 << 1) @@ -1139,6 +1006,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 { @@ -1147,67 +1015,84 @@ 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) -/* address in the RAM (different from a physical address) */ -#ifdef USE_KQEMU -typedef uint32_t ram_addr_t; -#else -typedef unsigned long ram_addr_t; -#endif +/* 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 */ #ifndef VBOX -extern int phys_ram_size; extern int phys_ram_fd; -extern int phys_ram_size; -#else /* VBOX */ -extern RTGCPHYS phys_ram_size; -/** This is required for bounds checking the phys_ram_dirty accesses. */ -extern RTGCPHYS phys_ram_dirty_size; -#endif /* VBOX */ -#if !defined(VBOX) -extern uint8_t *phys_ram_base; +extern ram_addr_t ram_size; +#endif /* !VBOX */ + +typedef struct RAMBlock { + uint8_t *host; + ram_addr_t offset; + ram_addr_t length; + char idstr[256]; + QLIST_ENTRY(RAMBlock) next; +#if defined(__linux__) && !defined(TARGET_S390X) + int fd; #endif -extern uint8_t *phys_ram_dirty; +} RAMBlock; + +typedef struct RAMList { + uint8_t *phys_dirty; +#ifdef VBOX + /** This is required for bounds checking the phys_ram_dirty accesses. + * We have memory ranges (the high PC-BIOS mapping) which causes some pages + * to fall outside the dirty map. */ + RTGCPHYS phys_dirty_size; +#if 1 +# define VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RET(addr,rv) \ + do { \ + if (RT_UNLIKELY( ((addr) >> TARGET_PAGE_BITS) >= ram_list.phys_dirty_size)) { \ + Log(("%s: %RGp\n", __FUNCTION__, (RTGCPHYS)addr)); \ + return (rv); \ + } \ + } while (0) +# define VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RETV(addr) \ + do { \ + if (RT_UNLIKELY( ((addr) >> TARGET_PAGE_BITS) >= ram_list.phys_dirty_size)) { \ + Log(("%s: %RGp\n", __FUNCTION__, (RTGCPHYS)addr)); \ + return; \ + } \ + } while (0) +#else +# define VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RET(addr,rv) \ + AssertMsgReturn(((addr) >> TARGET_PAGE_BITS) < ram_list.phys_dirty_size, ("%#RGp\n", (RTGCPHYS)(addr)), (rv)); +# define VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RETV(addr) \ + AssertMsgReturnVoid(((addr) >> TARGET_PAGE_BITS) < ram_list.phys_dirty_size, ("%#RGp\n", (RTGCPHYS)(addr))); +# endif +#else +# define VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RET(addr,rv) do {} while() +# define VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RETV(addr) do {} while() +#endif /* VBOX */ + QLIST_HEAD(ram, RAMBlock) blocks; +} RAMList; +extern RAMList ram_list; + +extern const char *mem_path; +extern int mem_prealloc; /* physical memory access */ /* 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 available. */ + so only a limited number of ids are avaiable. */ -#define IO_MEM_SHIFT 3 #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 (3 << IO_MEM_SHIFT) - -/* Acts like a ROM when read and like a device when written. */ -#define IO_MEM_ROMD (1) -#define IO_MEM_SUBPAGE (2) -#define IO_MEM_SUBWIDTH (4) - /* 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. */ @@ -1218,121 +1103,58 @@ extern uint8_t *phys_ram_dirty; /* Set if TLB entry is an IO callback. */ #define TLB_MMIO (1 << 5) -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, - ram_addr_t size, - ram_addr_t phys_offset); -uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr); -ram_addr_t qemu_ram_alloc(ram_addr_t); -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); -#ifndef VBOX -static inline void cpu_physical_memory_read(target_phys_addr_t addr, - uint8_t *buf, int len) -#else -DECLINLINE(void) cpu_physical_memory_read(target_phys_addr_t addr, - uint8_t *buf, int len) -#endif -{ - cpu_physical_memory_rw(addr, buf, len, 0); -} -#ifndef VBOX -static inline void cpu_physical_memory_write(target_phys_addr_t addr, - const uint8_t *buf, int len) -#else -DECLINLINE(void) cpu_physical_memory_write(target_phys_addr_t addr, - const uint8_t *buf, int len) -#endif -{ - 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 -#define KQEMU_DIRTY_FLAG 0x04 +#define VGA_DIRTY_FLAG 0x01 +#define CODE_DIRTY_FLAG 0x02 #define MIGRATION_DIRTY_FLAG 0x08 /* read dirty bit (return 0 or 1) */ -#ifndef VBOX static inline int cpu_physical_memory_is_dirty(ram_addr_t addr) { - return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff; + VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RET(addr, 0); + return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] == 0xff; } -#else -DECLINLINE(int) cpu_physical_memory_is_dirty(ram_addr_t addr) + +static inline int cpu_physical_memory_get_dirty_flags(ram_addr_t addr) { - if (RT_UNLIKELY((addr >> TARGET_PAGE_BITS) >= phys_ram_dirty_size)) - { - Log(("cpu_physical_memory_is_dirty: %RGp\n", (RTGCPHYS)addr)); - /*AssertMsgFailed(("cpu_physical_memory_is_dirty: %RGp\n", (RTGCPHYS)addr));*/ - return 0; - } - return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff; + VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RET(addr, 0xff); + return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS]; } -#endif -#ifndef VBOX 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; -} -#else -DECLINLINE(int) cpu_physical_memory_get_dirty(ram_addr_t addr, - int dirty_flags) -{ - if (RT_UNLIKELY((addr >> TARGET_PAGE_BITS) >= phys_ram_dirty_size)) - { - Log(("cpu_physical_memory_is_dirty: %RGp\n", (RTGCPHYS)addr)); - /*AssertMsgFailed(("cpu_physical_memory_is_dirty: %RGp\n", (RTGCPHYS)addr));*/ - return 0xff & dirty_flags; /** @todo I don't think this is the right thing to return, fix! */ - } - return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags; + VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RET(addr, 0xff & dirty_flags); + return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags; } -#endif -#ifndef VBOX static inline void cpu_physical_memory_set_dirty(ram_addr_t addr) { - phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff; + VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RETV(addr); + ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] = 0xff; } -#else -DECLINLINE(void) cpu_physical_memory_set_dirty(ram_addr_t addr) + +static inline int cpu_physical_memory_set_dirty_flags(ram_addr_t addr, + int dirty_flags) { - if (RT_UNLIKELY((addr >> TARGET_PAGE_BITS) >= phys_ram_dirty_size)) - { - Log(("cpu_physical_memory_is_dirty: %RGp\n", (RTGCPHYS)addr)); - /*AssertMsgFailed(("cpu_physical_memory_is_dirty: %RGp\n", (RTGCPHYS)addr));*/ - return; + VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RET(addr, 0xff); + return ram_list.phys_dirty[addr >> TARGET_PAGE_BITS] |= dirty_flags; +} + +static inline void cpu_physical_memory_mask_dirty_range(ram_addr_t start, + int length, + int dirty_flags) +{ + int i, mask, len; + uint8_t *p; + + VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RETV(start); + 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; } - phys_ram_dirty[addr >> TARGET_PAGE_BITS] = 0xff; } -#endif void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t end, int dirty_flags); @@ -1342,137 +1164,18 @@ int cpu_physical_memory_set_dirty_tracking(int enable); int cpu_physical_memory_get_dirty_tracking(void); +int cpu_physical_sync_dirty_bitmap(target_phys_addr_t start_addr, + target_phys_addr_t end_addr); + void dump_exec_info(FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...)); +#endif /* !CONFIG_USER_ONLY */ -/*******************************************/ -/* host CPU ticks (if available) */ - -#ifdef VBOX -# include <iprt/asm-amd64-x86.h> - -DECLINLINE(int64_t) cpu_get_real_ticks(void) -{ - return ASMReadTSC(); -} - -#elif defined(__powerpc__) - -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) -{ - uint32_t tbl; - asm volatile("mftbu %0" : "=r" (tbl)); - return tbl; -} - -static inline int64_t cpu_get_real_ticks(void) -{ - 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; -} - -#elif defined(__i386__) - -static inline int64_t cpu_get_real_ticks(void) -{ - int64_t val; - asm volatile ("rdtsc" : "=A" (val)); - return val; -} - -#elif defined(__x86_64__) - -static inline int64_t cpu_get_real_ticks(void) -{ - uint32_t low,high; - int64_t val; - asm volatile("rdtsc" : "=a" (low), "=d" (high)); - val = high; - val <<= 32; - val |= low; - return val; -} - -#elif defined(__ia64) - -static inline int64_t cpu_get_real_ticks(void) -{ - int64_t val; - asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory"); - return val; -} - -#elif defined(__s390__) - -static inline int64_t cpu_get_real_ticks(void) -{ - int64_t val; - asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc"); - return val; -} - -#elif defined(__sparc_v9__) - -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 -} -#else -/* The host CPU doesn't have an easily accessible cycle counter. - Just return a monotonically increasing vlue. 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 - -/* profiling */ -#ifdef CONFIG_PROFILER -static inline int64_t profile_getclock(void) -{ - return cpu_get_real_ticks(); -} - -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; +int cpu_memory_rw_debug(CPUState *env, target_ulong addr, + uint8_t *buf, int len, int is_write); -#endif +void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, + uint64_t mcg_status, uint64_t addr, uint64_t misc); #ifdef VBOX void tb_invalidate_virt(CPUState *env, uint32_t eip); |