xref: /qemu/bsd-user/main.c (revision d37853f9)
184778508Sblueswir1 /*
24c0a4fe6SWarner Losh  *  qemu bsd user main
384778508Sblueswir1  *
484778508Sblueswir1  *  Copyright (c) 2003-2008 Fabrice Bellard
54c0a4fe6SWarner Losh  *  Copyright (c) 2013-14 Stacey Son
684778508Sblueswir1  *
784778508Sblueswir1  *  This program is free software; you can redistribute it and/or modify
884778508Sblueswir1  *  it under the terms of the GNU General Public License as published by
984778508Sblueswir1  *  the Free Software Foundation; either version 2 of the License, or
1084778508Sblueswir1  *  (at your option) any later version.
1184778508Sblueswir1  *
1284778508Sblueswir1  *  This program is distributed in the hope that it will be useful,
1384778508Sblueswir1  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1484778508Sblueswir1  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1584778508Sblueswir1  *  GNU General Public License for more details.
1684778508Sblueswir1  *
1784778508Sblueswir1  *  You should have received a copy of the GNU General Public License
188167ee88SBlue Swirl  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
1984778508Sblueswir1  */
2014a48c1dSMarkus Armbruster 
212231197cSPeter Maydell #include "qemu/osdep.h"
22a8d25326SMarkus Armbruster #include "qemu-common.h"
2366d26ddbSPhilippe Mathieu-Daudé #include "qemu/units.h"
24940e43aaSClaudio Fontana #include "qemu/accel.h"
2514a48c1dSMarkus Armbruster #include "sysemu/tcg.h"
268c1c230aSEd Maste #include "qemu-version.h"
2784778508Sblueswir1 #include <machine/trap.h>
2884778508Sblueswir1 
29daa76aa4SMarkus Armbruster #include "qapi/error.h"
3084778508Sblueswir1 #include "qemu.h"
316913e79cSLluís Vilanova #include "qemu/config-file.h"
32f5852efaSChristophe Fergeau #include "qemu/error-report.h"
33f348b6d1SVeronia Bahaa #include "qemu/path.h"
34f348b6d1SVeronia Bahaa #include "qemu/help_option.h"
350b8fa32fSMarkus Armbruster #include "qemu/module.h"
3663c91552SPaolo Bonzini #include "exec/exec-all.h"
37dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg.h"
381de7afc9SPaolo Bonzini #include "qemu/timer.h"
391de7afc9SPaolo Bonzini #include "qemu/envlist.h"
4029aabb4fSWarner Losh #include "qemu/cutils.h"
41508127e2SPaolo Bonzini #include "exec/log.h"
426913e79cSLluís Vilanova #include "trace/control.h"
43fc0d96b4SBlue Swirl 
441b530a6dSaurel32 int singlestep;
452fa5d9baSBlue Swirl unsigned long mmap_min_addr;
465ca870b9SRichard Henderson uintptr_t guest_base;
47e307c192SRichard Henderson bool have_guest_base;
48d6ef40bfSPeter Maydell unsigned long reserved_va;
491b530a6dSaurel32 
507ee2822cSPaolo Bonzini static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
51fccae322SPeter Maydell const char *qemu_uname_release;
5278cfb07fSJuergen Lock enum BSDType bsd_type;
5384778508Sblueswir1 
5434bc8475SWarner Losh /*
5534bc8475SWarner Losh  * XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
5634bc8475SWarner Losh  * we allocate a bigger stack. Need a better solution, for example
5734bc8475SWarner Losh  * by remapping the process stack directly at the right place
5834bc8475SWarner Losh  */
5984778508Sblueswir1 unsigned long x86_stack_size = 512 * 1024;
6084778508Sblueswir1 
6184778508Sblueswir1 void gemu_log(const char *fmt, ...)
6284778508Sblueswir1 {
6384778508Sblueswir1     va_list ap;
6484778508Sblueswir1 
6584778508Sblueswir1     va_start(ap, fmt);
6684778508Sblueswir1     vfprintf(stderr, fmt, ap);
6784778508Sblueswir1     va_end(ap);
6884778508Sblueswir1 }
699399f095Sblueswir1 
7031fc12dfSblueswir1 #if defined(TARGET_I386)
71b98e9ca8SAndreas Färber int cpu_get_pic_interrupt(CPUX86State *env)
7231fc12dfSblueswir1 {
7331fc12dfSblueswir1     return -1;
7431fc12dfSblueswir1 }
7531fc12dfSblueswir1 #endif
7631fc12dfSblueswir1 
779399f095Sblueswir1 void fork_start(void)
789399f095Sblueswir1 {
799399f095Sblueswir1 }
809399f095Sblueswir1 
819399f095Sblueswir1 void fork_end(int child)
829399f095Sblueswir1 {
839399f095Sblueswir1     if (child) {
84f7ec7f7bSPeter Crosthwaite         gdbserver_fork(thread_cpu);
859399f095Sblueswir1     }
869399f095Sblueswir1 }
879399f095Sblueswir1 
8831fc12dfSblueswir1 #ifdef TARGET_I386
8931fc12dfSblueswir1 /***********************************************************/
9031fc12dfSblueswir1 /* CPUX86 core interface */
9131fc12dfSblueswir1 
9231fc12dfSblueswir1 uint64_t cpu_get_tsc(CPUX86State *env)
9331fc12dfSblueswir1 {
944a7428c5SChristopher Covington     return cpu_get_host_ticks();
9531fc12dfSblueswir1 }
9631fc12dfSblueswir1 
9731fc12dfSblueswir1 static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
9831fc12dfSblueswir1                      int flags)
9931fc12dfSblueswir1 {
10031fc12dfSblueswir1     unsigned int e1, e2;
10131fc12dfSblueswir1     uint32_t *p;
10231fc12dfSblueswir1     e1 = (addr << 16) | (limit & 0xffff);
10331fc12dfSblueswir1     e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
10431fc12dfSblueswir1     e2 |= flags;
10531fc12dfSblueswir1     p = ptr;
10631fc12dfSblueswir1     p[0] = tswap32(e1);
10731fc12dfSblueswir1     p[1] = tswap32(e2);
10831fc12dfSblueswir1 }
10931fc12dfSblueswir1 
11031fc12dfSblueswir1 static uint64_t *idt_table;
11131fc12dfSblueswir1 #ifdef TARGET_X86_64
11231fc12dfSblueswir1 static void set_gate64(void *ptr, unsigned int type, unsigned int dpl,
11331fc12dfSblueswir1                        uint64_t addr, unsigned int sel)
11431fc12dfSblueswir1 {
11531fc12dfSblueswir1     uint32_t *p, e1, e2;
11631fc12dfSblueswir1     e1 = (addr & 0xffff) | (sel << 16);
11731fc12dfSblueswir1     e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
11831fc12dfSblueswir1     p = ptr;
11931fc12dfSblueswir1     p[0] = tswap32(e1);
12031fc12dfSblueswir1     p[1] = tswap32(e2);
12131fc12dfSblueswir1     p[2] = tswap32(addr >> 32);
12231fc12dfSblueswir1     p[3] = 0;
12331fc12dfSblueswir1 }
12431fc12dfSblueswir1 /* only dpl matters as we do only user space emulation */
12531fc12dfSblueswir1 static void set_idt(int n, unsigned int dpl)
12631fc12dfSblueswir1 {
12731fc12dfSblueswir1     set_gate64(idt_table + n * 2, 0, dpl, 0, 0);
12831fc12dfSblueswir1 }
12931fc12dfSblueswir1 #else
13031fc12dfSblueswir1 static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
13131fc12dfSblueswir1                      uint32_t addr, unsigned int sel)
13231fc12dfSblueswir1 {
13331fc12dfSblueswir1     uint32_t *p, e1, e2;
13431fc12dfSblueswir1     e1 = (addr & 0xffff) | (sel << 16);
13531fc12dfSblueswir1     e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
13631fc12dfSblueswir1     p = ptr;
13731fc12dfSblueswir1     p[0] = tswap32(e1);
13831fc12dfSblueswir1     p[1] = tswap32(e2);
13931fc12dfSblueswir1 }
14031fc12dfSblueswir1 
14131fc12dfSblueswir1 /* only dpl matters as we do only user space emulation */
14231fc12dfSblueswir1 static void set_idt(int n, unsigned int dpl)
14331fc12dfSblueswir1 {
14431fc12dfSblueswir1     set_gate(idt_table + n, 0, dpl, 0, 0);
14531fc12dfSblueswir1 }
14631fc12dfSblueswir1 #endif
14731fc12dfSblueswir1 
14878cfb07fSJuergen Lock void cpu_loop(CPUX86State *env)
14931fc12dfSblueswir1 {
1506aa9e42fSRichard Henderson     CPUState *cs = env_cpu(env);
15131fc12dfSblueswir1     int trapnr;
15231fc12dfSblueswir1     abi_ulong pc;
15381afda4aSWarner Losh     /* target_siginfo_t info; */
15431fc12dfSblueswir1 
15531fc12dfSblueswir1     for (;;) {
156d148d90eSSergey Fedorov         cpu_exec_start(cs);
157ded554cdSSean Bruno         trapnr = cpu_exec(cs);
158d148d90eSSergey Fedorov         cpu_exec_end(cs);
159d148d90eSSergey Fedorov         process_queued_cpu_work(cs);
160d148d90eSSergey Fedorov 
16131fc12dfSblueswir1         switch (trapnr) {
16231fc12dfSblueswir1         case 0x80:
16331fc12dfSblueswir1             /* syscall from int $0x80 */
16478cfb07fSJuergen Lock             if (bsd_type == target_freebsd) {
16578cfb07fSJuergen Lock                 abi_ulong params = (abi_ulong) env->regs[R_ESP] +
16678cfb07fSJuergen Lock                     sizeof(int32_t);
16778cfb07fSJuergen Lock                 int32_t syscall_nr = env->regs[R_EAX];
16878cfb07fSJuergen Lock                 int32_t arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8;
16978cfb07fSJuergen Lock 
17078cfb07fSJuergen Lock                 if (syscall_nr == TARGET_FREEBSD_NR_syscall) {
17178cfb07fSJuergen Lock                     get_user_s32(syscall_nr, params);
17278cfb07fSJuergen Lock                     params += sizeof(int32_t);
17378cfb07fSJuergen Lock                 } else if (syscall_nr == TARGET_FREEBSD_NR___syscall) {
17478cfb07fSJuergen Lock                     get_user_s32(syscall_nr, params);
17578cfb07fSJuergen Lock                     params += sizeof(int64_t);
17678cfb07fSJuergen Lock                 }
17778cfb07fSJuergen Lock                 get_user_s32(arg1, params);
17878cfb07fSJuergen Lock                 params += sizeof(int32_t);
17978cfb07fSJuergen Lock                 get_user_s32(arg2, params);
18078cfb07fSJuergen Lock                 params += sizeof(int32_t);
18178cfb07fSJuergen Lock                 get_user_s32(arg3, params);
18278cfb07fSJuergen Lock                 params += sizeof(int32_t);
18378cfb07fSJuergen Lock                 get_user_s32(arg4, params);
18478cfb07fSJuergen Lock                 params += sizeof(int32_t);
18578cfb07fSJuergen Lock                 get_user_s32(arg5, params);
18678cfb07fSJuergen Lock                 params += sizeof(int32_t);
18778cfb07fSJuergen Lock                 get_user_s32(arg6, params);
18878cfb07fSJuergen Lock                 params += sizeof(int32_t);
18978cfb07fSJuergen Lock                 get_user_s32(arg7, params);
19078cfb07fSJuergen Lock                 params += sizeof(int32_t);
19178cfb07fSJuergen Lock                 get_user_s32(arg8, params);
19278cfb07fSJuergen Lock                 env->regs[R_EAX] = do_freebsd_syscall(env,
19378cfb07fSJuergen Lock                                                       syscall_nr,
19478cfb07fSJuergen Lock                                                       arg1,
19578cfb07fSJuergen Lock                                                       arg2,
19678cfb07fSJuergen Lock                                                       arg3,
19778cfb07fSJuergen Lock                                                       arg4,
19878cfb07fSJuergen Lock                                                       arg5,
19978cfb07fSJuergen Lock                                                       arg6,
20078cfb07fSJuergen Lock                                                       arg7,
20178cfb07fSJuergen Lock                                                       arg8);
20281afda4aSWarner Losh             } else { /* if (bsd_type == target_openbsd) */
20331fc12dfSblueswir1                 env->regs[R_EAX] = do_openbsd_syscall(env,
20431fc12dfSblueswir1                                                       env->regs[R_EAX],
20531fc12dfSblueswir1                                                       env->regs[R_EBX],
20631fc12dfSblueswir1                                                       env->regs[R_ECX],
20731fc12dfSblueswir1                                                       env->regs[R_EDX],
20831fc12dfSblueswir1                                                       env->regs[R_ESI],
20931fc12dfSblueswir1                                                       env->regs[R_EDI],
21031fc12dfSblueswir1                                                       env->regs[R_EBP]);
21178cfb07fSJuergen Lock             }
21278cfb07fSJuergen Lock             if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
21378cfb07fSJuergen Lock                 env->regs[R_EAX] = -env->regs[R_EAX];
21478cfb07fSJuergen Lock                 env->eflags |= CC_C;
21578cfb07fSJuergen Lock             } else {
21678cfb07fSJuergen Lock                 env->eflags &= ~CC_C;
21778cfb07fSJuergen Lock             }
21831fc12dfSblueswir1             break;
21931fc12dfSblueswir1 #ifndef TARGET_ABI32
22031fc12dfSblueswir1         case EXCP_SYSCALL:
2215ba18547SStefan Weil             /* syscall from syscall instruction */
222b23a51dcSWarner Losh             if (bsd_type == target_freebsd) {
22378cfb07fSJuergen Lock                 env->regs[R_EAX] = do_freebsd_syscall(env,
22478cfb07fSJuergen Lock                                                       env->regs[R_EAX],
22578cfb07fSJuergen Lock                                                       env->regs[R_EDI],
22678cfb07fSJuergen Lock                                                       env->regs[R_ESI],
22778cfb07fSJuergen Lock                                                       env->regs[R_EDX],
22878cfb07fSJuergen Lock                                                       env->regs[R_ECX],
22978cfb07fSJuergen Lock                                                       env->regs[8],
23078cfb07fSJuergen Lock                                                       env->regs[9], 0, 0);
231b23a51dcSWarner Losh             } else { /* if (bsd_type == target_openbsd) */
23231fc12dfSblueswir1                 env->regs[R_EAX] = do_openbsd_syscall(env,
23331fc12dfSblueswir1                                                       env->regs[R_EAX],
23431fc12dfSblueswir1                                                       env->regs[R_EDI],
23531fc12dfSblueswir1                                                       env->regs[R_ESI],
23631fc12dfSblueswir1                                                       env->regs[R_EDX],
23731fc12dfSblueswir1                                                       env->regs[10],
23831fc12dfSblueswir1                                                       env->regs[8],
23931fc12dfSblueswir1                                                       env->regs[9]);
24078cfb07fSJuergen Lock             }
24131fc12dfSblueswir1             env->eip = env->exception_next_eip;
24278cfb07fSJuergen Lock             if (((abi_ulong)env->regs[R_EAX]) >= (abi_ulong)(-515)) {
24378cfb07fSJuergen Lock                 env->regs[R_EAX] = -env->regs[R_EAX];
24478cfb07fSJuergen Lock                 env->eflags |= CC_C;
24578cfb07fSJuergen Lock             } else {
24678cfb07fSJuergen Lock                 env->eflags &= ~CC_C;
24778cfb07fSJuergen Lock             }
24831fc12dfSblueswir1             break;
24931fc12dfSblueswir1 #endif
25031fc12dfSblueswir1         case EXCP_INTERRUPT:
25131fc12dfSblueswir1             /* just indicate that signals should be handled asap */
25231fc12dfSblueswir1             break;
25331fc12dfSblueswir1         default:
25431fc12dfSblueswir1             pc = env->segs[R_CS].base + env->eip;
255b23a51dcSWarner Losh             fprintf(stderr,
256b23a51dcSWarner Losh                     "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
25731fc12dfSblueswir1                     (long)pc, trapnr);
25831fc12dfSblueswir1             abort();
25931fc12dfSblueswir1         }
26031fc12dfSblueswir1         process_pending_signals(env);
26131fc12dfSblueswir1     }
26231fc12dfSblueswir1 }
26331fc12dfSblueswir1 #endif
26431fc12dfSblueswir1 
26584778508Sblueswir1 static void usage(void)
26684778508Sblueswir1 {
2677e563bfbSThomas Huth     printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
2680781dd6eSThomas Huth            "\n" QEMU_COPYRIGHT "\n"
2692e59915dSPaolo Bonzini            "usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
27084778508Sblueswir1            "BSD CPU emulator (compiled for %s emulation)\n"
27184778508Sblueswir1            "\n"
27284778508Sblueswir1            "Standard options:\n"
27384778508Sblueswir1            "-h                print this help\n"
27484778508Sblueswir1            "-g port           wait gdb connection to port\n"
27584778508Sblueswir1            "-L path           set the elf interpreter prefix (default=%s)\n"
27684778508Sblueswir1            "-s size           set the stack size in bytes (default=%ld)\n"
277c8057f95SPeter Maydell            "-cpu model        select CPU (-cpu help for list)\n"
27884778508Sblueswir1            "-drop-ld-preload  drop LD_PRELOAD for target process\n"
279fc0d96b4SBlue Swirl            "-E var=value      sets/modifies targets environment variable(s)\n"
280fc0d96b4SBlue Swirl            "-U var            unsets targets environment variable(s)\n"
2812fa5d9baSBlue Swirl            "-B address        set guest_base address to address\n"
28284778508Sblueswir1            "-bsd type         select emulated BSD type FreeBSD/NetBSD/OpenBSD (default)\n"
28384778508Sblueswir1            "\n"
28484778508Sblueswir1            "Debug options:\n"
285989b697dSPeter Maydell            "-d item1[,...]    enable logging of specified items\n"
286989b697dSPeter Maydell            "                  (use '-d help' for a list of log items)\n"
287989b697dSPeter Maydell            "-D logfile        write logs to 'logfile' (default stderr)\n"
28884778508Sblueswir1            "-p pagesize       set the host page size to 'pagesize'\n"
2891b530a6dSaurel32            "-singlestep       always run in singlestep mode\n"
29084778508Sblueswir1            "-strace           log system calls\n"
2916913e79cSLluís Vilanova            "-trace            [[enable=]<pattern>][,events=<file>][,file=<file>]\n"
2926913e79cSLluís Vilanova            "                  specify tracing options\n"
29384778508Sblueswir1            "\n"
29484778508Sblueswir1            "Environment variables:\n"
29584778508Sblueswir1            "QEMU_STRACE       Print system calls and arguments similar to the\n"
29684778508Sblueswir1            "                  'strace' program.  Enable by setting to any value.\n"
297fc0d96b4SBlue Swirl            "You can use -E and -U options to set/unset environment variables\n"
298fc0d96b4SBlue Swirl            "for target process.  It is possible to provide several variables\n"
299fc0d96b4SBlue Swirl            "by repeating the option.  For example:\n"
300fc0d96b4SBlue Swirl            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
301fc0d96b4SBlue Swirl            "Note that if you provide several changes to single variable\n"
302fc0d96b4SBlue Swirl            "last change will stay in effect.\n"
303f5048cb7SEric Blake            "\n"
304f5048cb7SEric Blake            QEMU_HELP_BOTTOM "\n"
30584778508Sblueswir1            ,
3062e59915dSPaolo Bonzini            TARGET_NAME,
30784778508Sblueswir1            interp_prefix,
308989b697dSPeter Maydell            x86_stack_size);
3092d18e637Sblueswir1     exit(1);
31084778508Sblueswir1 }
31184778508Sblueswir1 
312dca1173cSAndreas Färber THREAD CPUState *thread_cpu;
31384778508Sblueswir1 
31448f59211SEd Maste bool qemu_cpu_is_self(CPUState *cpu)
31548f59211SEd Maste {
31648f59211SEd Maste     return thread_cpu == cpu;
31748f59211SEd Maste }
31848f59211SEd Maste 
31948f59211SEd Maste void qemu_cpu_kick(CPUState *cpu)
32048f59211SEd Maste {
32148f59211SEd Maste     cpu_exit(cpu);
32248f59211SEd Maste }
32348f59211SEd Maste 
32484778508Sblueswir1 /* Assumes contents are already zeroed.  */
32584778508Sblueswir1 void init_task_state(TaskState *ts)
32684778508Sblueswir1 {
32784778508Sblueswir1     int i;
32884778508Sblueswir1 
32984778508Sblueswir1     ts->used = 1;
33084778508Sblueswir1     ts->first_free = ts->sigqueue_table;
33184778508Sblueswir1     for (i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) {
33284778508Sblueswir1         ts->sigqueue_table[i].next = &ts->sigqueue_table[i + 1];
33384778508Sblueswir1     }
33484778508Sblueswir1     ts->sigqueue_table[i].next = NULL;
33584778508Sblueswir1 }
33684778508Sblueswir1 
33784778508Sblueswir1 int main(int argc, char **argv)
33884778508Sblueswir1 {
33984778508Sblueswir1     const char *filename;
34084778508Sblueswir1     const char *cpu_model;
3412278b939SIgor Mammedov     const char *cpu_type;
342989b697dSPeter Maydell     const char *log_file = NULL;
343c235d738SMatthew Fernandez     const char *log_mask = NULL;
34484778508Sblueswir1     struct target_pt_regs regs1, *regs = &regs1;
34584778508Sblueswir1     struct image_info info1, *info = &info1;
346*d37853f9SWarner Losh     struct bsd_binprm bprm;
34784778508Sblueswir1     TaskState ts1, *ts = &ts1;
3489349b4f9SAndreas Färber     CPUArchState *env;
349db6b81d4SAndreas Färber     CPUState *cpu;
35029aabb4fSWarner Losh     int optind, rv;
35184778508Sblueswir1     const char *r;
352fcedd920SAlex Bennée     const char *gdbstub = NULL;
353fc0d96b4SBlue Swirl     char **target_environ, **wrk;
354fc0d96b4SBlue Swirl     envlist_t *envlist = NULL;
35578cfb07fSJuergen Lock     bsd_type = target_openbsd;
35684778508Sblueswir1 
357b23a51dcSWarner Losh     if (argc <= 1) {
35884778508Sblueswir1         usage();
359b23a51dcSWarner Losh     }
36084778508Sblueswir1 
361f5852efaSChristophe Fergeau     error_init(argv[0]);
362fe4db84dSDaniel P. Berrange     module_call_init(MODULE_INIT_TRACE);
363267f685bSPaolo Bonzini     qemu_init_cpu_list();
364ce008c1fSAndreas Färber     module_call_init(MODULE_INIT_QOM);
365ce008c1fSAndreas Färber 
366ec45bbe5SSaurav Sachidanand     envlist = envlist_create();
367fc0d96b4SBlue Swirl 
368fc0d96b4SBlue Swirl     /* add current environment into the list */
369fc0d96b4SBlue Swirl     for (wrk = environ; *wrk != NULL; wrk++) {
370fc0d96b4SBlue Swirl         (void) envlist_setenv(envlist, *wrk);
371fc0d96b4SBlue Swirl     }
372fc0d96b4SBlue Swirl 
37384778508Sblueswir1     cpu_model = NULL;
3740c62de2fSJuergen Lock 
3756913e79cSLluís Vilanova     qemu_add_opts(&qemu_trace_opts);
3766913e79cSLluís Vilanova 
37784778508Sblueswir1     optind = 1;
37884778508Sblueswir1     for (;;) {
379b23a51dcSWarner Losh         if (optind >= argc) {
38084778508Sblueswir1             break;
381b23a51dcSWarner Losh         }
38284778508Sblueswir1         r = argv[optind];
383b23a51dcSWarner Losh         if (r[0] != '-') {
38484778508Sblueswir1             break;
385b23a51dcSWarner Losh         }
38684778508Sblueswir1         optind++;
38784778508Sblueswir1         r++;
38884778508Sblueswir1         if (!strcmp(r, "-")) {
38984778508Sblueswir1             break;
39084778508Sblueswir1         } else if (!strcmp(r, "d")) {
391c235d738SMatthew Fernandez             if (optind >= argc) {
39284778508Sblueswir1                 break;
39384778508Sblueswir1             }
394c235d738SMatthew Fernandez             log_mask = argv[optind++];
395c235d738SMatthew Fernandez         } else if (!strcmp(r, "D")) {
396c235d738SMatthew Fernandez             if (optind >= argc) {
397c235d738SMatthew Fernandez                 break;
39884778508Sblueswir1             }
399c235d738SMatthew Fernandez             log_file = argv[optind++];
400fc0d96b4SBlue Swirl         } else if (!strcmp(r, "E")) {
401fc0d96b4SBlue Swirl             r = argv[optind++];
402b23a51dcSWarner Losh             if (envlist_setenv(envlist, r) != 0) {
403fc0d96b4SBlue Swirl                 usage();
404b23a51dcSWarner Losh             }
405f66724c9SStefan Weil         } else if (!strcmp(r, "ignore-environment")) {
406f66724c9SStefan Weil             envlist_free(envlist);
407ec45bbe5SSaurav Sachidanand             envlist = envlist_create();
408fc0d96b4SBlue Swirl         } else if (!strcmp(r, "U")) {
409fc0d96b4SBlue Swirl             r = argv[optind++];
410b23a51dcSWarner Losh             if (envlist_unsetenv(envlist, r) != 0) {
411fc0d96b4SBlue Swirl                 usage();
412b23a51dcSWarner Losh             }
41384778508Sblueswir1         } else if (!strcmp(r, "s")) {
41484778508Sblueswir1             r = argv[optind++];
41529aabb4fSWarner Losh             rv = qemu_strtoul(r, &r, 0, &x86_stack_size);
41629aabb4fSWarner Losh             if (rv < 0 || x86_stack_size <= 0) {
41784778508Sblueswir1                 usage();
418b23a51dcSWarner Losh             }
419b23a51dcSWarner Losh             if (*r == 'M') {
42066d26ddbSPhilippe Mathieu-Daudé                 x86_stack_size *= MiB;
421b23a51dcSWarner Losh             } else if (*r == 'k' || *r == 'K') {
42266d26ddbSPhilippe Mathieu-Daudé                 x86_stack_size *= KiB;
423b23a51dcSWarner Losh             }
42484778508Sblueswir1         } else if (!strcmp(r, "L")) {
42584778508Sblueswir1             interp_prefix = argv[optind++];
42684778508Sblueswir1         } else if (!strcmp(r, "p")) {
42784778508Sblueswir1             qemu_host_page_size = atoi(argv[optind++]);
42884778508Sblueswir1             if (qemu_host_page_size == 0 ||
42984778508Sblueswir1                 (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
43084778508Sblueswir1                 fprintf(stderr, "page size must be a power of two\n");
43184778508Sblueswir1                 exit(1);
43284778508Sblueswir1             }
43384778508Sblueswir1         } else if (!strcmp(r, "g")) {
434fcedd920SAlex Bennée             gdbstub = g_strdup(argv[optind++]);
43584778508Sblueswir1         } else if (!strcmp(r, "r")) {
43684778508Sblueswir1             qemu_uname_release = argv[optind++];
43784778508Sblueswir1         } else if (!strcmp(r, "cpu")) {
43884778508Sblueswir1             cpu_model = argv[optind++];
439c8057f95SPeter Maydell             if (is_help_option(cpu_model)) {
44084778508Sblueswir1                 /* XXX: implement xxx_cpu_list for targets that still miss it */
44184778508Sblueswir1 #if defined(cpu_list)
4420442428aSMarkus Armbruster                 cpu_list();
44384778508Sblueswir1 #endif
4442d18e637Sblueswir1                 exit(1);
44584778508Sblueswir1             }
4462fa5d9baSBlue Swirl         } else if (!strcmp(r, "B")) {
44729aabb4fSWarner Losh             rv = qemu_strtoul(argv[optind++], NULL, 0, &guest_base);
44829aabb4fSWarner Losh             if (rv < 0) {
44929aabb4fSWarner Losh                 usage();
45029aabb4fSWarner Losh             }
451e307c192SRichard Henderson             have_guest_base = true;
45284778508Sblueswir1         } else if (!strcmp(r, "drop-ld-preload")) {
453fc0d96b4SBlue Swirl             (void) envlist_unsetenv(envlist, "LD_PRELOAD");
45484778508Sblueswir1         } else if (!strcmp(r, "bsd")) {
45584778508Sblueswir1             if (!strcasecmp(argv[optind], "freebsd")) {
45684778508Sblueswir1                 bsd_type = target_freebsd;
45784778508Sblueswir1             } else if (!strcasecmp(argv[optind], "netbsd")) {
45884778508Sblueswir1                 bsd_type = target_netbsd;
45984778508Sblueswir1             } else if (!strcasecmp(argv[optind], "openbsd")) {
46084778508Sblueswir1                 bsd_type = target_openbsd;
46184778508Sblueswir1             } else {
46284778508Sblueswir1                 usage();
46384778508Sblueswir1             }
46484778508Sblueswir1             optind++;
4651b530a6dSaurel32         } else if (!strcmp(r, "singlestep")) {
4661b530a6dSaurel32             singlestep = 1;
46784778508Sblueswir1         } else if (!strcmp(r, "strace")) {
46884778508Sblueswir1             do_strace = 1;
4696913e79cSLluís Vilanova         } else if (!strcmp(r, "trace")) {
47092eecfffSPaolo Bonzini             trace_opt_parse(optarg);
4716913e79cSLluís Vilanova         } else {
47284778508Sblueswir1             usage();
47384778508Sblueswir1         }
47484778508Sblueswir1     }
47584778508Sblueswir1 
476c235d738SMatthew Fernandez     /* init debug */
477f2937a33SPaolo Bonzini     qemu_log_needs_buffers();
478daa76aa4SMarkus Armbruster     qemu_set_log_filename(log_file, &error_fatal);
479c235d738SMatthew Fernandez     if (log_mask) {
480c235d738SMatthew Fernandez         int mask;
481c235d738SMatthew Fernandez 
4824fde1ebaSPeter Maydell         mask = qemu_str_to_log_mask(log_mask);
483c235d738SMatthew Fernandez         if (!mask) {
48459a6fa6eSPeter Maydell             qemu_print_log_usage(stdout);
485c235d738SMatthew Fernandez             exit(1);
486c235d738SMatthew Fernandez         }
48724537a01SPeter Maydell         qemu_set_log(mask);
488c235d738SMatthew Fernandez     }
489c235d738SMatthew Fernandez 
4904b5dfd82SPeter Maydell     if (optind >= argc) {
4914b5dfd82SPeter Maydell         usage();
4924b5dfd82SPeter Maydell     }
4934b5dfd82SPeter Maydell     filename = argv[optind];
4944b5dfd82SPeter Maydell 
4956913e79cSLluís Vilanova     if (!trace_init_backends()) {
4966913e79cSLluís Vilanova         exit(1);
4976913e79cSLluís Vilanova     }
49892eecfffSPaolo Bonzini     trace_init_file();
4996913e79cSLluís Vilanova 
50084778508Sblueswir1     /* Zero out regs */
50184778508Sblueswir1     memset(regs, 0, sizeof(struct target_pt_regs));
50284778508Sblueswir1 
503*d37853f9SWarner Losh     /* Zero bsd params */
504*d37853f9SWarner Losh     memset(&bprm, 0, sizeof(bprm));
505*d37853f9SWarner Losh 
50684778508Sblueswir1     /* Zero out image_info */
50784778508Sblueswir1     memset(info, 0, sizeof(struct image_info));
50884778508Sblueswir1 
50984778508Sblueswir1     /* Scan interp_prefix dir for replacement files. */
51084778508Sblueswir1     init_paths(interp_prefix);
51184778508Sblueswir1 
51284778508Sblueswir1     if (cpu_model == NULL) {
51331fc12dfSblueswir1 #if defined(TARGET_I386)
51431fc12dfSblueswir1 #ifdef TARGET_X86_64
51531fc12dfSblueswir1         cpu_model = "qemu64";
51631fc12dfSblueswir1 #else
51731fc12dfSblueswir1         cpu_model = "qemu32";
51831fc12dfSblueswir1 #endif
51984778508Sblueswir1 #else
52084778508Sblueswir1         cpu_model = "any";
52184778508Sblueswir1 #endif
52284778508Sblueswir1     }
5232b5249b8SIgor Mammedov 
524b86f59c7SClaudio Fontana     cpu_type = parse_cpu_option(cpu_model);
5252b5249b8SIgor Mammedov     /* init tcg before creating CPUs and to get qemu_host_page_size */
526940e43aaSClaudio Fontana     {
527940e43aaSClaudio Fontana         AccelClass *ac = ACCEL_GET_CLASS(current_accel());
5282b5249b8SIgor Mammedov 
529b86f59c7SClaudio Fontana         accel_init_interfaces(ac);
53092242f34SClaudio Fontana         ac->init_machine(NULL);
531940e43aaSClaudio Fontana     }
5322278b939SIgor Mammedov     cpu = cpu_create(cpu_type);
5332994fd96SEduardo Habkost     env = cpu->env_ptr;
534db6b81d4SAndreas Färber     cpu_reset(cpu);
535db6b81d4SAndreas Färber     thread_cpu = cpu;
53684778508Sblueswir1 
53784778508Sblueswir1     if (getenv("QEMU_STRACE")) {
53884778508Sblueswir1         do_strace = 1;
53984778508Sblueswir1     }
54084778508Sblueswir1 
541fc0d96b4SBlue Swirl     target_environ = envlist_to_environ(envlist, NULL);
542fc0d96b4SBlue Swirl     envlist_free(envlist);
54384778508Sblueswir1 
5442fa5d9baSBlue Swirl     /*
545fa79cde6SRichard Henderson      * Now that page sizes are configured we can do
5462fa5d9baSBlue Swirl      * proper page alignment for guest_base.
5472fa5d9baSBlue Swirl      */
5482fa5d9baSBlue Swirl     guest_base = HOST_PAGE_ALIGN(guest_base);
5492fa5d9baSBlue Swirl 
5502fa5d9baSBlue Swirl     /*
5512fa5d9baSBlue Swirl      * Read in mmap_min_addr kernel parameter.  This value is used
5522fa5d9baSBlue Swirl      * When loading the ELF image to determine whether guest_base
5532fa5d9baSBlue Swirl      * is needed.
5542fa5d9baSBlue Swirl      *
5552fa5d9baSBlue Swirl      * When user has explicitly set the quest base, we skip this
5562fa5d9baSBlue Swirl      * test.
5572fa5d9baSBlue Swirl      */
5582fa5d9baSBlue Swirl     if (!have_guest_base) {
5592fa5d9baSBlue Swirl         FILE *fp;
5602fa5d9baSBlue Swirl 
561b23a51dcSWarner Losh         fp = fopen("/proc/sys/vm/mmap_min_addr", "r");
562b23a51dcSWarner Losh         if (fp != NULL) {
5632fa5d9baSBlue Swirl             unsigned long tmp;
5642fa5d9baSBlue Swirl             if (fscanf(fp, "%lu", &tmp) == 1) {
5652fa5d9baSBlue Swirl                 mmap_min_addr = tmp;
566b23a51dcSWarner Losh                 qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n",
567b23a51dcSWarner Losh                               mmap_min_addr);
5682fa5d9baSBlue Swirl             }
5692fa5d9baSBlue Swirl             fclose(fp);
5702fa5d9baSBlue Swirl         }
5712fa5d9baSBlue Swirl     }
57284778508Sblueswir1 
573*d37853f9SWarner Losh     if (loader_exec(filename, argv + optind, target_environ, regs, info,
574*d37853f9SWarner Losh                     &bprm) != 0) {
57584778508Sblueswir1         printf("Error loading %s\n", filename);
57684778508Sblueswir1         _exit(1);
57784778508Sblueswir1     }
57884778508Sblueswir1 
57984778508Sblueswir1     for (wrk = target_environ; *wrk; wrk++) {
580ec45bbe5SSaurav Sachidanand         g_free(*wrk);
58184778508Sblueswir1     }
58284778508Sblueswir1 
583ec45bbe5SSaurav Sachidanand     g_free(target_environ);
58484778508Sblueswir1 
58513829020SPaolo Bonzini     if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
5865ca870b9SRichard Henderson         qemu_log("guest_base  %p\n", (void *)guest_base);
58710d0d505SAlex Bennée         log_page_dump("binary load");
58884778508Sblueswir1 
58993fcfe39Saliguori         qemu_log("start_brk   0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
59093fcfe39Saliguori         qemu_log("end_code    0x" TARGET_ABI_FMT_lx "\n", info->end_code);
59193fcfe39Saliguori         qemu_log("start_code  0x" TARGET_ABI_FMT_lx "\n",
59284778508Sblueswir1                  info->start_code);
59393fcfe39Saliguori         qemu_log("start_data  0x" TARGET_ABI_FMT_lx "\n",
59484778508Sblueswir1                  info->start_data);
59593fcfe39Saliguori         qemu_log("end_data    0x" TARGET_ABI_FMT_lx "\n", info->end_data);
59693fcfe39Saliguori         qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n",
59784778508Sblueswir1                  info->start_stack);
59893fcfe39Saliguori         qemu_log("brk         0x" TARGET_ABI_FMT_lx "\n", info->brk);
59993fcfe39Saliguori         qemu_log("entry       0x" TARGET_ABI_FMT_lx "\n", info->entry);
6002e77eac6Sblueswir1     }
60184778508Sblueswir1 
60284778508Sblueswir1     target_set_brk(info->brk);
60384778508Sblueswir1     syscall_init();
60484778508Sblueswir1     signal_init();
60584778508Sblueswir1 
60634bc8475SWarner Losh     /*
60734bc8475SWarner Losh      * Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
60834bc8475SWarner Losh      * generating the prologue until now so that the prologue can take
60934bc8475SWarner Losh      * the real value of GUEST_BASE into account.
61034bc8475SWarner Losh      */
611b1311c4aSEmilio G. Cota     tcg_prologue_init(tcg_ctx);
6129002ec79SRichard Henderson 
61384778508Sblueswir1     /* build Task State */
61484778508Sblueswir1     memset(ts, 0, sizeof(TaskState));
61584778508Sblueswir1     init_task_state(ts);
61684778508Sblueswir1     ts->info = info;
6170429a971SAndreas Färber     cpu->opaque = ts;
61884778508Sblueswir1 
61931fc12dfSblueswir1 #if defined(TARGET_I386)
62031fc12dfSblueswir1     env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
621b98dbc90SPaolo Bonzini     env->hflags |= HF_PE_MASK | HF_CPL_MASK;
6220514ef2fSEduardo Habkost     if (env->features[FEAT_1_EDX] & CPUID_SSE) {
62331fc12dfSblueswir1         env->cr[4] |= CR4_OSFXSR_MASK;
62431fc12dfSblueswir1         env->hflags |= HF_OSFXSR_MASK;
62531fc12dfSblueswir1     }
62631fc12dfSblueswir1 #ifndef TARGET_ABI32
62731fc12dfSblueswir1     /* enable 64 bit mode if possible */
6280514ef2fSEduardo Habkost     if (!(env->features[FEAT_8000_0001_EDX] & CPUID_EXT2_LM)) {
62931fc12dfSblueswir1         fprintf(stderr, "The selected x86 CPU does not support 64 bit mode\n");
63031fc12dfSblueswir1         exit(1);
63131fc12dfSblueswir1     }
63231fc12dfSblueswir1     env->cr[4] |= CR4_PAE_MASK;
63331fc12dfSblueswir1     env->efer |= MSR_EFER_LMA | MSR_EFER_LME;
63431fc12dfSblueswir1     env->hflags |= HF_LMA_MASK;
63531fc12dfSblueswir1 #endif
63631fc12dfSblueswir1 
63731fc12dfSblueswir1     /* flags setup : we activate the IRQs by default as in user mode */
63831fc12dfSblueswir1     env->eflags |= IF_MASK;
63931fc12dfSblueswir1 
64031fc12dfSblueswir1     /* linux register setup */
64131fc12dfSblueswir1 #ifndef TARGET_ABI32
64231fc12dfSblueswir1     env->regs[R_EAX] = regs->rax;
64331fc12dfSblueswir1     env->regs[R_EBX] = regs->rbx;
64431fc12dfSblueswir1     env->regs[R_ECX] = regs->rcx;
64531fc12dfSblueswir1     env->regs[R_EDX] = regs->rdx;
64631fc12dfSblueswir1     env->regs[R_ESI] = regs->rsi;
64731fc12dfSblueswir1     env->regs[R_EDI] = regs->rdi;
64831fc12dfSblueswir1     env->regs[R_EBP] = regs->rbp;
64931fc12dfSblueswir1     env->regs[R_ESP] = regs->rsp;
65031fc12dfSblueswir1     env->eip = regs->rip;
65131fc12dfSblueswir1 #else
65231fc12dfSblueswir1     env->regs[R_EAX] = regs->eax;
65331fc12dfSblueswir1     env->regs[R_EBX] = regs->ebx;
65431fc12dfSblueswir1     env->regs[R_ECX] = regs->ecx;
65531fc12dfSblueswir1     env->regs[R_EDX] = regs->edx;
65631fc12dfSblueswir1     env->regs[R_ESI] = regs->esi;
65731fc12dfSblueswir1     env->regs[R_EDI] = regs->edi;
65831fc12dfSblueswir1     env->regs[R_EBP] = regs->ebp;
65931fc12dfSblueswir1     env->regs[R_ESP] = regs->esp;
66031fc12dfSblueswir1     env->eip = regs->eip;
66131fc12dfSblueswir1 #endif
66231fc12dfSblueswir1 
66331fc12dfSblueswir1     /* linux interrupt setup */
66431fc12dfSblueswir1 #ifndef TARGET_ABI32
66531fc12dfSblueswir1     env->idt.limit = 511;
66631fc12dfSblueswir1 #else
66731fc12dfSblueswir1     env->idt.limit = 255;
66831fc12dfSblueswir1 #endif
66931fc12dfSblueswir1     env->idt.base = target_mmap(0, sizeof(uint64_t) * (env->idt.limit + 1),
67031fc12dfSblueswir1                                 PROT_READ | PROT_WRITE,
67131fc12dfSblueswir1                                 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
6723e8f1628SRichard Henderson     idt_table = g2h_untagged(env->idt.base);
67331fc12dfSblueswir1     set_idt(0, 0);
67431fc12dfSblueswir1     set_idt(1, 0);
67531fc12dfSblueswir1     set_idt(2, 0);
67631fc12dfSblueswir1     set_idt(3, 3);
67731fc12dfSblueswir1     set_idt(4, 3);
67831fc12dfSblueswir1     set_idt(5, 0);
67931fc12dfSblueswir1     set_idt(6, 0);
68031fc12dfSblueswir1     set_idt(7, 0);
68131fc12dfSblueswir1     set_idt(8, 0);
68231fc12dfSblueswir1     set_idt(9, 0);
68331fc12dfSblueswir1     set_idt(10, 0);
68431fc12dfSblueswir1     set_idt(11, 0);
68531fc12dfSblueswir1     set_idt(12, 0);
68631fc12dfSblueswir1     set_idt(13, 0);
68731fc12dfSblueswir1     set_idt(14, 0);
68831fc12dfSblueswir1     set_idt(15, 0);
68931fc12dfSblueswir1     set_idt(16, 0);
69031fc12dfSblueswir1     set_idt(17, 0);
69131fc12dfSblueswir1     set_idt(18, 0);
69231fc12dfSblueswir1     set_idt(19, 0);
69331fc12dfSblueswir1     set_idt(0x80, 3);
69431fc12dfSblueswir1 
69531fc12dfSblueswir1     /* linux segment setup */
69631fc12dfSblueswir1     {
69731fc12dfSblueswir1         uint64_t *gdt_table;
69831fc12dfSblueswir1         env->gdt.base = target_mmap(0, sizeof(uint64_t) * TARGET_GDT_ENTRIES,
69931fc12dfSblueswir1                                     PROT_READ | PROT_WRITE,
70031fc12dfSblueswir1                                     MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
70131fc12dfSblueswir1         env->gdt.limit = sizeof(uint64_t) * TARGET_GDT_ENTRIES - 1;
7023e8f1628SRichard Henderson         gdt_table = g2h_untagged(env->gdt.base);
70331fc12dfSblueswir1 #ifdef TARGET_ABI32
70431fc12dfSblueswir1         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
70531fc12dfSblueswir1                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
70631fc12dfSblueswir1                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
70731fc12dfSblueswir1 #else
70831fc12dfSblueswir1         /* 64 bit code segment */
70931fc12dfSblueswir1         write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
71031fc12dfSblueswir1                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
71131fc12dfSblueswir1                  DESC_L_MASK |
71231fc12dfSblueswir1                  (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
71331fc12dfSblueswir1 #endif
71431fc12dfSblueswir1         write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
71531fc12dfSblueswir1                  DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
71631fc12dfSblueswir1                  (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
71731fc12dfSblueswir1     }
71831fc12dfSblueswir1 
71931fc12dfSblueswir1     cpu_x86_load_seg(env, R_CS, __USER_CS);
72031fc12dfSblueswir1     cpu_x86_load_seg(env, R_SS, __USER_DS);
72131fc12dfSblueswir1 #ifdef TARGET_ABI32
72231fc12dfSblueswir1     cpu_x86_load_seg(env, R_DS, __USER_DS);
72331fc12dfSblueswir1     cpu_x86_load_seg(env, R_ES, __USER_DS);
72431fc12dfSblueswir1     cpu_x86_load_seg(env, R_FS, __USER_DS);
72531fc12dfSblueswir1     cpu_x86_load_seg(env, R_GS, __USER_DS);
72631fc12dfSblueswir1     /* This hack makes Wine work... */
72731fc12dfSblueswir1     env->segs[R_FS].selector = 0;
72831fc12dfSblueswir1 #else
72931fc12dfSblueswir1     cpu_x86_load_seg(env, R_DS, 0);
73031fc12dfSblueswir1     cpu_x86_load_seg(env, R_ES, 0);
73131fc12dfSblueswir1     cpu_x86_load_seg(env, R_FS, 0);
73231fc12dfSblueswir1     cpu_x86_load_seg(env, R_GS, 0);
73331fc12dfSblueswir1 #endif
73484778508Sblueswir1 #else
73584778508Sblueswir1 #error unsupported target CPU
73684778508Sblueswir1 #endif
73784778508Sblueswir1 
738fcedd920SAlex Bennée     if (gdbstub) {
739fcedd920SAlex Bennée         gdbserver_start(gdbstub);
740db6b81d4SAndreas Färber         gdb_handlesig(cpu, 0);
74184778508Sblueswir1     }
74278cfb07fSJuergen Lock     cpu_loop(env);
74384778508Sblueswir1     /* never exits */
74484778508Sblueswir1     return 0;
74584778508Sblueswir1 }
746