* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
#include "qemu.h"
#include "qemu-common.h"
+#include "cache-utils.h"
/* For tb_lock */
#include "exec-all.h"
+
+#include "envlist.h"
+
#define DEBUG_LOGFILE "/tmp/qemu.log"
-static const char *interp_prefix = CONFIG_QEMU_PREFIX;
-const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
+char *exec_path;
-#if defined(__i386__) && !defined(CONFIG_STATIC)
-/* Force usage of an ELF interpreter even if it is an ELF shared
- object ! */
-const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
+int singlestep;
+#if defined(CONFIG_USE_GUEST_BASE)
+unsigned long mmap_min_addr;
+unsigned long guest_base;
+int have_guest_base;
#endif
-/* for recent libc, we add these dummy symbols which are not declared
- when generating a linked object (bug in ld ?) */
-#if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(CONFIG_STATIC)
-asm(".globl __preinit_array_start\n"
- ".globl __preinit_array_end\n"
- ".globl __init_array_start\n"
- ".globl __init_array_end\n"
- ".globl __fini_array_start\n"
- ".globl __fini_array_end\n"
- ".section \".rodata\"\n"
- "__preinit_array_start:\n"
- "__preinit_array_end:\n"
- "__init_array_start:\n"
- "__init_array_end:\n"
- "__fini_array_start:\n"
- "__fini_array_end:\n"
- ".long 0\n"
- ".previous\n");
-#endif
+static const char *interp_prefix = CONFIG_QEMU_PREFIX;
+const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
va_end(ap);
}
-void cpu_outb(CPUState *env, int addr, int val)
-{
- fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
-}
-
-void cpu_outw(CPUState *env, int addr, int val)
-{
- fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
-}
-
-void cpu_outl(CPUState *env, int addr, int val)
-{
- fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
-}
-
-int cpu_inb(CPUState *env, int addr)
-{
- fprintf(stderr, "inb: port=0x%04x\n", addr);
- return 0;
-}
-
-int cpu_inw(CPUState *env, int addr)
-{
- fprintf(stderr, "inw: port=0x%04x\n", addr);
- return 0;
-}
-
-int cpu_inl(CPUState *env, int addr)
-{
- fprintf(stderr, "inl: port=0x%04x\n", addr);
- return 0;
-}
-
#if defined(TARGET_I386)
int cpu_get_pic_interrupt(CPUState *env)
{
#endif
-#if defined(USE_NPTL)
+#if defined(CONFIG_USE_NPTL)
/***********************************************************/
/* Helper routines for implementing atomic operations. */
We don't require a full sync, only that no cpus are executing guest code.
The alternative is to map target atomic ops onto host equivalents,
which requires quite a lot of per host/target work. */
+static pthread_mutex_t cpu_list_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t exclusive_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t exclusive_cond = PTHREAD_COND_INITIALIZER;
static pthread_cond_t exclusive_resume = PTHREAD_COND_INITIALIZER;
thread_env->next_cpu = NULL;
pending_cpus = 0;
pthread_mutex_init(&exclusive_lock, NULL);
+ pthread_mutex_init(&cpu_list_mutex, NULL);
pthread_cond_init(&exclusive_cond, NULL);
pthread_cond_init(&exclusive_resume, NULL);
pthread_mutex_init(&tb_lock, NULL);
+ gdbserver_fork(thread_env);
} else {
pthread_mutex_unlock(&exclusive_lock);
pthread_mutex_unlock(&tb_lock);
for (other = first_cpu; other; other = other->next_cpu) {
if (other->running) {
pending_cpus++;
- cpu_interrupt(other, CPU_INTERRUPT_EXIT);
+ cpu_exit(other);
}
}
if (pending_cpus > 1) {
exclusive_idle();
pthread_mutex_unlock(&exclusive_lock);
}
-#else /* if !USE_NPTL */
+
+void cpu_list_lock(void)
+{
+ pthread_mutex_lock(&cpu_list_mutex);
+}
+
+void cpu_list_unlock(void)
+{
+ pthread_mutex_unlock(&cpu_list_mutex);
+}
+#else /* if !CONFIG_USE_NPTL */
/* These are no-ops because we are not threadsafe. */
static inline void cpu_exec_start(CPUState *env)
{
}
void fork_end(int child)
+{
+ if (child) {
+ gdbserver_fork(thread_env);
+ }
+}
+
+void cpu_list_lock(void)
+{
+}
+
+void cpu_list_unlock(void)
{
}
#endif
p[1] = tswap32(e2);
}
-#if TARGET_X86_64
-uint64_t idt_table[512];
-
+static uint64_t *idt_table;
+#ifdef TARGET_X86_64
static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
uint64_t addr, unsigned int sel)
{
set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
}
#else
-uint64_t idt_table[256];
-
static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
uint32_t addr, unsigned int sel)
{
queue_signal(env, info.si_signo, &info);
}
break;
- case EXCP01_SSTP:
+ case EXCP01_DB:
case EXCP03_INT3:
#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
{
info.si_signo = SIGTRAP;
info.si_errno = 0;
- if (trapnr == EXCP01_SSTP) {
+ if (trapnr == EXCP01_DB) {
info.si_code = TARGET_TRAP_BRKPT;
info._sifields._sigfault._addr = env->eip;
} else {
#ifdef TARGET_ARM
-/* XXX: find a better solution */
-extern void tb_invalidate_page_range(abi_ulong start, abi_ulong end);
-
static void arm_cache_flush(abi_ulong start, abi_ulong last)
{
abi_ulong addr, last1;
return 0;
}
+static int do_strex(CPUARMState *env)
+{
+ uint32_t val;
+ int size;
+ int rc = 1;
+ int segv = 0;
+ uint32_t addr;
+ start_exclusive();
+ addr = env->exclusive_addr;
+ if (addr != env->exclusive_test) {
+ goto fail;
+ }
+ size = env->exclusive_info & 0xf;
+ switch (size) {
+ case 0:
+ segv = get_user_u8(val, addr);
+ break;
+ case 1:
+ segv = get_user_u16(val, addr);
+ break;
+ case 2:
+ case 3:
+ segv = get_user_u32(val, addr);
+ break;
+ }
+ if (segv) {
+ env->cp15.c6_data = addr;
+ goto done;
+ }
+ if (val != env->exclusive_val) {
+ goto fail;
+ }
+ if (size == 3) {
+ segv = get_user_u32(val, addr + 4);
+ if (segv) {
+ env->cp15.c6_data = addr + 4;
+ goto done;
+ }
+ if (val != env->exclusive_high) {
+ goto fail;
+ }
+ }
+ val = env->regs[(env->exclusive_info >> 8) & 0xf];
+ switch (size) {
+ case 0:
+ segv = put_user_u8(val, addr);
+ break;
+ case 1:
+ segv = put_user_u16(val, addr);
+ break;
+ case 2:
+ case 3:
+ segv = put_user_u32(val, addr);
+ break;
+ }
+ if (segv) {
+ env->cp15.c6_data = addr;
+ goto done;
+ }
+ if (size == 3) {
+ val = env->regs[(env->exclusive_info >> 12) & 0xf];
+ segv = put_user_u32(val, addr);
+ if (segv) {
+ env->cp15.c6_data = addr + 4;
+ goto done;
+ }
+ }
+ rc = 0;
+fail:
+ env->regs[15] += 4;
+ env->regs[(env->exclusive_info >> 4) & 0xf] = rc;
+done:
+ end_exclusive();
+ return segv;
+}
+
void cpu_loop(CPUARMState *env)
{
int trapnr;
if (do_kernel_trap(env))
goto error;
break;
+ case EXCP_STREX:
+ if (do_strex(env)) {
+ addr = env->cp15.c6_data;
+ goto do_segv;
+ }
+ break;
default:
error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
#endif
#ifdef TARGET_SPARC
+#define SPARC64_STACK_BIAS 2047
//#define DEBUG_WIN
abi_ulong sp_ptr;
sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#ifdef TARGET_SPARC64
+ if (sp_ptr & 3)
+ sp_ptr += SPARC64_STACK_BIAS;
+#endif
#if defined(DEBUG_WIN)
printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
sp_ptr, cwp1);
static void restore_window(CPUSPARCState *env)
{
- unsigned int new_wim, i, cwp1;
+#ifndef TARGET_SPARC64
+ unsigned int new_wim;
+#endif
+ unsigned int i, cwp1;
abi_ulong sp_ptr;
+#ifndef TARGET_SPARC64
new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
((1LL << env->nwindows) - 1);
+#endif
/* restore the invalid window */
cwp1 = cpu_cwp_inc(env, env->cwp + 1);
sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
+#ifdef TARGET_SPARC64
+ if (sp_ptr & 3)
+ sp_ptr += SPARC64_STACK_BIAS;
+#endif
#if defined(DEBUG_WIN)
printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
sp_ptr, cwp1);
get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
sp_ptr += sizeof(abi_ulong);
}
- env->wim = new_wim;
#ifdef TARGET_SPARC64
env->canrestore++;
if (env->cleanwin < env->nwindows - 1)
env->cleanwin++;
env->cansave--;
+#else
+ env->wim = new_wim;
#endif
}
for(;;) {
/* if restore would invoke restore_window(), then we can stop */
cwp1 = cpu_cwp_inc(env, env->cwp + offset);
+#ifndef TARGET_SPARC64
if (env->wim & (1 << cwp1))
break;
+#else
+ if (env->canrestore == 0)
+ break;
+ env->cansave++;
+ env->canrestore--;
+#endif
save_window_offset(env, cwp1);
offset++;
}
- /* set wim so that restore will reload the registers */
cwp1 = cpu_cwp_inc(env, env->cwp + 1);
+#ifndef TARGET_SPARC64
+ /* set wim so that restore will reload the registers */
env->wim = 1 << cwp1;
+#endif
#if defined(DEBUG_WIN)
printf("flush_windows: nb=%d\n", offset - 1);
#endif
if (trapnr == TT_DFAULT)
info._sifields._sigfault._addr = env->dmmuregs[4];
else
- info._sifields._sigfault._addr = env->tsptr->tpc;
+ info._sifields._sigfault._addr = cpu_tsptr(env)->tpc;
queue_signal(env, info.si_signo, &info);
}
break;
return -1;
}
-#define EXCP_DUMP(env, fmt, args...) \
-do { \
- fprintf(stderr, fmt , ##args); \
- cpu_dump_state(env, stderr, fprintf, 0); \
- if (loglevel != 0) { \
- fprintf(logfile, fmt , ##args); \
- cpu_dump_state(env, logfile, fprintf, 0); \
- } \
+#define EXCP_DUMP(env, fmt, ...) \
+do { \
+ fprintf(stderr, fmt , ## __VA_ARGS__); \
+ cpu_dump_state(env, stderr, fprintf, 0); \
+ qemu_log(fmt, ## __VA_ARGS__); \
+ if (logfile) \
+ log_cpu_state(env, 0); \
} while (0)
+static int do_store_exclusive(CPUPPCState *env)
+{
+ target_ulong addr;
+ target_ulong page_addr;
+ target_ulong val;
+ int flags;
+ int segv = 0;
+
+ addr = env->reserve_ea;
+ page_addr = addr & TARGET_PAGE_MASK;
+ start_exclusive();
+ mmap_lock();
+ flags = page_get_flags(page_addr);
+ if ((flags & PAGE_READ) == 0) {
+ segv = 1;
+ } else {
+ int reg = env->reserve_info & 0x1f;
+ int size = (env->reserve_info >> 5) & 0xf;
+ int stored = 0;
+
+ if (addr == env->reserve_addr) {
+ switch (size) {
+ case 1: segv = get_user_u8(val, addr); break;
+ case 2: segv = get_user_u16(val, addr); break;
+ case 4: segv = get_user_u32(val, addr); break;
+#if defined(TARGET_PPC64)
+ case 8: segv = get_user_u64(val, addr); break;
+#endif
+ default: abort();
+ }
+ if (!segv && val == env->reserve_val) {
+ val = env->gpr[reg];
+ switch (size) {
+ case 1: segv = put_user_u8(val, addr); break;
+ case 2: segv = put_user_u16(val, addr); break;
+ case 4: segv = put_user_u32(val, addr); break;
+#if defined(TARGET_PPC64)
+ case 8: segv = put_user_u64(val, addr); break;
+#endif
+ default: abort();
+ }
+ if (!segv) {
+ stored = 1;
+ }
+ }
+ }
+ env->crf[0] = (stored << 1) | xer_so;
+ env->reserve_addr = (target_ulong)-1;
+ }
+ if (!segv) {
+ env->nip += 4;
+ }
+ mmap_unlock();
+ end_exclusive();
+ return segv;
+}
+
void cpu_loop(CPUPPCState *env)
{
target_siginfo_t info;
uint32_t ret;
for(;;) {
+ cpu_exec_start(env);
trapnr = cpu_ppc_exec(env);
+ cpu_exec_end(env);
switch(trapnr) {
case POWERPC_EXCP_NONE:
/* Just go on */
"Aborting\n");
break;
case POWERPC_EXCP_DSI: /* Data storage exception */
- EXCP_DUMP(env, "Invalid data memory access: 0x" ADDRX "\n",
+ EXCP_DUMP(env, "Invalid data memory access: 0x" TARGET_FMT_lx "\n",
env->spr[SPR_DAR]);
/* XXX: check this. Seems bugged */
switch (env->error_code & 0xFF000000) {
queue_signal(env, info.si_signo, &info);
break;
case POWERPC_EXCP_ISI: /* Instruction storage exception */
- EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" ADDRX "\n",
- env->spr[SPR_SRR0]);
+ EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" TARGET_FMT_lx
+ "\n", env->spr[SPR_SRR0]);
/* XXX: check this */
switch (env->error_code & 0xFF000000) {
case 0x40000000:
cpu_abort(env, "Instruction TLB exception while in user mode. "
"Aborting\n");
break;
- case POWERPC_EXCP_DEBUG: /* Debug interrupt */
- /* XXX: check this */
- {
- int sig;
-
- sig = gdb_handlesig(env, TARGET_SIGTRAP);
- if (sig) {
- info.si_signo = sig;
- info.si_errno = 0;
- info.si_code = TARGET_TRAP_BRKPT;
- queue_signal(env, info.si_signo, &info);
- }
- }
- break;
case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavail. */
EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
info.si_signo = TARGET_SIGILL;
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]);
+ if (ret == (uint32_t)(-TARGET_QEMU_ESIGRETURN)) {
+ /* Returning from a successful sigreturn syscall.
+ Avoid corrupting register state. */
+ break;
+ }
if (ret > (uint32_t)(-515)) {
env->crf[0] |= 0x1;
ret = -ret;
printf("syscall returned 0x%08x (%d)\n", ret, ret);
#endif
break;
+ case POWERPC_EXCP_STCX:
+ if (do_store_exclusive(env)) {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->nip;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig(env, TARGET_SIGTRAP);
+ if (sig) {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, &info);
+ }
+ }
+ break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
MIPS_SYS(sys_ipc , 6)
MIPS_SYS(sys_fsync , 1)
MIPS_SYS(sys_sigreturn , 0)
- MIPS_SYS(sys_clone , 0) /* 4120 */
+ MIPS_SYS(sys_clone , 6) /* 4120 */
MIPS_SYS(sys_setdomainname, 2)
MIPS_SYS(sys_newuname , 1)
MIPS_SYS(sys_ni_syscall , 0) /* sys_modify_ldt */
#undef MIPS_SYS
+static int do_store_exclusive(CPUMIPSState *env)
+{
+ target_ulong addr;
+ target_ulong page_addr;
+ target_ulong val;
+ int flags;
+ int segv = 0;
+ int reg;
+ int d;
+
+ addr = env->lladdr;
+ page_addr = addr & TARGET_PAGE_MASK;
+ start_exclusive();
+ mmap_lock();
+ flags = page_get_flags(page_addr);
+ if ((flags & PAGE_READ) == 0) {
+ segv = 1;
+ } else {
+ reg = env->llreg & 0x1f;
+ d = (env->llreg & 0x20) != 0;
+ if (d) {
+ segv = get_user_s64(val, addr);
+ } else {
+ segv = get_user_s32(val, addr);
+ }
+ if (!segv) {
+ if (val != env->llval) {
+ env->active_tc.gpr[reg] = 0;
+ } else {
+ if (d) {
+ segv = put_user_u64(env->llnewval, addr);
+ } else {
+ segv = put_user_u32(env->llnewval, addr);
+ }
+ if (!segv) {
+ env->active_tc.gpr[reg] = 1;
+ }
+ }
+ }
+ }
+ env->lladdr = -1;
+ if (!segv) {
+ env->active_tc.PC += 4;
+ }
+ mmap_unlock();
+ end_exclusive();
+ return segv;
+}
+
void cpu_loop(CPUMIPSState *env)
{
target_siginfo_t info;
unsigned int syscall_num;
for(;;) {
+ cpu_exec_start(env);
trapnr = cpu_mips_exec(env);
+ cpu_exec_end(env);
switch(trapnr) {
case EXCP_SYSCALL:
syscall_num = env->active_tc.gpr[2] - 4000;
env->active_tc.gpr[7],
arg5, arg6/*, arg7, arg8*/);
}
+ if (ret == -TARGET_QEMU_ESIGRETURN) {
+ /* Returning from a successful sigreturn syscall.
+ Avoid clobbering register state. */
+ break;
+ }
if ((unsigned int)ret >= (unsigned int)(-1133)) {
env->active_tc.gpr[7] = 1; /* error flag */
ret = -ret;
break;
case EXCP_TLBL:
case EXCP_TLBS:
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->CP0_BadVAddr;
+ queue_signal(env, info.si_signo, &info);
+ break;
case EXCP_CpU:
case EXCP_RI:
info.si_signo = TARGET_SIGILL;
}
}
break;
+ case EXCP_SC:
+ if (do_store_exclusive(env)) {
+ info.si_signo = TARGET_SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = env->active_tc.PC;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
default:
// error:
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
switch (trapnr) {
case 0x160:
+ env->pc += 2;
ret = do_syscall(env,
env->gregs[3],
env->gregs[4],
env->gregs[0],
env->gregs[1]);
env->gregs[0] = ret;
- env->pc += 2;
break;
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
env->pregs[7],
env->pregs[11]);
env->regs[10] = ret;
- env->pc += 2;
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(env, info.si_signo, &info);
+ }
+ }
+ break;
+ default:
+ printf ("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(env, stderr, fprintf, 0);
+ exit (1);
+ }
+ process_pending_signals (env);
+ }
+}
+#endif
+
+#ifdef TARGET_MICROBLAZE
+void cpu_loop (CPUState *env)
+{
+ int trapnr, ret;
+ target_siginfo_t info;
+
+ while (1) {
+ trapnr = cpu_mb_exec (env);
+ switch (trapnr) {
+ case 0xaa:
+ {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* XXX: check env->error_code */
+ info.si_code = TARGET_SEGV_MAPERR;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_BREAK:
+ /* Return address is 4 bytes after the call. */
+ env->regs[14] += 4;
+ ret = do_syscall(env,
+ env->regs[12],
+ env->regs[5],
+ env->regs[6],
+ env->regs[7],
+ env->regs[8],
+ env->regs[9],
+ env->regs[10]);
+ env->regs[3] = ret;
+ env->sregs[SR_PC] = env->regs[14];
break;
case EXCP_DEBUG:
{
exit(1);
break;
case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1):
- fprintf(stderr, "Call to PALcode\n");
call_pal(env, (trapnr >> 6) | 0x80);
break;
case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1):
static void usage(void)
{
- printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
+ printf("qemu-" TARGET_ARCH " version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
"usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
"Linux CPU emulator (compiled for %s emulation)\n"
"\n"
"-s size set the stack size in bytes (default=%ld)\n"
"-cpu model select CPU (-cpu ? for list)\n"
"-drop-ld-preload drop LD_PRELOAD for target process\n"
+ "-E var=value sets/modifies targets environment variable(s)\n"
+ "-U var unsets targets environment variable(s)\n"
+ "-0 argv0 forces target process argv[0] to be argv0\n"
+#if defined(CONFIG_USE_GUEST_BASE)
+ "-B address set guest_base address to address\n"
+#endif
"\n"
"Debug options:\n"
"-d options activate log (logfile=%s)\n"
"-p pagesize set the host page size to 'pagesize'\n"
+ "-singlestep always run in singlestep mode\n"
"-strace log system calls\n"
"\n"
"Environment variables:\n"
"QEMU_STRACE Print system calls and arguments similar to the\n"
" 'strace' program. Enable by setting to any value.\n"
+ "You can use -E and -U options to set/unset environment variables\n"
+ "for target process. It is possible to provide several variables\n"
+ "by repeating the option. For example:\n"
+ " -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
+ "Note that if you provide several changes to single variable\n"
+ "last change will stay in effect.\n"
,
TARGET_ARCH,
interp_prefix,
x86_stack_size,
DEBUG_LOGFILE);
- _exit(1);
+ exit(1);
}
THREAD CPUState *thread_env;
+void task_settid(TaskState *ts)
+{
+ if (ts->ts_tid == 0) {
+#ifdef CONFIG_USE_NPTL
+ ts->ts_tid = (pid_t)syscall(SYS_gettid);
+#else
+ /* when no threads are used, tid becomes pid */
+ ts->ts_tid = getpid();
+#endif
+ }
+}
+
+void stop_all_tasks(void)
+{
+ /*
+ * We trust that when using NPTL, start_exclusive()
+ * handles thread stopping correctly.
+ */
+ start_exclusive();
+}
+
/* Assumes contents are already zeroed. */
void init_task_state(TaskState *ts)
{
ts->sigqueue_table[i].next = NULL;
}
-int main(int argc, char **argv)
+int main(int argc, char **argv, char **envp)
{
const char *filename;
const char *cpu_model;
struct target_pt_regs regs1, *regs = ®s1;
struct image_info info1, *info = &info1;
+ struct linux_binprm bprm;
TaskState ts1, *ts = &ts1;
CPUState *env;
int optind;
const char *r;
int gdbstub_port = 0;
- int drop_ld_preload = 0, environ_count = 0;
- char **target_environ, **wrk, **dst;
+ char **target_environ, **wrk;
+ char **target_argv;
+ int target_argc;
+ envlist_t *envlist = NULL;
+ const char *argv0 = NULL;
+ int i;
+ int ret;
if (argc <= 1)
usage();
+ qemu_cache_utils_init(envp);
+
/* init debug */
cpu_set_log_filename(DEBUG_LOGFILE);
+ if ((envlist = envlist_create()) == NULL) {
+ (void) fprintf(stderr, "Unable to allocate envlist\n");
+ exit(1);
+ }
+
+ /* add current environment into the list */
+ for (wrk = environ; *wrk != NULL; wrk++) {
+ (void) envlist_setenv(envlist, *wrk);
+ }
+
cpu_model = NULL;
optind = 1;
for(;;) {
break;
} else if (!strcmp(r, "d")) {
int mask;
- CPULogItem *item;
+ const CPULogItem *item;
if (optind >= argc)
break;
exit(1);
}
cpu_set_log(mask);
+ } else if (!strcmp(r, "E")) {
+ r = argv[optind++];
+ if (envlist_setenv(envlist, r) != 0)
+ usage();
+ } else if (!strcmp(r, "U")) {
+ r = argv[optind++];
+ if (envlist_unsetenv(envlist, r) != 0)
+ usage();
+ } else if (!strcmp(r, "0")) {
+ r = argv[optind++];
+ argv0 = r;
} else if (!strcmp(r, "s")) {
+ if (optind >= argc)
+ break;
r = argv[optind++];
x86_stack_size = strtol(r, (char **)&r, 0);
if (x86_stack_size <= 0)
} else if (!strcmp(r, "L")) {
interp_prefix = argv[optind++];
} else if (!strcmp(r, "p")) {
+ if (optind >= argc)
+ break;
qemu_host_page_size = atoi(argv[optind++]);
if (qemu_host_page_size == 0 ||
(qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
exit(1);
}
} else if (!strcmp(r, "g")) {
+ if (optind >= argc)
+ break;
gdbstub_port = atoi(argv[optind++]);
} else if (!strcmp(r, "r")) {
qemu_uname_release = argv[optind++];
} else if (!strcmp(r, "cpu")) {
cpu_model = argv[optind++];
- if (strcmp(cpu_model, "?") == 0) {
+ if (cpu_model == NULL || strcmp(cpu_model, "?") == 0) {
/* XXX: implement xxx_cpu_list for targets that still miss it */
#if defined(cpu_list)
cpu_list(stdout, &fprintf);
#endif
- _exit(1);
+ exit(1);
}
+#if defined(CONFIG_USE_GUEST_BASE)
+ } else if (!strcmp(r, "B")) {
+ guest_base = strtol(argv[optind++], NULL, 0);
+ have_guest_base = 1;
+#endif
} else if (!strcmp(r, "drop-ld-preload")) {
- drop_ld_preload = 1;
+ (void) envlist_unsetenv(envlist, "LD_PRELOAD");
+ } else if (!strcmp(r, "singlestep")) {
+ singlestep = 1;
} else if (!strcmp(r, "strace")) {
do_strace = 1;
} else
if (optind >= argc)
usage();
filename = argv[optind];
+ exec_path = argv[optind];
/* Zero out regs */
memset(regs, 0, sizeof(struct target_pt_regs));
/* Zero out image_info */
memset(info, 0, sizeof(struct image_info));
+ memset(&bprm, 0, sizeof (bprm));
+
/* Scan interp_prefix dir for replacement files. */
init_paths(interp_prefix);
cpu_model = "qemu32";
#endif
#elif defined(TARGET_ARM)
- cpu_model = "arm926";
+ cpu_model = "any";
#elif defined(TARGET_M68K)
cpu_model = "any";
#elif defined(TARGET_SPARC)
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
+#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
+ cpu_reset(env);
+#endif
+
thread_env = env;
if (getenv("QEMU_STRACE")) {
do_strace = 1;
}
- wrk = environ;
- while (*(wrk++))
- environ_count++;
-
- target_environ = malloc((environ_count + 1) * sizeof(char *));
- if (!target_environ)
- abort();
- for (wrk = environ, dst = target_environ; *wrk; wrk++) {
- if (drop_ld_preload && !strncmp(*wrk, "LD_PRELOAD=", 11))
- continue;
- *(dst++) = strdup(*wrk);
+ target_environ = envlist_to_environ(envlist, NULL);
+ envlist_free(envlist);
+
+#if defined(CONFIG_USE_GUEST_BASE)
+ /*
+ * Now that page sizes are configured in cpu_init() we can do
+ * proper page alignment for guest_base.
+ */
+ guest_base = HOST_PAGE_ALIGN(guest_base);
+
+ /*
+ * Read in mmap_min_addr kernel parameter. This value is used
+ * When loading the ELF image to determine whether guest_base
+ * is needed.
+ *
+ * When user has explicitly set the quest base, we skip this
+ * test.
+ */
+ if (!have_guest_base) {
+ FILE *fp;
+
+ if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
+ unsigned long tmp;
+ if (fscanf(fp, "%lu", &tmp) == 1) {
+ mmap_min_addr = tmp;
+ qemu_log("host mmap_min_addr=0x%lx\n", mmap_min_addr);
+ }
+ fclose(fp);
+ }
+ }
+#endif /* CONFIG_USE_GUEST_BASE */
+
+ /*
+ * Prepare copy of argv vector for target.
+ */
+ target_argc = argc - optind;
+ target_argv = calloc(target_argc + 1, sizeof (char *));
+ if (target_argv == NULL) {
+ (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
+ exit(1);
+ }
+
+ /*
+ * If argv0 is specified (using '-0' switch) we replace
+ * argv[0] pointer with the given one.
+ */
+ i = 0;
+ if (argv0 != NULL) {
+ target_argv[i++] = strdup(argv0);
}
- *dst = NULL; /* NULL terminate target_environ */
+ for (; i < target_argc; i++) {
+ target_argv[i] = strdup(argv[optind + i]);
+ }
+ target_argv[target_argc] = NULL;
+
+ memset(ts, 0, sizeof(TaskState));
+ init_task_state(ts);
+ /* build Task State */
+ ts->info = info;
+ ts->bprm = &bprm;
+ env->opaque = ts;
+ task_settid(ts);
- if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
- printf("Error loading %s\n", filename);
+ ret = loader_exec(filename, target_argv, target_environ, regs,
+ info, &bprm);
+ if (ret != 0) {
+ printf("Error %d while loading %s\n", ret, filename);
_exit(1);
}
+ for (i = 0; i < target_argc; i++) {
+ free(target_argv[i]);
+ }
+ free(target_argv);
+
for (wrk = target_environ; *wrk; wrk++) {
free(*wrk);
}
free(target_environ);
- if (loglevel) {
- page_dump(logfile);
-
- fprintf(logfile, "start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
- fprintf(logfile, "end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code);
- fprintf(logfile, "start_code 0x" TARGET_ABI_FMT_lx "\n",
- info->start_code);
- fprintf(logfile, "start_data 0x" TARGET_ABI_FMT_lx "\n",
- info->start_data);
- fprintf(logfile, "end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data);
- fprintf(logfile, "start_stack 0x" TARGET_ABI_FMT_lx "\n",
- info->start_stack);
- fprintf(logfile, "brk 0x" TARGET_ABI_FMT_lx "\n", info->brk);
- fprintf(logfile, "entry 0x" TARGET_ABI_FMT_lx "\n", info->entry);
+ if (qemu_log_enabled()) {
+#if defined(CONFIG_USE_GUEST_BASE)
+ qemu_log("guest_base 0x%lx\n", guest_base);
+#endif
+ log_page_dump();
+
+ qemu_log("start_brk 0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
+ qemu_log("end_code 0x" TARGET_ABI_FMT_lx "\n", info->end_code);
+ qemu_log("start_code 0x" TARGET_ABI_FMT_lx "\n",
+ info->start_code);
+ qemu_log("start_data 0x" TARGET_ABI_FMT_lx "\n",
+ info->start_data);
+ qemu_log("end_data 0x" TARGET_ABI_FMT_lx "\n", info->end_data);
+ qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
+ info->start_stack);
+ qemu_log("brk 0x" TARGET_ABI_FMT_lx "\n", info->brk);
+ qemu_log("entry 0x" TARGET_ABI_FMT_lx "\n", info->entry);
}
target_set_brk(info->brk);
syscall_init();
signal_init();
- /* build Task State */
- memset(ts, 0, sizeof(TaskState));
- init_task_state(ts);
- ts->info = info;
- env->opaque = ts;
- env->user_mode_only = 1;
-
#if defined(TARGET_I386)
cpu_x86_set_cpl(env, 3);
#endif
/* linux interrupt setup */
- env->idt.base = h2g(idt_table);
- env->idt.limit = sizeof(idt_table) - 1;
+#ifndef TARGET_ABI32
+ env->idt.limit = 511;
+#else
+ env->idt.limit = 255;
+#endif
+ env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
+ idt_table = g2h(env->idt.base);
set_idt(0, 0);
set_idt(1, 0);
set_idt(2, 0);
/* linux segment setup */
{
uint64_t *gdt_table;
- gdt_table = qemu_mallocz(sizeof(uint64_t) * TARGET_GDT_ENTRIES);
- env->gdt.base = h2g((unsigned long)gdt_table);
+ env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
+ PROT_READ|PROT_WRITE,
+ MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
+ gdt_table = g2h(env->gdt.base);
#ifdef TARGET_ABI32
write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
env->sr = regs->sr;
ts->sim_syscalls = 1;
}
+#elif defined(TARGET_MICROBLAZE)
+ {
+ env->regs[0] = regs->r0;
+ env->regs[1] = regs->r1;
+ env->regs[2] = regs->r2;
+ env->regs[3] = regs->r3;
+ env->regs[4] = regs->r4;
+ env->regs[5] = regs->r5;
+ env->regs[6] = regs->r6;
+ env->regs[7] = regs->r7;
+ env->regs[8] = regs->r8;
+ env->regs[9] = regs->r9;
+ env->regs[10] = regs->r10;
+ env->regs[11] = regs->r11;
+ env->regs[12] = regs->r12;
+ env->regs[13] = regs->r13;
+ env->regs[14] = regs->r14;
+ env->regs[15] = regs->r15;
+ env->regs[16] = regs->r16;
+ env->regs[17] = regs->r17;
+ env->regs[18] = regs->r18;
+ env->regs[19] = regs->r19;
+ env->regs[20] = regs->r20;
+ env->regs[21] = regs->r21;
+ env->regs[22] = regs->r22;
+ env->regs[23] = regs->r23;
+ env->regs[24] = regs->r24;
+ env->regs[25] = regs->r25;
+ env->regs[26] = regs->r26;
+ env->regs[27] = regs->r27;
+ env->regs[28] = regs->r28;
+ env->regs[29] = regs->r29;
+ env->regs[30] = regs->r30;
+ env->regs[31] = regs->r31;
+ env->sregs[SR_PC] = regs->pc;
+ }
#elif defined(TARGET_MIPS)
{
int i;