* 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 <errno.h>
#include <unistd.h>
#include <machine/trap.h>
+#include <sys/types.h>
+#include <sys/mman.h>
#include "qemu.h"
#include "qemu-common.h"
/* For tb_lock */
-#include "exec-all.h"
+#include "cpu.h"
+#include "tcg.h"
+#include "qemu-timer.h"
+#include "envlist.h"
#define DEBUG_LOGFILE "/tmp/qemu.log"
-static const char *interp_prefix = CONFIG_QEMU_PREFIX;
+int singlestep;
+#if defined(CONFIG_USE_GUEST_BASE)
+unsigned long mmap_min_addr;
+unsigned long guest_base;
+int have_guest_base;
+unsigned long reserved_va;
+#endif
+
+static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
extern char **environ;
+enum BSDType bsd_type;
/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
we allocate a bigger stack. Need a better solution, for example
vfprintf(stderr, fmt, ap);
va_end(ap);
}
+
+#if defined(TARGET_I386)
+int cpu_get_pic_interrupt(CPUX86State *env)
+{
+ return -1;
+}
+#endif
+
+/* These are no-ops because we are not threadsafe. */
+static inline void cpu_exec_start(CPUArchState *env)
+{
+}
+
+static inline void cpu_exec_end(CPUArchState *env)
+{
+}
+
+static inline void start_exclusive(void)
+{
+}
+
+static inline void end_exclusive(void)
+{
+}
+
+void fork_start(void)
+{
+}
+
+void fork_end(int child)
+{
+ if (child) {
+ gdbserver_fork(thread_env);
+ }
+}
+
+void cpu_list_lock(void)
+{
+}
+
+void cpu_list_unlock(void)
+{
+}
+
+#ifdef TARGET_I386
+/***********************************************************/
+/* CPUX86 core interface */
+
+void cpu_smm_update(CPUX86State *env)
+{
+}
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+ return cpu_get_real_ticks();
+}
+
+static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
+ int flags)
+{
+ unsigned int e1, e2;
+ uint32_t *p;
+ e1 = (addr << 16) | (limit & 0xffff);
+ e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+ e2 |= flags;
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+}
+
+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)
+{
+ uint32_t *p, e1, e2;
+ e1 = (addr & 0xffff) | (sel << 16);
+ e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+ p[2] = tswap32(addr >> 32);
+ p[3] = 0;
+}
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+ set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
+}
+#else
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+ uint32_t addr, unsigned int sel)
+{
+ uint32_t *p, e1, e2;
+ e1 = (addr & 0xffff) | (sel << 16);
+ e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+ p = ptr;
+ p[0] = tswap32(e1);
+ p[1] = tswap32(e2);
+}
+
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+ set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+#endif
+
+void cpu_loop(CPUX86State *env)
+{
+ int trapnr;
+ abi_ulong pc;
+ //target_siginfo_t info;
+
+ for(;;) {
+ trapnr = cpu_x86_exec(env);
+ switch(trapnr) {
+ case 0x80:
+ /* syscall from int $0x80 */
+ if (bsd_type == target_freebsd) {
+ abi_ulong params = (abi_ulong) env->regs[R_ESP] +
+ sizeof(int32_t);
+ int32_t syscall_nr = env->regs[R_EAX];
+ int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
+
+ if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
+ get_user_s32(syscall_nr, params);
+ params += sizeof(int32_t);
+ } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
+ get_user_s32(syscall_nr, params);
+ params += sizeof(int64_t);
+ }
+ get_user_s32(arg1, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg2, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg3, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg4, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg5, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg6, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg7, params);
+ params += sizeof(int32_t);
+ get_user_s32(arg8, params);
+ env->regs[R_EAX] = do_freebsd_syscall(env,
+ syscall_nr,
+ arg1,
+ arg2,
+ arg3,
+ arg4,
+ arg5,
+ arg6,
+ arg7,
+ arg8);
+ } else { //if (bsd_type == target_openbsd)
+ env->regs[R_EAX] = do_openbsd_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EBX],
+ env->regs[R_ECX],
+ env->regs[R_EDX],
+ env->regs[R_ESI],
+ env->regs[R_EDI],
+ env->regs[R_EBP]);
+ }
+ if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+ env->regs[R_EAX] = -env->regs[R_EAX];
+ env->eflags |= CC_C;
+ } else {
+ env->eflags &= ~CC_C;
+ }
+ break;
+#ifndef TARGET_ABI32
+ case EXCP_SYSCALL:
+ /* syscall from syscall instruction */
+ if (bsd_type == target_freebsd)
+ env->regs[R_EAX] = do_freebsd_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EDI],
+ env->regs[R_ESI],
+ env->regs[R_EDX],
+ env->regs[R_ECX],
+ env->regs[8],
+ env->regs[9], 0, 0);
+ else { //if (bsd_type == target_openbsd)
+ env->regs[R_EAX] = do_openbsd_syscall(env,
+ env->regs[R_EAX],
+ env->regs[R_EDI],
+ env->regs[R_ESI],
+ env->regs[R_EDX],
+ env->regs[10],
+ env->regs[8],
+ env->regs[9]);
+ }
+ env->eip = env->exception_next_eip;
+ if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
+ env->regs[R_EAX] = -env->regs[R_EAX];
+ env->eflags |= CC_C;
+ } else {
+ env->eflags &= ~CC_C;
+ }
+ break;
+#endif
+#if 0
+ case EXCP0B_NOSEG:
+ case EXCP0C_STACK:
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ break;
+ case EXCP0D_GPF:
+ /* XXX: potential problem if ABI32 */
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_fault(env);
+ } else
+#endif
+ {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+ case EXCP0E_PAGE:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ if (!(env->error_code & 1))
+ info.si_code = TARGET_SEGV_MAPERR;
+ else
+ info.si_code = TARGET_SEGV_ACCERR;
+ info._sifields._sigfault._addr = env->cr[2];
+ queue_signal(env, info.si_signo, &info);
+ break;
+ case EXCP00_DIVZ:
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else
+#endif
+ {
+ /* division by zero */
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = TARGET_FPE_INTDIV;
+ info._sifields._sigfault._addr = env->eip;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+ case EXCP01_DB:
+ case EXCP03_INT3:
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else
+#endif
+ {
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ if (trapnr == EXCP01_DB) {
+ info.si_code = TARGET_TRAP_BRKPT;
+ info._sifields._sigfault._addr = env->eip;
+ } else {
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ }
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+ case EXCP04_INTO:
+ case EXCP05_BOUND:
+#ifndef TARGET_X86_64
+ if (env->eflags & VM_MASK) {
+ handle_vm86_trap(env, trapnr);
+ } else
+#endif
+ {
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = TARGET_SI_KERNEL;
+ info._sifields._sigfault._addr = 0;
+ queue_signal(env, info.si_signo, &info);
+ }
+ break;
+ case EXCP06_ILLOP:
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = TARGET_ILL_ILLOPN;
+ info._sifields._sigfault._addr = env->eip;
+ queue_signal(env, info.si_signo, &info);
+ break;
+#endif
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+#if 0
+ 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;
+#endif
+ default:
+ pc = env->segs[R_CS].base + env->eip;
+ fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
+ (long)pc, trapnr);
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+#endif
+
#ifdef TARGET_SPARC
#define SPARC64_STACK_BIAS 2047
#endif
}
-void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
+void cpu_loop(CPUSPARCState *env)
{
int trapnr, ret, syscall_nr;
//target_siginfo_t info;
#ifndef TARGET_SPARC64
case 0x80:
#else
+ /* FreeBSD uses 0x141 for syscalls too */
+ case 0x141:
+ if (bsd_type != target_freebsd)
+ goto badtrap;
case 0x100:
#endif
syscall_nr = env->gregs[1];
-#if defined(TARGET_SPARC)
- syscall_nr &= ~(SYSCALL_G7RFLAG | SYSCALL_G2RFLAG);
-#endif
if (bsd_type == target_freebsd)
ret = do_freebsd_syscall(env, syscall_nr,
env->regwptr[0], env->regwptr[1],
env->regwptr[2], env->regwptr[3],
- env->regwptr[4], env->regwptr[5]);
+ env->regwptr[4], env->regwptr[5], 0, 0);
else if (bsd_type == target_netbsd)
ret = do_netbsd_syscall(env, syscall_nr,
env->regwptr[0], env->regwptr[1],
env->regwptr[2], env->regwptr[3],
env->regwptr[4], env->regwptr[5]);
- else //if (bsd_type == target_openbsd)
+ else { //if (bsd_type == target_openbsd)
+#if defined(TARGET_SPARC64)
+ syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
+ TARGET_OPENBSD_SYSCALL_G2RFLAG);
+#endif
ret = do_openbsd_syscall(env, syscall_nr,
env->regwptr[0], env->regwptr[1],
env->regwptr[2], env->regwptr[3],
env->regwptr[4], env->regwptr[5]);
+ }
if ((unsigned int)ret >= (unsigned int)(-515)) {
+ ret = -ret;
#if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
env->xcc |= PSR_CARRY;
#else
}
env->regwptr[0] = ret;
/* next instruction */
-#if defined(TARGET_SPARC)
- if (env->gregs[1] & SYSCALL_G2RFLAG) {
+#if defined(TARGET_SPARC64)
+ if (bsd_type == target_openbsd &&
+ env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
env->pc = env->gregs[2];
env->npc = env->pc + 4;
- } else if (env->gregs[1] & SYSCALL_G7RFLAG) {
+ } else if (bsd_type == target_openbsd &&
+ env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
env->pc = env->gregs[7];
env->npc = env->pc + 4;
} else {
}
break;
default:
+#ifdef TARGET_SPARC64
+ badtrap:
+#endif
printf ("Unhandled trap: 0x%x\n", trapnr);
cpu_dump_state(env, stderr, fprintf, 0);
exit (1);
"-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"
+#if defined(CONFIG_USE_GUEST_BASE)
+ "-B address set guest_base address to address\n"
+#endif
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
"\n"
"Debug options:\n"
- "-d options activate log (logfile=%s)\n"
+ "-d options activate log (default logfile=%s)\n"
+ "-D logfile override default logfile location\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;
+THREAD CPUArchState *thread_env;
/* Assumes contents are already zeroed. */
void init_task_state(TaskState *ts)
{
const char *filename;
const char *cpu_model;
+ const char *log_file = DEBUG_LOGFILE;
+ const char *log_mask = NULL;
struct target_pt_regs regs1, *regs = ®s1;
struct image_info info1, *info = &info1;
TaskState ts1, *ts = &ts1;
- CPUState *env;
+ CPUArchState *env;
int optind;
const char *r;
int gdbstub_port = 0;
- int drop_ld_preload = 0, environ_count = 0;
- char **target_environ, **wrk, **dst;
- enum BSDType bsd_type = target_openbsd;
+ char **target_environ, **wrk;
+ envlist_t *envlist = NULL;
+ bsd_type = target_openbsd;
if (argc <= 1)
usage();
- /* init debug */
- cpu_set_log_filename(DEBUG_LOGFILE);
+ module_call_init(MODULE_INIT_QOM);
+
+ 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;
+#if defined(cpudef_setup)
+ cpudef_setup(); /* parse cpu definitions in target config file (TBD) */
+#endif
+
optind = 1;
for(;;) {
if (optind >= argc)
if (!strcmp(r, "-")) {
break;
} else if (!strcmp(r, "d")) {
- int mask;
- const CPULogItem *item;
-
- if (optind >= argc)
+ if (optind >= argc) {
break;
-
+ }
+ log_mask = argv[optind++];
+ } else if (!strcmp(r, "D")) {
+ if (optind >= argc) {
+ break;
+ }
+ log_file = argv[optind++];
+ } else if (!strcmp(r, "E")) {
r = argv[optind++];
- mask = cpu_str_to_log_mask(r);
- if (!mask) {
- printf("Log items (comma separated):\n");
- for(item = cpu_log_items; item->mask != 0; item++) {
- printf("%-10s %s\n", item->name, item->help);
- }
+ if (envlist_setenv(envlist, r) != 0)
+ usage();
+ } else if (!strcmp(r, "ignore-environment")) {
+ envlist_free(envlist);
+ if ((envlist = envlist_create()) == NULL) {
+ (void) fprintf(stderr, "Unable to allocate envlist\n");
exit(1);
}
- cpu_set_log(mask);
+ } else if (!strcmp(r, "U")) {
+ r = argv[optind++];
+ if (envlist_unsetenv(envlist, r) != 0)
+ usage();
} else if (!strcmp(r, "s")) {
r = argv[optind++];
x86_stack_size = strtol(r, (char **)&r, 0);
#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, "bsd")) {
if (!strcasecmp(argv[optind], "freebsd")) {
bsd_type = target_freebsd;
usage();
}
optind++;
+ } else if (!strcmp(r, "singlestep")) {
+ singlestep = 1;
} else if (!strcmp(r, "strace")) {
do_strace = 1;
} else
usage();
}
}
- if (optind >= argc)
+
+ /* init debug */
+ cpu_set_log_filename(log_file);
+ if (log_mask) {
+ int mask;
+ const CPULogItem *item;
+
+ mask = cpu_str_to_log_mask(log_mask);
+ if (!mask) {
+ printf("Log items (comma separated):\n");
+ for (item = cpu_log_items; item->mask != 0; item++) {
+ printf("%-10s %s\n", item->name, item->help);
+ }
+ exit(1);
+ }
+ cpu_set_log(mask);
+ }
+
+ if (optind >= argc) {
usage();
+ }
filename = argv[optind];
/* Zero out regs */
init_paths(interp_prefix);
if (cpu_model == NULL) {
-#if defined(TARGET_SPARC)
+#if defined(TARGET_I386)
+#ifdef TARGET_X86_64
+ cpu_model = "qemu64";
+#else
+ cpu_model = "qemu32";
+#endif
+#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
cpu_model = "TI UltraSparc II";
#else
cpu_model = "any";
#endif
}
- cpu_exec_init_all(0);
+ tcg_exec_init(0);
+ cpu_exec_init_all();
/* NOTE: we need to init the CPU at this stage to get
qemu_host_page_size */
env = cpu_init(cpu_model);
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
+#if defined(TARGET_I386) || defined(TARGET_SPARC) || defined(TARGET_PPC)
+ cpu_state_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);
+ }
}
- *dst = NULL; /* NULL terminate target_environ */
+#endif /* CONFIG_USE_GUEST_BASE */
if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
printf("Error loading %s\n", filename);
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();
+#if defined(CONFIG_USE_GUEST_BASE)
+ /* Now that we've loaded the binary, GUEST_BASE is fixed. Delay
+ generating the prologue until now so that the prologue can take
+ the real value of GUEST_BASE into account. */
+ tcg_prologue_init(&tcg_ctx);
+#endif
+
/* 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_SPARC)
+#if defined(TARGET_I386)
+ cpu_x86_set_cpl(env, 3);
+
+ env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+ env->hflags |= HF_PE_MASK;
+ if (env->cpuid_features & CPUID_SSE) {
+ env->cr[4] |= CR4_OSFXSR_MASK;
+ env->hflags |= HF_OSFXSR_MASK;
+ }
+#ifndef TARGET_ABI32
+ /* enable 64 bit mode if possible */
+ if (!(env->cpuid_ext2_features & CPUID_EXT2_LM)) {
+ fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
+ exit(1);
+ }
+ env->cr[4] |= CR4_PAE_MASK;
+ env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
+ env->hflags |= HF_LMA_MASK;
+#endif
+
+ /* flags setup : we activate the IRQs by default as in user mode */
+ env->eflags |= IF_MASK;
+
+ /* linux register setup */
+#ifndef TARGET_ABI32
+ env->regs[R_EAX] = regs->rax;
+ env->regs[R_EBX] = regs->rbx;
+ env->regs[R_ECX] = regs->rcx;
+ env->regs[R_EDX] = regs->rdx;
+ env->regs[R_ESI] = regs->rsi;
+ env->regs[R_EDI] = regs->rdi;
+ env->regs[R_EBP] = regs->rbp;
+ env->regs[R_ESP] = regs->rsp;
+ env->eip = regs->rip;
+#else
+ env->regs[R_EAX] = regs->eax;
+ env->regs[R_EBX] = regs->ebx;
+ env->regs[R_ECX] = regs->ecx;
+ env->regs[R_EDX] = regs->edx;
+ env->regs[R_ESI] = regs->esi;
+ env->regs[R_EDI] = regs->edi;
+ env->regs[R_EBP] = regs->ebp;
+ env->regs[R_ESP] = regs->esp;
+ env->eip = regs->eip;
+#endif
+
+ /* linux interrupt setup */
+#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);
+ set_idt(3, 3);
+ set_idt(4, 3);
+ set_idt(5, 0);
+ set_idt(6, 0);
+ set_idt(7, 0);
+ set_idt(8, 0);
+ set_idt(9, 0);
+ set_idt(10, 0);
+ set_idt(11, 0);
+ set_idt(12, 0);
+ set_idt(13, 0);
+ set_idt(14, 0);
+ set_idt(15, 0);
+ set_idt(16, 0);
+ set_idt(17, 0);
+ set_idt(18, 0);
+ set_idt(19, 0);
+ set_idt(0x80, 3);
+
+ /* linux segment setup */
+ {
+ uint64_t *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 |
+ (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#else
+ /* 64 bit code segment */
+ write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ DESC_L_MASK |
+ (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+#endif
+ write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+ }
+
+ cpu_x86_load_seg(env, R_CS, __USER_CS);
+ cpu_x86_load_seg(env, R_SS, __USER_DS);
+#ifdef TARGET_ABI32
+ cpu_x86_load_seg(env, R_DS, __USER_DS);
+ cpu_x86_load_seg(env, R_ES, __USER_DS);
+ cpu_x86_load_seg(env, R_FS, __USER_DS);
+ cpu_x86_load_seg(env, R_GS, __USER_DS);
+ /* This hack makes Wine work... */
+ env->segs[R_FS].selector = 0;
+#else
+ cpu_x86_load_seg(env, R_DS, 0);
+ cpu_x86_load_seg(env, R_ES, 0);
+ cpu_x86_load_seg(env, R_FS, 0);
+ cpu_x86_load_seg(env, R_GS, 0);
+#endif
+#elif defined(TARGET_SPARC)
{
int i;
env->pc = regs->pc;
gdbserver_start (gdbstub_port);
gdb_handlesig(env, 0);
}
- cpu_loop(env, bsd_type);
+ cpu_loop(env);
/* never exits */
return 0;
}