#include "tcg.h"
#include "qemu-timer.h"
#include "envlist.h"
+#include "elf.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
#if defined(CONFIG_USE_GUEST_BASE)
unsigned long guest_base;
int have_guest_base;
+#if (TARGET_LONG_BITS == 32) && (HOST_LONG_BITS == 64)
+/*
+ * When running 32-on-64 we should make sure we can fit all of the possible
+ * guest address space into a contiguous chunk of virtual host memory.
+ *
+ * This way we will never overlap with our own libraries or binaries or stack
+ * or anything else that QEMU maps.
+ */
+unsigned long reserved_va = 0xf7000000;
+#else
unsigned long reserved_va;
#endif
+#endif
static void usage(void);
}
#if defined(TARGET_I386)
-int cpu_get_pic_interrupt(CPUState *env)
+int cpu_get_pic_interrupt(CPUX86State *env)
{
return -1;
}
#endif
-/* timers for rdtsc */
-
-#if 0
-
-static uint64_t emu_time;
-
-int64_t cpu_get_real_ticks(void)
-{
- return emu_time++;
-}
-
-#endif
-
#if defined(CONFIG_USE_NPTL)
/***********************************************************/
/* Helper routines for implementing atomic operations. */
Must only be called from outside cpu_arm_exec. */
static inline void start_exclusive(void)
{
- CPUState *other;
+ CPUArchState *other;
pthread_mutex_lock(&exclusive_lock);
exclusive_idle();
}
/* Wait for exclusive ops to finish, and begin cpu execution. */
-static inline void cpu_exec_start(CPUState *env)
+static inline void cpu_exec_start(CPUArchState *env)
{
pthread_mutex_lock(&exclusive_lock);
exclusive_idle();
}
/* Mark cpu as not executing, and release pending exclusive ops. */
-static inline void cpu_exec_end(CPUState *env)
+static inline void cpu_exec_end(CPUArchState *env)
{
pthread_mutex_lock(&exclusive_lock);
env->running = 0;
}
#else /* if !CONFIG_USE_NPTL */
/* These are no-ops because we are not threadsafe. */
-static inline void cpu_exec_start(CPUState *env)
+static inline void cpu_exec_start(CPUArchState *env)
{
}
-static inline void cpu_exec_end(CPUState *env)
+static inline void cpu_exec_end(CPUArchState *env)
{
}
/***********************************************************/
/* CPUX86 core interface */
-void cpu_smm_update(CPUState *env)
+void cpu_smm_update(CPUX86State *env)
{
}
#ifdef TARGET_ARM
+#define get_user_code_u32(x, gaddr, doswap) \
+ ({ abi_long __r = get_user_u32((x), (gaddr)); \
+ if (!__r && (doswap)) { \
+ (x) = bswap32(x); \
+ } \
+ __r; \
+ })
+
+#define get_user_code_u16(x, gaddr, doswap) \
+ ({ abi_long __r = get_user_u16((x), (gaddr)); \
+ if (!__r && (doswap)) { \
+ (x) = bswap16(x); \
+ } \
+ __r; \
+ })
+
/*
* See the Linux kernel's Documentation/arm/kernel_user_helpers.txt
* Input:
/* we handle the FPU emulation here, as Linux */
/* we get the opcode */
/* FIXME - what to do if get_user() fails? */
- get_user_u32(opcode, env->regs[15]);
+ get_user_code_u32(opcode, env->regs[15], env->bswap_code);
rc = EmulateAll(opcode, &ts->fpa, env);
if (rc == 0) { /* illegal instruction */
if (trapnr == EXCP_BKPT) {
if (env->thumb) {
/* FIXME - what to do if get_user() fails? */
- get_user_u16(insn, env->regs[15]);
+ get_user_code_u16(insn, env->regs[15], env->bswap_code);
n = insn & 0xff;
env->regs[15] += 2;
} else {
/* FIXME - what to do if get_user() fails? */
- get_user_u32(insn, env->regs[15]);
+ get_user_code_u32(insn, env->regs[15], env->bswap_code);
n = (insn & 0xf) | ((insn >> 4) & 0xff0);
env->regs[15] += 4;
}
} else {
if (env->thumb) {
/* FIXME - what to do if get_user() fails? */
- get_user_u16(insn, env->regs[15] - 2);
+ get_user_code_u16(insn, env->regs[15] - 2,
+ env->bswap_code);
n = insn & 0xff;
} else {
/* FIXME - what to do if get_user() fails? */
- get_user_u32(insn, env->regs[15] - 4);
+ get_user_code_u32(insn, env->regs[15] - 4,
+ env->bswap_code);
n = insn & 0xffffff;
}
}
} else if (n == ARM_NR_semihosting
|| n == ARM_NR_thumb_semihosting) {
env->regs[0] = do_arm_semihosting (env);
- } else if (n == 0 || n >= ARM_SYSCALL_BASE
- || (env->thumb && n == ARM_THUMB_SYSCALL)) {
+ } else if (n == 0 || n >= ARM_SYSCALL_BASE || env->thumb) {
/* linux syscall */
if (env->thumb || n == 0) {
n = env->regs[7];
#ifdef TARGET_UNICORE32
-void cpu_loop(CPUState *env)
+void cpu_loop(CPUUniCore32State *env)
{
int trapnr;
unsigned int n, insn;
}
}
break;
- case UC32_EXCP_TRAP:
+ case UC32_EXCP_DTRAP:
+ case UC32_EXCP_ITRAP:
info.si_signo = SIGSEGV;
info.si_errno = 0;
/* XXX: check env->error_code */
case TT_TFAULT:
case TT_DFAULT:
{
- info.si_signo = SIGSEGV;
+ info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
case TT_TFAULT:
case TT_DFAULT:
{
- info.si_signo = SIGSEGV;
+ info.si_signo = TARGET_SIGSEGV;
info.si_errno = 0;
/* XXX: check env->error_code */
info.si_code = TARGET_SEGV_MAPERR;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
+ case TT_ILL_INSN:
+ {
+ info.si_signo = TARGET_SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPC;
+ info._sifields._sigfault._addr = env->pc;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
case EXCP_DEBUG:
{
int sig;
#endif
#ifdef TARGET_PPC
-static inline uint64_t cpu_ppc_get_tb (CPUState *env)
+static inline uint64_t cpu_ppc_get_tb(CPUPPCState *env)
{
/* TO FIX */
return 0;
}
-uint64_t cpu_ppc_load_tbl (CPUState *env)
+uint64_t cpu_ppc_load_tbl(CPUPPCState *env)
{
return cpu_ppc_get_tb(env);
}
-uint32_t cpu_ppc_load_tbu (CPUState *env)
+uint32_t cpu_ppc_load_tbu(CPUPPCState *env)
{
return cpu_ppc_get_tb(env) >> 32;
}
-uint64_t cpu_ppc_load_atbl (CPUState *env)
+uint64_t cpu_ppc_load_atbl(CPUPPCState *env)
{
return cpu_ppc_get_tb(env);
}
-uint32_t cpu_ppc_load_atbu (CPUState *env)
+uint32_t cpu_ppc_load_atbu(CPUPPCState *env)
{
return cpu_ppc_get_tb(env) >> 32;
}
-uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
__attribute__ (( alias ("cpu_ppc_load_tbu") ));
-uint32_t cpu_ppc601_load_rtcl (CPUState *env)
+uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
{
return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
}
fprintf(stderr, fmt , ## __VA_ARGS__); \
cpu_dump_state(env, stderr, fprintf, 0); \
qemu_log(fmt, ## __VA_ARGS__); \
- if (logfile) \
+ if (qemu_log_enabled()) { \
log_cpu_state(env, 0); \
+ } \
} while (0)
static int do_store_exclusive(CPUPPCState *env)
{
target_siginfo_t info;
int trapnr;
- uint32_t ret;
+ target_ulong ret;
for(;;) {
cpu_exec_start(env);
queue_signal(env, info.si_signo, &info);
break;
case POWERPC_EXCP_PIT: /* Programmable interval timer IRQ */
- cpu_abort(env, "Programable interval timer interrupt "
+ cpu_abort(env, "Programmable interval timer interrupt "
"while in user mode. Aborting\n");
break;
case POWERPC_EXCP_IO: /* IO error exception */
* PPC ABI uses overflow flag in cr0 to signal an error
* in syscalls.
*/
-#if 0
- printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0],
- env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
-#endif
env->crf[0] &= ~0x1;
ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->gpr[7],
env->gpr[8], 0, 0);
- if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) {
+ if (ret == (target_ulong)(-TARGET_QEMU_ESIGRETURN)) {
/* Returning from a successful sigreturn syscall.
Avoid corrupting register state. */
break;
}
- if (ret > (uint32_t)(-515)) {
+ if (ret > (target_ulong)(-515)) {
env->crf[0] |= 0x1;
ret = -ret;
}
env->gpr[3] = ret;
-#if 0
- printf("syscall returned 0x%08x (%d)\n", ret, ret);
-#endif
break;
case POWERPC_EXCP_STCX:
if (do_store_exclusive(env)) {
}
#endif
+#ifdef TARGET_OPENRISC
+
+void cpu_loop(CPUOpenRISCState *env)
+{
+ int trapnr, gdbsig;
+
+ for (;;) {
+ trapnr = cpu_exec(env);
+ gdbsig = 0;
+
+ switch (trapnr) {
+ case EXCP_RESET:
+ qemu_log("\nReset request, exit, pc is %#x\n", env->pc);
+ exit(1);
+ break;
+ case EXCP_BUSERR:
+ qemu_log("\nBus error, exit, pc is %#x\n", env->pc);
+ gdbsig = SIGBUS;
+ break;
+ case EXCP_DPF:
+ case EXCP_IPF:
+ cpu_dump_state(env, stderr, fprintf, 0);
+ gdbsig = TARGET_SIGSEGV;
+ break;
+ case EXCP_TICK:
+ qemu_log("\nTick time interrupt pc is %#x\n", env->pc);
+ break;
+ case EXCP_ALIGN:
+ qemu_log("\nAlignment pc is %#x\n", env->pc);
+ gdbsig = SIGBUS;
+ break;
+ case EXCP_ILLEGAL:
+ qemu_log("\nIllegal instructionpc is %#x\n", env->pc);
+ gdbsig = SIGILL;
+ break;
+ case EXCP_INT:
+ qemu_log("\nExternal interruptpc is %#x\n", env->pc);
+ break;
+ case EXCP_DTLBMISS:
+ case EXCP_ITLBMISS:
+ qemu_log("\nTLB miss\n");
+ break;
+ case EXCP_RANGE:
+ qemu_log("\nRange\n");
+ gdbsig = SIGSEGV;
+ break;
+ case EXCP_SYSCALL:
+ env->pc += 4; /* 0xc00; */
+ env->gpr[11] = do_syscall(env,
+ env->gpr[11], /* return value */
+ env->gpr[3], /* r3 - r7 are params */
+ env->gpr[4],
+ env->gpr[5],
+ env->gpr[6],
+ env->gpr[7],
+ env->gpr[8], 0, 0);
+ break;
+ case EXCP_FPE:
+ qemu_log("\nFloating point error\n");
+ break;
+ case EXCP_TRAP:
+ qemu_log("\nTrap\n");
+ gdbsig = SIGTRAP;
+ break;
+ case EXCP_NR:
+ qemu_log("\nNR\n");
+ break;
+ default:
+ qemu_log("\nqemu: unhandled CPU exception %#x - aborting\n",
+ trapnr);
+ cpu_dump_state(env, stderr, fprintf, 0);
+ gdbsig = TARGET_SIGILL;
+ break;
+ }
+ if (gdbsig) {
+ gdb_handlesig(env, gdbsig);
+ if (gdbsig != TARGET_SIGTRAP) {
+ exit(1);
+ }
+ }
+
+ process_pending_signals(env);
+ }
+}
+
+#endif /* TARGET_OPENRISC */
+
#ifdef TARGET_SH4
-void cpu_loop (CPUState *env)
+void cpu_loop(CPUSH4State *env)
{
int trapnr, ret;
target_siginfo_t info;
#endif
#ifdef TARGET_CRIS
-void cpu_loop (CPUState *env)
+void cpu_loop(CPUCRISState *env)
{
int trapnr, ret;
target_siginfo_t info;
#endif
#ifdef TARGET_MICROBLAZE
-void cpu_loop (CPUState *env)
+void cpu_loop(CPUMBState *env)
{
int trapnr, ret;
target_siginfo_t info;
if (env->iflags & D_FLAG) {
env->sregs[SR_ESR] |= 1 << 12;
env->sregs[SR_PC] -= 4;
- /* FIXME: if branch was immed, replay the imm aswell. */
+ /* FIXME: if branch was immed, replay the imm as well. */
}
env->iflags &= ~(IMM_FLAG | D_FLAG);
queue_signal(env, TARGET_SIGSEGV, &info);
}
-void cpu_loop (CPUState *env)
+void cpu_loop(CPUAlphaState *env)
{
int trapnr;
target_siginfo_t info;
break;
}
/* Syscall writes 0 to V0 to bypass error check, similar
- to how this is handled internal to Linux kernel. */
- if (env->ir[IR_V0] == 0) {
- env->ir[IR_V0] = sysret;
- } else {
- env->ir[IR_V0] = (sysret < 0 ? -sysret : sysret);
- env->ir[IR_A3] = (sysret < 0);
- }
+ to how this is handled internal to Linux kernel.
+ (Ab)use trapnr temporarily as boolean indicating error. */
+ trapnr = (env->ir[IR_V0] != 0 && sysret < 0);
+ env->ir[IR_V0] = (trapnr ? -sysret : sysret);
+ env->ir[IR_A3] = trapnr;
break;
case 0x86:
/* IMB */
case EXCP_STQ_C:
do_store_exclusive(env, env->error_code, trapnr - EXCP_STL_C);
break;
+ case EXCP_INTERRUPT:
+ /* Just indicate that signals should be handled asap. */
+ break;
default:
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(env, stderr, fprintf, 0);
#endif /* TARGET_S390X */
-THREAD CPUState *thread_env;
+THREAD CPUArchState *thread_env;
void task_settid(TaskState *ts)
{
cpu_set_log(mask);
}
+static void handle_arg_log_filename(const char *arg)
+{
+ cpu_set_log_filename(arg);
+}
+
static void handle_arg_set_env(const char *arg)
{
char *r, *p, *token;
static void handle_arg_cpu(const char *arg)
{
cpu_model = strdup(arg);
- if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
+ if (cpu_model == NULL || is_help_option(cpu_model)) {
/* XXX: implement xxx_cpu_list for targets that still miss it */
#if defined(cpu_list_id)
cpu_list_id(stdout, &fprintf, "");
const char *help;
};
-struct qemu_argument arg_table[] = {
+static const struct qemu_argument arg_table[] = {
{"h", "", false, handle_arg_help,
"", "print this help"},
{"g", "QEMU_GDB", true, handle_arg_gdb,
{"s", "QEMU_STACK_SIZE", true, handle_arg_stack_size,
"size", "set the stack size to 'size' bytes"},
{"cpu", "QEMU_CPU", true, handle_arg_cpu,
- "model", "select CPU (-cpu ? for list)"},
+ "model", "select CPU (-cpu help for list)"},
{"E", "QEMU_SET_ENV", true, handle_arg_set_env,
"var=value", "sets targets environment variable (see below)"},
{"U", "QEMU_UNSET_ENV", true, handle_arg_unset_env,
#endif
{"d", "QEMU_LOG", true, handle_arg_log,
"options", "activate log"},
+ {"D", "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
+ "logfile", "override default logfile location"},
{"p", "QEMU_PAGESIZE", true, handle_arg_pagesize,
"pagesize", "set the host page size to 'pagesize'"},
{"singlestep", "QEMU_SINGLESTEP", false, handle_arg_singlestep,
static void usage(void)
{
- struct qemu_argument *arginfo;
+ const struct qemu_argument *arginfo;
int maxarglen;
int maxenvlen;
{
const char *r;
int optind;
- struct qemu_argument *arginfo;
+ const struct qemu_argument *arginfo;
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (arginfo->env == NULL) {
struct image_info info1, *info = &info1;
struct linux_binprm bprm;
TaskState *ts;
- CPUState *env;
+ CPUArchState *env;
int optind;
char **target_environ, **wrk;
char **target_argv;
int i;
int ret;
+ module_call_init(MODULE_INIT_QOM);
+
qemu_cache_utils_init(envp);
if ((envlist = envlist_create()) == NULL) {
#else
cpu_model = "24Kf";
#endif
+#elif defined TARGET_OPENRISC
+ cpu_model = "or1200";
#elif defined(TARGET_PPC)
#ifdef TARGET_PPC64
cpu_model = "970fx";
exit(1);
}
#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
- cpu_reset(env);
+ cpu_reset(ENV_GET_CPU(env));
#endif
thread_env = env;
*/
guest_base = HOST_PAGE_ALIGN(guest_base);
- if (reserved_va) {
- void *p;
- int flags;
-
- flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_NORESERVE;
- if (have_guest_base) {
- flags |= MAP_FIXED;
- }
- p = mmap((void *)guest_base, reserved_va, PROT_NONE, flags, -1, 0);
- if (p == MAP_FAILED) {
- fprintf(stderr, "Unable to reserve guest address space\n");
+ if (reserved_va || have_guest_base) {
+ guest_base = init_guest_space(guest_base, reserved_va, 0,
+ have_guest_base);
+ if (guest_base == (unsigned long)-1) {
+ fprintf(stderr, "Unable to reserve 0x%lx bytes of virtual address "
+ "space for use as guest address space (check your virtual "
+ "memory ulimit setting or reserve less using -R option)\n",
+ reserved_va);
exit(1);
}
- guest_base = (unsigned long)p;
- /* Make sure the address is properly aligned. */
- if (guest_base & ~qemu_host_page_mask) {
- munmap(p, reserved_va);
- p = mmap((void *)guest_base, reserved_va + qemu_host_page_size,
- PROT_NONE, flags, -1, 0);
- if (p == MAP_FAILED) {
- fprintf(stderr, "Unable to reserve guest address space\n");
- exit(1);
- }
- guest_base = HOST_PAGE_ALIGN((unsigned long)p);
- }
- qemu_log("Reserved 0x%lx bytes of guest address space\n", reserved_va);
- }
- if (reserved_va || have_guest_base) {
- if (!guest_validate_base(guest_base)) {
- fprintf(stderr, "Guest base/Reserved VA rejected by guest code\n");
- exit(1);
+ if (reserved_va) {
+ mmap_next_start = reserved_va;
}
}
#endif /* CONFIG_USE_GUEST_BASE */
_exit(1);
}
- for (i = 0; i < target_argc; i++) {
- free(target_argv[i]);
- }
- free(target_argv);
-
for (wrk = target_environ; *wrk; wrk++) {
free(*wrk);
}
for(i = 0; i < 16; i++) {
env->regs[i] = regs->uregs[i];
}
+ /* Enable BE8. */
+ if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
+ && (info->elf_flags & EF_ARM_BE8)) {
+ env->bswap_code = 1;
+ }
}
#elif defined(TARGET_UNICORE32)
{
env->hflags |= MIPS_HFLAG_M16;
}
}
+#elif defined(TARGET_OPENRISC)
+ {
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ env->gpr[i] = regs->gpr[i];
+ }
+
+ env->sr = regs->sr;
+ env->pc = regs->pc;
+ }
#elif defined(TARGET_SH4)
{
int i;