xref: /qemu/bsd-user/main.c (revision 93fcfe39)
184778508Sblueswir1 /*
284778508Sblueswir1  *  qemu user main
384778508Sblueswir1  *
484778508Sblueswir1  *  Copyright (c) 2003-2008 Fabrice Bellard
584778508Sblueswir1  *
684778508Sblueswir1  *  This program is free software; you can redistribute it and/or modify
784778508Sblueswir1  *  it under the terms of the GNU General Public License as published by
884778508Sblueswir1  *  the Free Software Foundation; either version 2 of the License, or
984778508Sblueswir1  *  (at your option) any later version.
1084778508Sblueswir1  *
1184778508Sblueswir1  *  This program is distributed in the hope that it will be useful,
1284778508Sblueswir1  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1384778508Sblueswir1  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1484778508Sblueswir1  *  GNU General Public License for more details.
1584778508Sblueswir1  *
1684778508Sblueswir1  *  You should have received a copy of the GNU General Public License
1784778508Sblueswir1  *  along with this program; if not, write to the Free Software
18530e7615Sblueswir1  *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19530e7615Sblueswir1  *  MA 02110-1301, USA.
2084778508Sblueswir1  */
2184778508Sblueswir1 #include <stdlib.h>
2284778508Sblueswir1 #include <stdio.h>
2384778508Sblueswir1 #include <stdarg.h>
2484778508Sblueswir1 #include <string.h>
2584778508Sblueswir1 #include <errno.h>
2684778508Sblueswir1 #include <unistd.h>
2784778508Sblueswir1 #include <machine/trap.h>
2884778508Sblueswir1 
2984778508Sblueswir1 #include "qemu.h"
3084778508Sblueswir1 #include "qemu-common.h"
3184778508Sblueswir1 /* For tb_lock */
3284778508Sblueswir1 #include "exec-all.h"
3384778508Sblueswir1 
3484778508Sblueswir1 #define DEBUG_LOGFILE "/tmp/qemu.log"
3584778508Sblueswir1 
3684778508Sblueswir1 static const char *interp_prefix = CONFIG_QEMU_PREFIX;
3784778508Sblueswir1 const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
3884778508Sblueswir1 extern char **environ;
3984778508Sblueswir1 
4084778508Sblueswir1 /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
4184778508Sblueswir1    we allocate a bigger stack. Need a better solution, for example
4284778508Sblueswir1    by remapping the process stack directly at the right place */
4384778508Sblueswir1 unsigned long x86_stack_size = 512 * 1024;
4484778508Sblueswir1 
4584778508Sblueswir1 void gemu_log(const char *fmt, ...)
4684778508Sblueswir1 {
4784778508Sblueswir1     va_list ap;
4884778508Sblueswir1 
4984778508Sblueswir1     va_start(ap, fmt);
5084778508Sblueswir1     vfprintf(stderr, fmt, ap);
5184778508Sblueswir1     va_end(ap);
5284778508Sblueswir1 }
5384778508Sblueswir1 #ifdef TARGET_SPARC
5484778508Sblueswir1 #define SPARC64_STACK_BIAS 2047
5584778508Sblueswir1 
5684778508Sblueswir1 //#define DEBUG_WIN
5784778508Sblueswir1 /* WARNING: dealing with register windows _is_ complicated. More info
5884778508Sblueswir1    can be found at http://www.sics.se/~psm/sparcstack.html */
5984778508Sblueswir1 static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
6084778508Sblueswir1 {
6184778508Sblueswir1     index = (index + cwp * 16) % (16 * env->nwindows);
6284778508Sblueswir1     /* wrap handling : if cwp is on the last window, then we use the
6384778508Sblueswir1        registers 'after' the end */
6484778508Sblueswir1     if (index < 8 && env->cwp == env->nwindows - 1)
6584778508Sblueswir1         index += 16 * env->nwindows;
6684778508Sblueswir1     return index;
6784778508Sblueswir1 }
6884778508Sblueswir1 
6984778508Sblueswir1 /* save the register window 'cwp1' */
7084778508Sblueswir1 static inline void save_window_offset(CPUSPARCState *env, int cwp1)
7184778508Sblueswir1 {
7284778508Sblueswir1     unsigned int i;
7384778508Sblueswir1     abi_ulong sp_ptr;
7484778508Sblueswir1 
7584778508Sblueswir1     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
7684778508Sblueswir1 #ifdef TARGET_SPARC64
7784778508Sblueswir1     if (sp_ptr & 3)
7884778508Sblueswir1         sp_ptr += SPARC64_STACK_BIAS;
7984778508Sblueswir1 #endif
8084778508Sblueswir1 #if defined(DEBUG_WIN)
8184778508Sblueswir1     printf("win_overflow: sp_ptr=0x" TARGET_ABI_FMT_lx " save_cwp=%d\n",
8284778508Sblueswir1            sp_ptr, cwp1);
8384778508Sblueswir1 #endif
8484778508Sblueswir1     for(i = 0; i < 16; i++) {
8584778508Sblueswir1         /* FIXME - what to do if put_user() fails? */
8684778508Sblueswir1         put_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
8784778508Sblueswir1         sp_ptr += sizeof(abi_ulong);
8884778508Sblueswir1     }
8984778508Sblueswir1 }
9084778508Sblueswir1 
9184778508Sblueswir1 static void save_window(CPUSPARCState *env)
9284778508Sblueswir1 {
9384778508Sblueswir1 #ifndef TARGET_SPARC64
9484778508Sblueswir1     unsigned int new_wim;
9584778508Sblueswir1     new_wim = ((env->wim >> 1) | (env->wim << (env->nwindows - 1))) &
9684778508Sblueswir1         ((1LL << env->nwindows) - 1);
9784778508Sblueswir1     save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
9884778508Sblueswir1     env->wim = new_wim;
9984778508Sblueswir1 #else
10084778508Sblueswir1     save_window_offset(env, cpu_cwp_dec(env, env->cwp - 2));
10184778508Sblueswir1     env->cansave++;
10284778508Sblueswir1     env->canrestore--;
10384778508Sblueswir1 #endif
10484778508Sblueswir1 }
10584778508Sblueswir1 
10684778508Sblueswir1 static void restore_window(CPUSPARCState *env)
10784778508Sblueswir1 {
10884778508Sblueswir1 #ifndef TARGET_SPARC64
10984778508Sblueswir1     unsigned int new_wim;
11084778508Sblueswir1 #endif
11184778508Sblueswir1     unsigned int i, cwp1;
11284778508Sblueswir1     abi_ulong sp_ptr;
11384778508Sblueswir1 
11484778508Sblueswir1 #ifndef TARGET_SPARC64
11584778508Sblueswir1     new_wim = ((env->wim << 1) | (env->wim >> (env->nwindows - 1))) &
11684778508Sblueswir1         ((1LL << env->nwindows) - 1);
11784778508Sblueswir1 #endif
11884778508Sblueswir1 
11984778508Sblueswir1     /* restore the invalid window */
12084778508Sblueswir1     cwp1 = cpu_cwp_inc(env, env->cwp + 1);
12184778508Sblueswir1     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
12284778508Sblueswir1 #ifdef TARGET_SPARC64
12384778508Sblueswir1     if (sp_ptr & 3)
12484778508Sblueswir1         sp_ptr += SPARC64_STACK_BIAS;
12584778508Sblueswir1 #endif
12684778508Sblueswir1 #if defined(DEBUG_WIN)
12784778508Sblueswir1     printf("win_underflow: sp_ptr=0x" TARGET_ABI_FMT_lx " load_cwp=%d\n",
12884778508Sblueswir1            sp_ptr, cwp1);
12984778508Sblueswir1 #endif
13084778508Sblueswir1     for(i = 0; i < 16; i++) {
13184778508Sblueswir1         /* FIXME - what to do if get_user() fails? */
13284778508Sblueswir1         get_user_ual(env->regbase[get_reg_index(env, cwp1, 8 + i)], sp_ptr);
13384778508Sblueswir1         sp_ptr += sizeof(abi_ulong);
13484778508Sblueswir1     }
13584778508Sblueswir1 #ifdef TARGET_SPARC64
13684778508Sblueswir1     env->canrestore++;
13784778508Sblueswir1     if (env->cleanwin < env->nwindows - 1)
13884778508Sblueswir1         env->cleanwin++;
13984778508Sblueswir1     env->cansave--;
14084778508Sblueswir1 #else
14184778508Sblueswir1     env->wim = new_wim;
14284778508Sblueswir1 #endif
14384778508Sblueswir1 }
14484778508Sblueswir1 
14584778508Sblueswir1 static void flush_windows(CPUSPARCState *env)
14684778508Sblueswir1 {
14784778508Sblueswir1     int offset, cwp1;
14884778508Sblueswir1 
14984778508Sblueswir1     offset = 1;
15084778508Sblueswir1     for(;;) {
15184778508Sblueswir1         /* if restore would invoke restore_window(), then we can stop */
15284778508Sblueswir1         cwp1 = cpu_cwp_inc(env, env->cwp + offset);
15384778508Sblueswir1 #ifndef TARGET_SPARC64
15484778508Sblueswir1         if (env->wim & (1 << cwp1))
15584778508Sblueswir1             break;
15684778508Sblueswir1 #else
15784778508Sblueswir1         if (env->canrestore == 0)
15884778508Sblueswir1             break;
15984778508Sblueswir1         env->cansave++;
16084778508Sblueswir1         env->canrestore--;
16184778508Sblueswir1 #endif
16284778508Sblueswir1         save_window_offset(env, cwp1);
16384778508Sblueswir1         offset++;
16484778508Sblueswir1     }
16584778508Sblueswir1     cwp1 = cpu_cwp_inc(env, env->cwp + 1);
16684778508Sblueswir1 #ifndef TARGET_SPARC64
16784778508Sblueswir1     /* set wim so that restore will reload the registers */
16884778508Sblueswir1     env->wim = 1 << cwp1;
16984778508Sblueswir1 #endif
17084778508Sblueswir1 #if defined(DEBUG_WIN)
17184778508Sblueswir1     printf("flush_windows: nb=%d\n", offset - 1);
17284778508Sblueswir1 #endif
17384778508Sblueswir1 }
17484778508Sblueswir1 
17584778508Sblueswir1 void cpu_loop(CPUSPARCState *env, enum BSDType bsd_type)
17684778508Sblueswir1 {
17784778508Sblueswir1     int trapnr, ret, syscall_nr;
17884778508Sblueswir1     //target_siginfo_t info;
17984778508Sblueswir1 
18084778508Sblueswir1     while (1) {
18184778508Sblueswir1         trapnr = cpu_sparc_exec (env);
18284778508Sblueswir1 
18384778508Sblueswir1         switch (trapnr) {
18477b9435fSblueswir1 #ifndef TARGET_SPARC64
18577b9435fSblueswir1         case 0x80:
18677b9435fSblueswir1 #else
18784778508Sblueswir1         case 0x100:
18877b9435fSblueswir1 #endif
18984778508Sblueswir1             syscall_nr = env->gregs[1];
19084778508Sblueswir1             if (bsd_type == target_freebsd)
19184778508Sblueswir1                 ret = do_freebsd_syscall(env, syscall_nr,
19284778508Sblueswir1                                          env->regwptr[0], env->regwptr[1],
19384778508Sblueswir1                                          env->regwptr[2], env->regwptr[3],
19484778508Sblueswir1                                          env->regwptr[4], env->regwptr[5]);
19584778508Sblueswir1             else if (bsd_type == target_netbsd)
19684778508Sblueswir1                 ret = do_netbsd_syscall(env, syscall_nr,
19784778508Sblueswir1                                         env->regwptr[0], env->regwptr[1],
19884778508Sblueswir1                                         env->regwptr[2], env->regwptr[3],
19984778508Sblueswir1                                         env->regwptr[4], env->regwptr[5]);
200cdba95bdSblueswir1             else { //if (bsd_type == target_openbsd)
201cdba95bdSblueswir1 #if defined(TARGET_SPARC64)
202cdba95bdSblueswir1                 syscall_nr &= ~(TARGET_OPENBSD_SYSCALL_G7RFLAG |
203cdba95bdSblueswir1                                 TARGET_OPENBSD_SYSCALL_G2RFLAG);
204cdba95bdSblueswir1 #endif
20584778508Sblueswir1                 ret = do_openbsd_syscall(env, syscall_nr,
20684778508Sblueswir1                                          env->regwptr[0], env->regwptr[1],
20784778508Sblueswir1                                          env->regwptr[2], env->regwptr[3],
20884778508Sblueswir1                                          env->regwptr[4], env->regwptr[5]);
209cdba95bdSblueswir1             }
21084778508Sblueswir1             if ((unsigned int)ret >= (unsigned int)(-515)) {
21184778508Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
21284778508Sblueswir1                 env->xcc |= PSR_CARRY;
21384778508Sblueswir1 #else
21484778508Sblueswir1                 env->psr |= PSR_CARRY;
21584778508Sblueswir1 #endif
21684778508Sblueswir1             } else {
21784778508Sblueswir1 #if defined(TARGET_SPARC64) && !defined(TARGET_ABI32)
21884778508Sblueswir1                 env->xcc &= ~PSR_CARRY;
21984778508Sblueswir1 #else
22084778508Sblueswir1                 env->psr &= ~PSR_CARRY;
22184778508Sblueswir1 #endif
22284778508Sblueswir1             }
22384778508Sblueswir1             env->regwptr[0] = ret;
22484778508Sblueswir1             /* next instruction */
225cdba95bdSblueswir1 #if defined(TARGET_SPARC64)
226cdba95bdSblueswir1             if (bsd_type == target_openbsd &&
227cdba95bdSblueswir1                 env->gregs[1] & TARGET_OPENBSD_SYSCALL_G2RFLAG) {
22884778508Sblueswir1                 env->pc = env->gregs[2];
22984778508Sblueswir1                 env->npc = env->pc + 4;
230cdba95bdSblueswir1             } else if (bsd_type == target_openbsd &&
231cdba95bdSblueswir1                        env->gregs[1] & TARGET_OPENBSD_SYSCALL_G7RFLAG) {
23284778508Sblueswir1                 env->pc = env->gregs[7];
23384778508Sblueswir1                 env->npc = env->pc + 4;
23484778508Sblueswir1             } else {
23584778508Sblueswir1                 env->pc = env->npc;
23684778508Sblueswir1                 env->npc = env->npc + 4;
23784778508Sblueswir1             }
23884778508Sblueswir1 #else
23984778508Sblueswir1             env->pc = env->npc;
24084778508Sblueswir1             env->npc = env->npc + 4;
24184778508Sblueswir1 #endif
24284778508Sblueswir1             break;
24384778508Sblueswir1         case 0x83: /* flush windows */
24484778508Sblueswir1 #ifdef TARGET_ABI32
24584778508Sblueswir1         case 0x103:
24684778508Sblueswir1 #endif
24784778508Sblueswir1             flush_windows(env);
24884778508Sblueswir1             /* next instruction */
24984778508Sblueswir1             env->pc = env->npc;
25084778508Sblueswir1             env->npc = env->npc + 4;
25184778508Sblueswir1             break;
25284778508Sblueswir1 #ifndef TARGET_SPARC64
25384778508Sblueswir1         case TT_WIN_OVF: /* window overflow */
25484778508Sblueswir1             save_window(env);
25584778508Sblueswir1             break;
25684778508Sblueswir1         case TT_WIN_UNF: /* window underflow */
25784778508Sblueswir1             restore_window(env);
25884778508Sblueswir1             break;
25984778508Sblueswir1         case TT_TFAULT:
26084778508Sblueswir1         case TT_DFAULT:
26184778508Sblueswir1 #if 0
26284778508Sblueswir1             {
26384778508Sblueswir1                 info.si_signo = SIGSEGV;
26484778508Sblueswir1                 info.si_errno = 0;
26584778508Sblueswir1                 /* XXX: check env->error_code */
26684778508Sblueswir1                 info.si_code = TARGET_SEGV_MAPERR;
26784778508Sblueswir1                 info._sifields._sigfault._addr = env->mmuregs[4];
26884778508Sblueswir1                 queue_signal(env, info.si_signo, &info);
26984778508Sblueswir1             }
27084778508Sblueswir1 #endif
27184778508Sblueswir1             break;
27284778508Sblueswir1 #else
27384778508Sblueswir1         case TT_SPILL: /* window overflow */
27484778508Sblueswir1             save_window(env);
27584778508Sblueswir1             break;
27684778508Sblueswir1         case TT_FILL: /* window underflow */
27784778508Sblueswir1             restore_window(env);
27884778508Sblueswir1             break;
27984778508Sblueswir1         case TT_TFAULT:
28084778508Sblueswir1         case TT_DFAULT:
28184778508Sblueswir1 #if 0
28284778508Sblueswir1             {
28384778508Sblueswir1                 info.si_signo = SIGSEGV;
28484778508Sblueswir1                 info.si_errno = 0;
28584778508Sblueswir1                 /* XXX: check env->error_code */
28684778508Sblueswir1                 info.si_code = TARGET_SEGV_MAPERR;
28784778508Sblueswir1                 if (trapnr == TT_DFAULT)
28884778508Sblueswir1                     info._sifields._sigfault._addr = env->dmmuregs[4];
28984778508Sblueswir1                 else
29084778508Sblueswir1                     info._sifields._sigfault._addr = env->tsptr->tpc;
29184778508Sblueswir1                 //queue_signal(env, info.si_signo, &info);
29284778508Sblueswir1             }
29384778508Sblueswir1 #endif
29484778508Sblueswir1             break;
29584778508Sblueswir1 #endif
29684778508Sblueswir1         case EXCP_INTERRUPT:
29784778508Sblueswir1             /* just indicate that signals should be handled asap */
29884778508Sblueswir1             break;
29984778508Sblueswir1         case EXCP_DEBUG:
30084778508Sblueswir1             {
30184778508Sblueswir1                 int sig;
30284778508Sblueswir1 
30384778508Sblueswir1                 sig = gdb_handlesig (env, TARGET_SIGTRAP);
30484778508Sblueswir1 #if 0
30584778508Sblueswir1                 if (sig)
30684778508Sblueswir1                   {
30784778508Sblueswir1                     info.si_signo = sig;
30884778508Sblueswir1                     info.si_errno = 0;
30984778508Sblueswir1                     info.si_code = TARGET_TRAP_BRKPT;
31084778508Sblueswir1                     //queue_signal(env, info.si_signo, &info);
31184778508Sblueswir1                   }
31284778508Sblueswir1 #endif
31384778508Sblueswir1             }
31484778508Sblueswir1             break;
31584778508Sblueswir1         default:
31684778508Sblueswir1             printf ("Unhandled trap: 0x%x\n", trapnr);
31784778508Sblueswir1             cpu_dump_state(env, stderr, fprintf, 0);
31884778508Sblueswir1             exit (1);
31984778508Sblueswir1         }
32084778508Sblueswir1         process_pending_signals (env);
32184778508Sblueswir1     }
32284778508Sblueswir1 }
32384778508Sblueswir1 
32484778508Sblueswir1 #endif
32584778508Sblueswir1 
32684778508Sblueswir1 static void usage(void)
32784778508Sblueswir1 {
32884778508Sblueswir1     printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"
32984778508Sblueswir1            "usage: qemu-" TARGET_ARCH " [options] program [arguments...]\n"
33084778508Sblueswir1            "BSD CPU emulator (compiled for %s emulation)\n"
33184778508Sblueswir1            "\n"
33284778508Sblueswir1            "Standard options:\n"
33384778508Sblueswir1            "-h                print this help\n"
33484778508Sblueswir1            "-g port           wait gdb connection to port\n"
33584778508Sblueswir1            "-L path           set the elf interpreter prefix (default=%s)\n"
33684778508Sblueswir1            "-s size           set the stack size in bytes (default=%ld)\n"
33784778508Sblueswir1            "-cpu model        select CPU (-cpu ? for list)\n"
33884778508Sblueswir1            "-drop-ld-preload  drop LD_PRELOAD for target process\n"
33984778508Sblueswir1            "-bsd type         select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
34084778508Sblueswir1            "\n"
34184778508Sblueswir1            "Debug options:\n"
34284778508Sblueswir1            "-d options   activate log (logfile=%s)\n"
34384778508Sblueswir1            "-p pagesize  set the host page size to 'pagesize'\n"
34484778508Sblueswir1            "-strace      log system calls\n"
34584778508Sblueswir1            "\n"
34684778508Sblueswir1            "Environment variables:\n"
34784778508Sblueswir1            "QEMU_STRACE       Print system calls and arguments similar to the\n"
34884778508Sblueswir1            "                  'strace' program.  Enable by setting to any value.\n"
34984778508Sblueswir1            ,
35084778508Sblueswir1            TARGET_ARCH,
35184778508Sblueswir1            interp_prefix,
35284778508Sblueswir1            x86_stack_size,
35384778508Sblueswir1            DEBUG_LOGFILE);
35484778508Sblueswir1     _exit(1);
35584778508Sblueswir1 }
35684778508Sblueswir1 
35784778508Sblueswir1 THREAD CPUState *thread_env;
35884778508Sblueswir1 
35984778508Sblueswir1 /* Assumes contents are already zeroed.  */
36084778508Sblueswir1 void init_task_state(TaskState *ts)
36184778508Sblueswir1 {
36284778508Sblueswir1     int i;
36384778508Sblueswir1 
36484778508Sblueswir1     ts->used = 1;
36584778508Sblueswir1     ts->first_free = ts->sigqueue_table;
36684778508Sblueswir1     for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
36784778508Sblueswir1         ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
36884778508Sblueswir1     }
36984778508Sblueswir1     ts->sigqueue_table[i].next = NULL;
37084778508Sblueswir1 }
37184778508Sblueswir1 
37284778508Sblueswir1 int main(int argc, char **argv)
37384778508Sblueswir1 {
37484778508Sblueswir1     const char *filename;
37584778508Sblueswir1     const char *cpu_model;
37684778508Sblueswir1     struct target_pt_regs regs1, *regs = &regs1;
37784778508Sblueswir1     struct image_info info1, *info = &info1;
37884778508Sblueswir1     TaskState ts1, *ts = &ts1;
37984778508Sblueswir1     CPUState *env;
38084778508Sblueswir1     int optind;
38184778508Sblueswir1     const char *r;
38284778508Sblueswir1     int gdbstub_port = 0;
38384778508Sblueswir1     int drop_ld_preload = 0, environ_count = 0;
38484778508Sblueswir1     char **target_environ, **wrk, **dst;
38584778508Sblueswir1     enum BSDType bsd_type = target_openbsd;
38684778508Sblueswir1 
38784778508Sblueswir1     if (argc <= 1)
38884778508Sblueswir1         usage();
38984778508Sblueswir1 
39084778508Sblueswir1     /* init debug */
39184778508Sblueswir1     cpu_set_log_filename(DEBUG_LOGFILE);
39284778508Sblueswir1 
39384778508Sblueswir1     cpu_model = NULL;
39484778508Sblueswir1     optind = 1;
39584778508Sblueswir1     for(;;) {
39684778508Sblueswir1         if (optind >= argc)
39784778508Sblueswir1             break;
39884778508Sblueswir1         r = argv[optind];
39984778508Sblueswir1         if (r[0] != '-')
40084778508Sblueswir1             break;
40184778508Sblueswir1         optind++;
40284778508Sblueswir1         r++;
40384778508Sblueswir1         if (!strcmp(r, "-")) {
40484778508Sblueswir1             break;
40584778508Sblueswir1         } else if (!strcmp(r, "d")) {
40684778508Sblueswir1             int mask;
40784778508Sblueswir1             const CPULogItem *item;
40884778508Sblueswir1 
40984778508Sblueswir1             if (optind >= argc)
41084778508Sblueswir1                 break;
41184778508Sblueswir1 
41284778508Sblueswir1             r = argv[optind++];
41384778508Sblueswir1             mask = cpu_str_to_log_mask(r);
41484778508Sblueswir1             if (!mask) {
41584778508Sblueswir1                 printf("Log items (comma separated):\n");
41684778508Sblueswir1                 for(item = cpu_log_items; item->mask != 0; item++) {
41784778508Sblueswir1                     printf("%-10s %s\n", item->name, item->help);
41884778508Sblueswir1                 }
41984778508Sblueswir1                 exit(1);
42084778508Sblueswir1             }
42184778508Sblueswir1             cpu_set_log(mask);
42284778508Sblueswir1         } else if (!strcmp(r, "s")) {
42384778508Sblueswir1             r = argv[optind++];
42484778508Sblueswir1             x86_stack_size = strtol(r, (char **)&r, 0);
42584778508Sblueswir1             if (x86_stack_size <= 0)
42684778508Sblueswir1                 usage();
42784778508Sblueswir1             if (*r == 'M')
42884778508Sblueswir1                 x86_stack_size *= 1024 * 1024;
42984778508Sblueswir1             else if (*r == 'k' || *r == 'K')
43084778508Sblueswir1                 x86_stack_size *= 1024;
43184778508Sblueswir1         } else if (!strcmp(r, "L")) {
43284778508Sblueswir1             interp_prefix = argv[optind++];
43384778508Sblueswir1         } else if (!strcmp(r, "p")) {
43484778508Sblueswir1             qemu_host_page_size = atoi(argv[optind++]);
43584778508Sblueswir1             if (qemu_host_page_size == 0 ||
43684778508Sblueswir1                 (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
43784778508Sblueswir1                 fprintf(stderr, "page size must be a power of two\n");
43884778508Sblueswir1                 exit(1);
43984778508Sblueswir1             }
44084778508Sblueswir1         } else if (!strcmp(r, "g")) {
44184778508Sblueswir1             gdbstub_port = atoi(argv[optind++]);
44284778508Sblueswir1         } else if (!strcmp(r, "r")) {
44384778508Sblueswir1             qemu_uname_release = argv[optind++];
44484778508Sblueswir1         } else if (!strcmp(r, "cpu")) {
44584778508Sblueswir1             cpu_model = argv[optind++];
44684778508Sblueswir1             if (strcmp(cpu_model, "?") == 0) {
44784778508Sblueswir1 /* XXX: implement xxx_cpu_list for targets that still miss it */
44884778508Sblueswir1 #if defined(cpu_list)
44984778508Sblueswir1                     cpu_list(stdout, &fprintf);
45084778508Sblueswir1 #endif
45184778508Sblueswir1                 _exit(1);
45284778508Sblueswir1             }
45384778508Sblueswir1         } else if (!strcmp(r, "drop-ld-preload")) {
45484778508Sblueswir1             drop_ld_preload = 1;
45584778508Sblueswir1         } else if (!strcmp(r, "bsd")) {
45684778508Sblueswir1             if (!strcasecmp(argv[optind], "freebsd")) {
45784778508Sblueswir1                 bsd_type = target_freebsd;
45884778508Sblueswir1             } else if (!strcasecmp(argv[optind], "netbsd")) {
45984778508Sblueswir1                 bsd_type = target_netbsd;
46084778508Sblueswir1             } else if (!strcasecmp(argv[optind], "openbsd")) {
46184778508Sblueswir1                 bsd_type = target_openbsd;
46284778508Sblueswir1             } else {
46384778508Sblueswir1                 usage();
46484778508Sblueswir1             }
46584778508Sblueswir1             optind++;
46684778508Sblueswir1         } else if (!strcmp(r, "strace")) {
46784778508Sblueswir1             do_strace = 1;
46884778508Sblueswir1         } else
46984778508Sblueswir1         {
47084778508Sblueswir1             usage();
47184778508Sblueswir1         }
47284778508Sblueswir1     }
47384778508Sblueswir1     if (optind >= argc)
47484778508Sblueswir1         usage();
47584778508Sblueswir1     filename = argv[optind];
47684778508Sblueswir1 
47784778508Sblueswir1     /* Zero out regs */
47884778508Sblueswir1     memset(regs, 0, sizeof(struct target_pt_regs));
47984778508Sblueswir1 
48084778508Sblueswir1     /* Zero out image_info */
48184778508Sblueswir1     memset(info, 0, sizeof(struct image_info));
48284778508Sblueswir1 
48384778508Sblueswir1     /* Scan interp_prefix dir for replacement files. */
48484778508Sblueswir1     init_paths(interp_prefix);
48584778508Sblueswir1 
48684778508Sblueswir1     if (cpu_model == NULL) {
48784778508Sblueswir1 #if defined(TARGET_SPARC)
48884778508Sblueswir1 #ifdef TARGET_SPARC64
48984778508Sblueswir1         cpu_model = "TI UltraSparc II";
49084778508Sblueswir1 #else
49184778508Sblueswir1         cpu_model = "Fujitsu MB86904";
49284778508Sblueswir1 #endif
49384778508Sblueswir1 #else
49484778508Sblueswir1         cpu_model = "any";
49584778508Sblueswir1 #endif
49684778508Sblueswir1     }
49784778508Sblueswir1     cpu_exec_init_all(0);
49884778508Sblueswir1     /* NOTE: we need to init the CPU at this stage to get
49984778508Sblueswir1        qemu_host_page_size */
50084778508Sblueswir1     env = cpu_init(cpu_model);
50184778508Sblueswir1     if (!env) {
50284778508Sblueswir1         fprintf(stderr, "Unable to find CPU definition\n");
50384778508Sblueswir1         exit(1);
50484778508Sblueswir1     }
50584778508Sblueswir1     thread_env = env;
50684778508Sblueswir1 
50784778508Sblueswir1     if (getenv("QEMU_STRACE")) {
50884778508Sblueswir1         do_strace = 1;
50984778508Sblueswir1     }
51084778508Sblueswir1 
51184778508Sblueswir1     wrk = environ;
51284778508Sblueswir1     while (*(wrk++))
51384778508Sblueswir1         environ_count++;
51484778508Sblueswir1 
51584778508Sblueswir1     target_environ = malloc((environ_count + 1) * sizeof(char *));
51684778508Sblueswir1     if (!target_environ)
51784778508Sblueswir1         abort();
51884778508Sblueswir1     for (wrk = environ, dst = target_environ; *wrk; wrk++) {
51984778508Sblueswir1         if (drop_ld_preload && !strncmp(*wrk, "LD_PRELOAD=", 11))
52084778508Sblueswir1             continue;
52184778508Sblueswir1         *(dst++) = strdup(*wrk);
52284778508Sblueswir1     }
52384778508Sblueswir1     *dst = NULL; /* NULL terminate target_environ */
52484778508Sblueswir1 
52584778508Sblueswir1     if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
52684778508Sblueswir1         printf("Error loading %s\n", filename);
52784778508Sblueswir1         _exit(1);
52884778508Sblueswir1     }
52984778508Sblueswir1 
53084778508Sblueswir1     for (wrk = target_environ; *wrk; wrk++) {
53184778508Sblueswir1         free(*wrk);
53284778508Sblueswir1     }
53384778508Sblueswir1 
53484778508Sblueswir1     free(target_environ);
53584778508Sblueswir1 
536*93fcfe39Saliguori     log_page_dump();
53784778508Sblueswir1 
538*93fcfe39Saliguori     qemu_log("start_brk   0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
539*93fcfe39Saliguori     qemu_log("end_code    0x" TARGET_ABI_FMT_lx "\n", info->end_code);
540*93fcfe39Saliguori     qemu_log("start_code  0x" TARGET_ABI_FMT_lx "\n",
54184778508Sblueswir1             info->start_code);
542*93fcfe39Saliguori     qemu_log("start_data  0x" TARGET_ABI_FMT_lx "\n",
54384778508Sblueswir1             info->start_data);
544*93fcfe39Saliguori     qemu_log("end_data    0x" TARGET_ABI_FMT_lx "\n", info->end_data);
545*93fcfe39Saliguori     qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
54684778508Sblueswir1             info->start_stack);
547*93fcfe39Saliguori     qemu_log("brk         0x" TARGET_ABI_FMT_lx "\n", info->brk);
548*93fcfe39Saliguori     qemu_log("entry       0x" TARGET_ABI_FMT_lx "\n", info->entry);
54984778508Sblueswir1 
55084778508Sblueswir1     target_set_brk(info->brk);
55184778508Sblueswir1     syscall_init();
55284778508Sblueswir1     signal_init();
55384778508Sblueswir1 
55484778508Sblueswir1     /* build Task State */
55584778508Sblueswir1     memset(ts, 0, sizeof(TaskState));
55684778508Sblueswir1     init_task_state(ts);
55784778508Sblueswir1     ts->info = info;
55884778508Sblueswir1     env->opaque = ts;
55984778508Sblueswir1 
56084778508Sblueswir1 #if defined(TARGET_SPARC)
56184778508Sblueswir1     {
56284778508Sblueswir1         int i;
56384778508Sblueswir1         env->pc = regs->pc;
56484778508Sblueswir1         env->npc = regs->npc;
56584778508Sblueswir1         env->y = regs->y;
56684778508Sblueswir1         for(i = 0; i < 8; i++)
56784778508Sblueswir1             env->gregs[i] = regs->u_regs[i];
56884778508Sblueswir1         for(i = 0; i < 8; i++)
56984778508Sblueswir1             env->regwptr[i] = regs->u_regs[i + 8];
57084778508Sblueswir1     }
57184778508Sblueswir1 #else
57284778508Sblueswir1 #error unsupported target CPU
57384778508Sblueswir1 #endif
57484778508Sblueswir1 
57584778508Sblueswir1     if (gdbstub_port) {
57684778508Sblueswir1         gdbserver_start (gdbstub_port);
57784778508Sblueswir1         gdb_handlesig(env, 0);
57884778508Sblueswir1     }
57984778508Sblueswir1     cpu_loop(env, bsd_type);
58084778508Sblueswir1     /* never exits */
58184778508Sblueswir1     return 0;
58284778508Sblueswir1 }
583