cpu-all.h revision 993c76af63e99635bda98e2fa1ff71ee842107ba
/*
* defines common to all virtual CPUs
*
* Copyright (c) 2003 Fabrice Bellard
*
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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, see <http://www.gnu.org/licenses/>.
*/
/*
* Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
* other than GPL or LGPL is available it will apply instead, Oracle elects to use only
* the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
* a choice of LGPL license versions is made available with the language indicating
* that LGPLv2 or any later version may be used, or where a choice of which version
* of the LGPL is applied is otherwise unspecified.
*/
#ifndef CPU_ALL_H
#define CPU_ALL_H
#ifdef VBOX
# ifndef LOG_GROUP
# define LOG_GROUP LOG_GROUP_REM
# 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.
*
* 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 "softfloat.h"
#if defined(HOST_WORDS_BIGENDIAN) != defined(TARGET_WORDS_BIGENDIAN)
#define BSWAP_NEEDED
#endif
#ifdef BSWAP_NEEDED
{
return bswap16(s);
}
{
return bswap32(s);
}
{
return bswap64(s);
}
{
*s = bswap16(*s);
}
{
*s = bswap32(*s);
}
{
*s = bswap64(*s);
}
#else
{
return s;
}
{
return s;
}
{
return s;
}
{
}
{
}
{
}
#endif
#if TARGET_LONG_SIZE == 4
#else
#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(HOST_WORDS_BIGENDIAN) \
struct {
} l;
#else
struct {
} l;
#endif
} CPU_DoubleU;
#ifdef TARGET_SPARC
typedef union {
float128 q;
#if defined(HOST_WORDS_BIGENDIAN) \
struct {
} l;
struct {
} ll;
#else
struct {
} l;
struct {
} ll;
#endif
} CPU_QuadU;
#endif
/* CPU memory access without any memory or io remapping */
/*
* the generic syntax for the memory accesses is:
*
* load: ld{type}{sign}{size}{endian}_{access_type}(ptr)
*
* store: st{type}{size}{endian}_{access_type}(ptr, val)
*
* type is:
* (empty): integer access
* f : float access
*
* sign is:
* (empty): for floats or 32 bit size
* u : unsigned
* s : signed
*
* size is:
* b: 8 bits
* 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)
* be : big endian (not implemented yet)
* le : little endian (not implemented yet)
*
* access_type is:
* raw : host memory access
* user : user mode access using soft MMU
* kernel : kernel mode access using soft MMU
*/
#ifdef VBOX
# ifndef REM_PHYS_ADDR_IN_TLB
# endif
#endif /* VBOX */
#if defined(VBOX) && defined(REM_PHYS_ADDR_IN_TLB)
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
{
}
/* float access */
{
union {
float32 f;
uint32_t i;
} u;
return u.f;
}
{
union {
float32 f;
uint32_t i;
} u;
u.f = v;
}
{
CPU_DoubleU u;
return u.d;
}
{
CPU_DoubleU u;
u.d = v;
}
#else /* !VBOX || !REM_PHYS_ADDR_IN_TLB */
{
}
{
}
{
}
it is a system wide setting : bad */
#if defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
/* conservative code for little endian unaligned accesses */
{
#ifdef _ARCH_PPC
int val;
return val;
#else
return p[0] | (p[1] << 8);
#endif
}
{
#ifdef _ARCH_PPC
int val;
#else
#endif
}
{
#ifdef _ARCH_PPC
int val;
return val;
#else
return p[0] | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
#endif
}
{
}
{
#ifdef _ARCH_PPC
#else
p[0] = v;
p[1] = v >> 8;
#endif
}
{
#ifdef _ARCH_PPC
#else
p[0] = v;
p[1] = v >> 8;
p[2] = v >> 16;
p[3] = v >> 24;
#endif
}
{
}
/* float access */
{
union {
float32 f;
uint32_t i;
} u;
return u.f;
}
{
union {
float32 f;
uint32_t i;
} u;
u.f = v;
}
{
CPU_DoubleU u;
return u.d;
}
{
CPU_DoubleU u;
u.d = v;
}
#else
{
}
{
}
{
}
{
}
{
}
{
}
{
}
/* float access */
{
}
{
}
{
}
{
}
#endif
#endif /* !VBOX || !REM_PHYS_ADDR_IN_TLB */
#if !defined(HOST_WORDS_BIGENDIAN) || defined(WORDS_ALIGNED)
{
#if defined(__i386__)
int val;
asm volatile ("movzwl %1, %0\n"
"xchgb %b0, %h0\n"
: "=q" (val)
return val;
#else
return ((b[0] << 8) | b[1]);
#endif
}
{
#if defined(__i386__)
int val;
asm volatile ("movzwl %1, %0\n"
"xchgb %b0, %h0\n"
: "=q" (val)
#else
#endif
}
{
#if defined(__i386__) || defined(__x86_64__)
int val;
asm volatile ("movl %1, %0\n"
"bswap %0\n"
: "=r" (val)
return val;
#else
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
#endif
}
{
uint32_t a,b;
return (((uint64_t)a<<32)|b);
}
{
#if defined(__i386__)
asm volatile ("xchgb %b0, %h0\n"
"movw %w0, %1\n"
: "=q" (v)
#else
d[0] = v >> 8;
d[1] = v;
#endif
}
{
#if defined(__i386__) || defined(__x86_64__)
asm volatile ("bswap %0\n"
"movl %0, %1\n"
: "=r" (v)
#else
d[0] = v >> 24;
d[1] = v >> 16;
d[2] = v >> 8;
d[3] = v;
#endif
}
{
}
/* float access */
{
union {
float32 f;
uint32_t i;
} u;
return u.f;
}
{
union {
float32 f;
uint32_t i;
} u;
u.f = v;
}
{
CPU_DoubleU u;
return u.d;
}
{
CPU_DoubleU u;
u.d = v;
}
#else
{
}
{
}
{
}
{
}
{
}
{
}
{
}
/* float access */
{
}
{
}
{
}
{
}
#endif
/* target CPU memory access functions */
#if defined(TARGET_WORDS_BIGENDIAN)
#else
#endif
/* 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.
*/
#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_valid(x) 1
#else
#define h2g_valid(x) ({ \
unsigned long __guest = (unsigned long)(x) - GUEST_BASE; \
})
#endif
#define h2g(x) ({ \
unsigned long __ret = (unsigned long)(x) - GUEST_BASE; \
/* Check if given address fits target address space */ \
})
#else /* !CONFIG_USER_ONLY */
/* NOTE: we use double casts if pointers and target_ulong have
different sizes */
#endif
#if defined(CONFIG_USER_ONLY)
/* if user mode, no other memory access functions */
#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)
#define stw_kernel(p, v) stw_raw(p, v)
#define stl_kernel(p, v) stl_raw(p, v)
#define stq_kernel(p, v) stq_raw(p, v)
#define stfl_kernel(p, v) stfl_raw(p, v)
#endif /* defined(CONFIG_USER_ONLY) */
/* page related stuff */
/* ??? These should be the larger of unsigned long and target_ulong. */
extern unsigned long qemu_real_host_page_size;
extern unsigned long qemu_host_page_bits;
extern unsigned long qemu_host_page_size;
extern unsigned long qemu_host_page_mask;
/* same as PROT_xxx */
#define PAGE_READ 0x0001
#define PAGE_WRITE 0x0002
#define PAGE_EXEC 0x0004
#define PAGE_VALID 0x0008
/* 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)
#define PAGE_RESERVED 0x0020
#endif
#if defined(CONFIG_USER_ONLY)
typedef int (*walk_memory_regions_fn)(void *, abi_ulong,
abi_ulong, unsigned long);
int walk_memory_regions(void *, walk_memory_regions_fn);
#endif
int flags);
int flags);
#ifndef VBOX
#else /* VBOX */
;
#endif /* VBOX */
extern CPUState *cpu_single_env;
#ifdef VBOX
/** Executes a single instruction. cpu_exec() will normally return EXCP_SINGLE_INSTR. */
# 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 0x02000000
/** VM execution was interrupted by VMR3Reset, VMR3Suspend or VMR3PowerOff. */
# 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 */
/* Breakpoint/watchpoint flags */
#define BP_MEM_READ 0x01
#define BP_MEM_WRITE 0x02
#define BP_STOP_BEFORE_ACCESS 0x04
#define BP_WATCHPOINT_HIT 0x08
#define BP_GDB 0x10
#define BP_CPU 0x20
#define CPU_LOG_TB_OUT_ASM (1 << 0)
/* define log items */
typedef struct CPULogItem {
int mask;
const char *name;
const char *help;
} CPULogItem;
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);
#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. */
/* memory API */
#ifndef VBOX
extern int phys_ram_fd;
extern ram_addr_t ram_size;
#endif /* !VBOX */
typedef struct RAMBlock {
char idstr[256];
#if defined(__linux__) && !defined(TARGET_S390X)
int fd;
#endif
} RAMBlock;
typedef struct RAMList {
#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. */
#if 1
do { \
return (rv); \
} \
} while (0)
# define VBOX_RAMLIST_DIRTY_BOUNDS_CHECK_RETV(addr) \
do { \
return; \
} \
} while (0)
#else
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_RETV(addr) do {} while()
#endif /* VBOX */
} RAMList;
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 avaiable. */
/* 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. */
/* Set if TLB entry references a clean RAM page. The iotlb entry will
contain the page physical address. */
/* Set if TLB entry is an IO callback. */
#define VGA_DIRTY_FLAG 0x01
#define CODE_DIRTY_FLAG 0x02
#define MIGRATION_DIRTY_FLAG 0x08
/* read dirty bit (return 0 or 1) */
{
}
{
}
int dirty_flags)
{
}
{
}
int dirty_flags)
{
}
int length,
int dirty_flags)
{
uint8_t *p;
mask = ~dirty_flags;
for (i = 0; i < len; i++) {
p[i] &= mask;
}
}
int dirty_flags);
int cpu_physical_memory_set_dirty_tracking(int enable);
int cpu_physical_memory_get_dirty_tracking(void);
void dump_exec_info(FILE *f,
#endif /* !CONFIG_USER_ONLY */
#ifdef VBOX
#endif /* VBOX */
#endif /* CPU_ALL_H */