xref: /qemu/linux-user/main.c (revision 2113aed6)
131e31b8aSbellard /*
293ac68bcSbellard  *  qemu user main
331e31b8aSbellard  *
468d0f70eSbellard  *  Copyright (c) 2003-2008 Fabrice Bellard
531e31b8aSbellard  *
631e31b8aSbellard  *  This program is free software; you can redistribute it and/or modify
731e31b8aSbellard  *  it under the terms of the GNU General Public License as published by
831e31b8aSbellard  *  the Free Software Foundation; either version 2 of the License, or
931e31b8aSbellard  *  (at your option) any later version.
1031e31b8aSbellard  *
1131e31b8aSbellard  *  This program is distributed in the hope that it will be useful,
1231e31b8aSbellard  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1331e31b8aSbellard  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1431e31b8aSbellard  *  GNU General Public License for more details.
1531e31b8aSbellard  *
1631e31b8aSbellard  *  You should have received a copy of the GNU General Public License
178167ee88SBlue Swirl  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
1831e31b8aSbellard  */
1914a48c1dSMarkus Armbruster 
20d39594e9SPeter Maydell #include "qemu/osdep.h"
21a8d25326SMarkus Armbruster #include "qemu-common.h"
22b52713c1SPhilippe Mathieu-Daudé #include "qemu/units.h"
23940e43aaSClaudio Fontana #include "qemu/accel.h"
2414a48c1dSMarkus Armbruster #include "sysemu/tcg.h"
2567a1de0dSFam Zheng #include "qemu-version.h"
26edf8e2afSMika Westerberg #include <sys/syscall.h>
27703e0e89SRichard Henderson #include <sys/resource.h>
28ee947430SAlex Bennée #include <sys/shm.h>
296e1c0d7bSLaurent Vivier #include <linux/binfmts.h>
3031e31b8aSbellard 
31daa76aa4SMarkus Armbruster #include "qapi/error.h"
323ef693a0Sbellard #include "qemu.h"
33f348b6d1SVeronia Bahaa #include "qemu/path.h"
34dc5e9ac7SMarkus Armbruster #include "qemu/queue.h"
356533dd6eSLluís Vilanova #include "qemu/config-file.h"
36f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
37f5852efaSChristophe Fergeau #include "qemu/error-report.h"
38f348b6d1SVeronia Bahaa #include "qemu/help_option.h"
390b8fa32fSMarkus Armbruster #include "qemu/module.h"
40f308f64eSLluís Vilanova #include "qemu/plugin.h"
4163c91552SPaolo Bonzini #include "exec/exec-all.h"
42dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg.h"
431de7afc9SPaolo Bonzini #include "qemu/timer.h"
441de7afc9SPaolo Bonzini #include "qemu/envlist.h"
455ebdd774SRichard Henderson #include "qemu/guest-random.h"
46d8fd2954SPaul Brook #include "elf.h"
476533dd6eSLluís Vilanova #include "trace/control.h"
48542ca434SLaurent Vivier #include "target_elf.h"
49cd71c089SLaurent Vivier #include "cpu_loop-common.h"
50a573e9baSRichard Henderson #include "crypto/init.h"
51c093364fSOwen Anderson #include "fd-trans.h"
52*2113aed6SPeter Maydell #include "signal-common.h"
5304a6dfebSaurel32 
546e1c0d7bSLaurent Vivier #ifndef AT_FLAGS_PRESERVE_ARGV0
556e1c0d7bSLaurent Vivier #define AT_FLAGS_PRESERVE_ARGV0_BIT 0
566e1c0d7bSLaurent Vivier #define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
576e1c0d7bSLaurent Vivier #endif
586e1c0d7bSLaurent Vivier 
59d088d664Saurel32 char *exec_path;
60d088d664Saurel32 
611b530a6dSaurel32 int singlestep;
628cb76755SStefan Weil static const char *argv0;
63fcedd920SAlex Bennée static const char *gdbstub;
648cb76755SStefan Weil static envlist_t *envlist;
6551fb256aSAndreas Färber static const char *cpu_model;
662278b939SIgor Mammedov static const char *cpu_type;
675ebdd774SRichard Henderson static const char *seed_optarg;
68379f6698SPaul Brook unsigned long mmap_min_addr;
695ca870b9SRichard Henderson uintptr_t guest_base;
70e307c192SRichard Henderson bool have_guest_base;
71120a9848SPaolo Bonzini 
72288e65b9SAlexander Graf /*
734b25a506SJosh Kunz  * Used to implement backwards-compatibility for the `-strace`, and
744b25a506SJosh Kunz  * QEMU_STRACE options. Without this, the QEMU_LOG can be overwritten by
754b25a506SJosh Kunz  * -strace, or vice versa.
764b25a506SJosh Kunz  */
774b25a506SJosh Kunz static bool enable_strace;
784b25a506SJosh Kunz 
794b25a506SJosh Kunz /*
804b25a506SJosh Kunz  * The last log mask given by the user in an environment variable or argument.
814b25a506SJosh Kunz  * Used to support command line arguments overriding environment variables.
824b25a506SJosh Kunz  */
834b25a506SJosh Kunz static int last_log_mask;
844b25a506SJosh Kunz 
854b25a506SJosh Kunz /*
86288e65b9SAlexander Graf  * When running 32-on-64 we should make sure we can fit all of the possible
87288e65b9SAlexander Graf  * guest address space into a contiguous chunk of virtual host memory.
88288e65b9SAlexander Graf  *
89288e65b9SAlexander Graf  * This way we will never overlap with our own libraries or binaries or stack
90288e65b9SAlexander Graf  * or anything else that QEMU maps.
9118e80c55SRichard Henderson  *
9218e80c55SRichard Henderson  * Many cpus reserve the high bit (or more than one for some 64-bit cpus)
9318e80c55SRichard Henderson  * of the address for the kernel.  Some cpus rely on this and user space
9418e80c55SRichard Henderson  * uses the high bit(s) for pointer tagging and the like.  For them, we
9518e80c55SRichard Henderson  * must preserve the expected address space.
96288e65b9SAlexander Graf  */
9718e80c55SRichard Henderson #ifndef MAX_RESERVED_VA
9818e80c55SRichard Henderson # if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
9918e80c55SRichard Henderson #  if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \
10018e80c55SRichard Henderson       (TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
10118e80c55SRichard Henderson /* There are a number of places where we assign reserved_va to a variable
10218e80c55SRichard Henderson    of type abi_ulong and expect it to fit.  Avoid the last page.  */
1038f67b9c6SRichard Henderson #   define MAX_RESERVED_VA(CPU)  (0xfffffffful & TARGET_PAGE_MASK)
104314992b1SAlexander Graf #  else
1058f67b9c6SRichard Henderson #   define MAX_RESERVED_VA(CPU)  (1ul << TARGET_VIRT_ADDR_SPACE_BITS)
106314992b1SAlexander Graf #  endif
107288e65b9SAlexander Graf # else
1088f67b9c6SRichard Henderson #  define MAX_RESERVED_VA(CPU)  0
10918e80c55SRichard Henderson # endif
11018e80c55SRichard Henderson #endif
11118e80c55SRichard Henderson 
11268a1c816SPaul Brook unsigned long reserved_va;
1131b530a6dSaurel32 
114d03f9c32SMeador Inge static void usage(int exitcode);
115fc9c5412SJohannes Schauer 
1167ee2822cSPaolo Bonzini static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
117e586822aSRiku Voipio const char *qemu_uname_release;
118586314f2Sbellard 
1199de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
1209de5e440Sbellard    we allocate a bigger stack. Need a better solution, for example
1219de5e440Sbellard    by remapping the process stack directly at the right place */
122703e0e89SRichard Henderson unsigned long guest_stack_size = 8 * 1024 * 1024UL;
12331e31b8aSbellard 
1248fcd3692Sblueswir1 #if defined(TARGET_I386)
12505390248SAndreas Färber int cpu_get_pic_interrupt(CPUX86State *env)
12692ccca6aSbellard {
12792ccca6aSbellard     return -1;
12892ccca6aSbellard }
1298fcd3692Sblueswir1 #endif
13092ccca6aSbellard 
131d5975363Spbrook /***********************************************************/
132d5975363Spbrook /* Helper routines for implementing atomic operations.  */
133d5975363Spbrook 
134d5975363Spbrook /* Make sure everything is in a consistent state for calling fork().  */
135d5975363Spbrook void fork_start(void)
136d5975363Spbrook {
13706065c45SPeter Maydell     start_exclusive();
138d032d1b4SRiku Voipio     mmap_fork_start();
139024949caSPeter Maydell     cpu_list_lock();
140d5975363Spbrook }
141d5975363Spbrook 
142d5975363Spbrook void fork_end(int child)
143d5975363Spbrook {
144d032d1b4SRiku Voipio     mmap_fork_end(child);
145d5975363Spbrook     if (child) {
146bdc44640SAndreas Färber         CPUState *cpu, *next_cpu;
147d5975363Spbrook         /* Child processes created by fork() only have a single thread.
148d5975363Spbrook            Discard information about the parent threads.  */
149bdc44640SAndreas Färber         CPU_FOREACH_SAFE(cpu, next_cpu) {
150bdc44640SAndreas Färber             if (cpu != thread_cpu) {
151068a5ea0SEmilio G. Cota                 QTAILQ_REMOVE_RCU(&cpus, cpu, node);
152bdc44640SAndreas Färber             }
153bdc44640SAndreas Färber         }
154267f685bSPaolo Bonzini         qemu_init_cpu_list();
155f7ec7f7bSPeter Crosthwaite         gdbserver_fork(thread_cpu);
15606065c45SPeter Maydell         /* qemu_init_cpu_list() takes care of reinitializing the
15706065c45SPeter Maydell          * exclusive state, so we don't need to end_exclusive() here.
15806065c45SPeter Maydell          */
159d5975363Spbrook     } else {
160267f685bSPaolo Bonzini         cpu_list_unlock();
16106065c45SPeter Maydell         end_exclusive();
162d5975363Spbrook     }
163d5975363Spbrook }
164d5975363Spbrook 
165b44316fbSPeter Maydell __thread CPUState *thread_cpu;
16659faf6d6Sbellard 
167178f9429SSergey Fedorov bool qemu_cpu_is_self(CPUState *cpu)
168178f9429SSergey Fedorov {
169178f9429SSergey Fedorov     return thread_cpu == cpu;
170178f9429SSergey Fedorov }
171178f9429SSergey Fedorov 
172178f9429SSergey Fedorov void qemu_cpu_kick(CPUState *cpu)
173178f9429SSergey Fedorov {
174178f9429SSergey Fedorov     cpu_exit(cpu);
175178f9429SSergey Fedorov }
176178f9429SSergey Fedorov 
177edf8e2afSMika Westerberg void task_settid(TaskState *ts)
178edf8e2afSMika Westerberg {
179edf8e2afSMika Westerberg     if (ts->ts_tid == 0) {
180edf8e2afSMika Westerberg         ts->ts_tid = (pid_t)syscall(SYS_gettid);
181edf8e2afSMika Westerberg     }
182edf8e2afSMika Westerberg }
183edf8e2afSMika Westerberg 
184edf8e2afSMika Westerberg void stop_all_tasks(void)
185edf8e2afSMika Westerberg {
186edf8e2afSMika Westerberg     /*
187edf8e2afSMika Westerberg      * We trust that when using NPTL, start_exclusive()
188edf8e2afSMika Westerberg      * handles thread stopping correctly.
189edf8e2afSMika Westerberg      */
190edf8e2afSMika Westerberg     start_exclusive();
191edf8e2afSMika Westerberg }
192edf8e2afSMika Westerberg 
193c3a92833Spbrook /* Assumes contents are already zeroed.  */
194624f7979Spbrook void init_task_state(TaskState *ts)
195624f7979Spbrook {
196624f7979Spbrook     ts->used = 1;
1975bfce0b7SPeter Maydell     ts->sigaltstack_used = (struct target_sigaltstack) {
1985bfce0b7SPeter Maydell         .ss_sp = 0,
1995bfce0b7SPeter Maydell         .ss_size = 0,
2005bfce0b7SPeter Maydell         .ss_flags = TARGET_SS_DISABLE,
2015bfce0b7SPeter Maydell     };
202624f7979Spbrook }
2039de5e440Sbellard 
20430ba0ee5SAndreas Färber CPUArchState *cpu_copy(CPUArchState *env)
20530ba0ee5SAndreas Färber {
20629a0af61SRichard Henderson     CPUState *cpu = env_cpu(env);
2072278b939SIgor Mammedov     CPUState *new_cpu = cpu_create(cpu_type);
20861c7480fSLeon Alrae     CPUArchState *new_env = new_cpu->env_ptr;
20930ba0ee5SAndreas Färber     CPUBreakpoint *bp;
21030ba0ee5SAndreas Färber 
21130ba0ee5SAndreas Färber     /* Reset non arch specific state */
21275a34036SAndreas Färber     cpu_reset(new_cpu);
21330ba0ee5SAndreas Färber 
2146cc9d67cSRichard Henderson     new_cpu->tcg_cflags = cpu->tcg_cflags;
21530ba0ee5SAndreas Färber     memcpy(new_env, env, sizeof(CPUArchState));
21630ba0ee5SAndreas Färber 
21730ba0ee5SAndreas Färber     /* Clone all break/watchpoints.
21830ba0ee5SAndreas Färber        Note: Once we support ptrace with hw-debug register access, make sure
21930ba0ee5SAndreas Färber        BP_CPU break/watchpoints are handled correctly on clone. */
2201d085f6cSThierry Bultel     QTAILQ_INIT(&new_cpu->breakpoints);
221f0c3c505SAndreas Färber     QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
222b3310ab3SAndreas Färber         cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
22330ba0ee5SAndreas Färber     }
22430ba0ee5SAndreas Färber 
22530ba0ee5SAndreas Färber     return new_env;
22630ba0ee5SAndreas Färber }
22730ba0ee5SAndreas Färber 
228fc9c5412SJohannes Schauer static void handle_arg_help(const char *arg)
229fc9c5412SJohannes Schauer {
2304d1275c2SRiku Voipio     usage(EXIT_SUCCESS);
231fc9c5412SJohannes Schauer }
232fc9c5412SJohannes Schauer 
233fc9c5412SJohannes Schauer static void handle_arg_log(const char *arg)
234fc9c5412SJohannes Schauer {
2354b25a506SJosh Kunz     last_log_mask = qemu_str_to_log_mask(arg);
2364b25a506SJosh Kunz     if (!last_log_mask) {
23759a6fa6eSPeter Maydell         qemu_print_log_usage(stdout);
2384d1275c2SRiku Voipio         exit(EXIT_FAILURE);
239fc9c5412SJohannes Schauer     }
240fc9c5412SJohannes Schauer }
241fc9c5412SJohannes Schauer 
2428423fa90SAlex Bennée static void handle_arg_dfilter(const char *arg)
2438423fa90SAlex Bennée {
2447f4341e8SAlex Bennée     qemu_set_dfilter_ranges(arg, &error_fatal);
2458423fa90SAlex Bennée }
2468423fa90SAlex Bennée 
24750171d42S陳韋任 static void handle_arg_log_filename(const char *arg)
24850171d42S陳韋任 {
249daa76aa4SMarkus Armbruster     qemu_set_log_filename(arg, &error_fatal);
25050171d42S陳韋任 }
25150171d42S陳韋任 
252fc9c5412SJohannes Schauer static void handle_arg_set_env(const char *arg)
253fc9c5412SJohannes Schauer {
254fc9c5412SJohannes Schauer     char *r, *p, *token;
255fc9c5412SJohannes Schauer     r = p = strdup(arg);
256fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
257fc9c5412SJohannes Schauer         if (envlist_setenv(envlist, token) != 0) {
2584d1275c2SRiku Voipio             usage(EXIT_FAILURE);
259fc9c5412SJohannes Schauer         }
260fc9c5412SJohannes Schauer     }
261fc9c5412SJohannes Schauer     free(r);
262fc9c5412SJohannes Schauer }
263fc9c5412SJohannes Schauer 
264fc9c5412SJohannes Schauer static void handle_arg_unset_env(const char *arg)
265fc9c5412SJohannes Schauer {
266fc9c5412SJohannes Schauer     char *r, *p, *token;
267fc9c5412SJohannes Schauer     r = p = strdup(arg);
268fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
269fc9c5412SJohannes Schauer         if (envlist_unsetenv(envlist, token) != 0) {
2704d1275c2SRiku Voipio             usage(EXIT_FAILURE);
271fc9c5412SJohannes Schauer         }
272fc9c5412SJohannes Schauer     }
273fc9c5412SJohannes Schauer     free(r);
274fc9c5412SJohannes Schauer }
275fc9c5412SJohannes Schauer 
276fc9c5412SJohannes Schauer static void handle_arg_argv0(const char *arg)
277fc9c5412SJohannes Schauer {
278fc9c5412SJohannes Schauer     argv0 = strdup(arg);
279fc9c5412SJohannes Schauer }
280fc9c5412SJohannes Schauer 
281fc9c5412SJohannes Schauer static void handle_arg_stack_size(const char *arg)
282fc9c5412SJohannes Schauer {
283fc9c5412SJohannes Schauer     char *p;
284fc9c5412SJohannes Schauer     guest_stack_size = strtoul(arg, &p, 0);
285fc9c5412SJohannes Schauer     if (guest_stack_size == 0) {
2864d1275c2SRiku Voipio         usage(EXIT_FAILURE);
287fc9c5412SJohannes Schauer     }
288fc9c5412SJohannes Schauer 
289fc9c5412SJohannes Schauer     if (*p == 'M') {
290b52713c1SPhilippe Mathieu-Daudé         guest_stack_size *= MiB;
291fc9c5412SJohannes Schauer     } else if (*p == 'k' || *p == 'K') {
292b52713c1SPhilippe Mathieu-Daudé         guest_stack_size *= KiB;
293fc9c5412SJohannes Schauer     }
294fc9c5412SJohannes Schauer }
295fc9c5412SJohannes Schauer 
296fc9c5412SJohannes Schauer static void handle_arg_ld_prefix(const char *arg)
297fc9c5412SJohannes Schauer {
298fc9c5412SJohannes Schauer     interp_prefix = strdup(arg);
299fc9c5412SJohannes Schauer }
300fc9c5412SJohannes Schauer 
301fc9c5412SJohannes Schauer static void handle_arg_pagesize(const char *arg)
302fc9c5412SJohannes Schauer {
303fc9c5412SJohannes Schauer     qemu_host_page_size = atoi(arg);
304fc9c5412SJohannes Schauer     if (qemu_host_page_size == 0 ||
305fc9c5412SJohannes Schauer         (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
306fc9c5412SJohannes Schauer         fprintf(stderr, "page size must be a power of two\n");
3074d1275c2SRiku Voipio         exit(EXIT_FAILURE);
308fc9c5412SJohannes Schauer     }
309fc9c5412SJohannes Schauer }
310fc9c5412SJohannes Schauer 
3115ebdd774SRichard Henderson static void handle_arg_seed(const char *arg)
312c5e4a5a9SMagnus Reftel {
3135ebdd774SRichard Henderson     seed_optarg = arg;
314c5e4a5a9SMagnus Reftel }
315c5e4a5a9SMagnus Reftel 
316fc9c5412SJohannes Schauer static void handle_arg_gdb(const char *arg)
317fc9c5412SJohannes Schauer {
318fcedd920SAlex Bennée     gdbstub = g_strdup(arg);
319fc9c5412SJohannes Schauer }
320fc9c5412SJohannes Schauer 
321fc9c5412SJohannes Schauer static void handle_arg_uname(const char *arg)
322fc9c5412SJohannes Schauer {
323fc9c5412SJohannes Schauer     qemu_uname_release = strdup(arg);
324fc9c5412SJohannes Schauer }
325fc9c5412SJohannes Schauer 
326fc9c5412SJohannes Schauer static void handle_arg_cpu(const char *arg)
327fc9c5412SJohannes Schauer {
328fc9c5412SJohannes Schauer     cpu_model = strdup(arg);
329c8057f95SPeter Maydell     if (cpu_model == NULL || is_help_option(cpu_model)) {
330fc9c5412SJohannes Schauer         /* XXX: implement xxx_cpu_list for targets that still miss it */
331e916cbf8SPeter Maydell #if defined(cpu_list)
3320442428aSMarkus Armbruster         cpu_list();
333fc9c5412SJohannes Schauer #endif
3344d1275c2SRiku Voipio         exit(EXIT_FAILURE);
335fc9c5412SJohannes Schauer     }
336fc9c5412SJohannes Schauer }
337fc9c5412SJohannes Schauer 
338fc9c5412SJohannes Schauer static void handle_arg_guest_base(const char *arg)
339fc9c5412SJohannes Schauer {
340fc9c5412SJohannes Schauer     guest_base = strtol(arg, NULL, 0);
341e307c192SRichard Henderson     have_guest_base = true;
342fc9c5412SJohannes Schauer }
343fc9c5412SJohannes Schauer 
344fc9c5412SJohannes Schauer static void handle_arg_reserved_va(const char *arg)
345fc9c5412SJohannes Schauer {
346fc9c5412SJohannes Schauer     char *p;
347fc9c5412SJohannes Schauer     int shift = 0;
348fc9c5412SJohannes Schauer     reserved_va = strtoul(arg, &p, 0);
349fc9c5412SJohannes Schauer     switch (*p) {
350fc9c5412SJohannes Schauer     case 'k':
351fc9c5412SJohannes Schauer     case 'K':
352fc9c5412SJohannes Schauer         shift = 10;
353fc9c5412SJohannes Schauer         break;
354fc9c5412SJohannes Schauer     case 'M':
355fc9c5412SJohannes Schauer         shift = 20;
356fc9c5412SJohannes Schauer         break;
357fc9c5412SJohannes Schauer     case 'G':
358fc9c5412SJohannes Schauer         shift = 30;
359fc9c5412SJohannes Schauer         break;
360fc9c5412SJohannes Schauer     }
361fc9c5412SJohannes Schauer     if (shift) {
362fc9c5412SJohannes Schauer         unsigned long unshifted = reserved_va;
363fc9c5412SJohannes Schauer         p++;
364fc9c5412SJohannes Schauer         reserved_va <<= shift;
3658f67b9c6SRichard Henderson         if (reserved_va >> shift != unshifted) {
366fc9c5412SJohannes Schauer             fprintf(stderr, "Reserved virtual address too big\n");
3674d1275c2SRiku Voipio             exit(EXIT_FAILURE);
368fc9c5412SJohannes Schauer         }
369fc9c5412SJohannes Schauer     }
370fc9c5412SJohannes Schauer     if (*p) {
371fc9c5412SJohannes Schauer         fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
3724d1275c2SRiku Voipio         exit(EXIT_FAILURE);
373fc9c5412SJohannes Schauer     }
374fc9c5412SJohannes Schauer }
375fc9c5412SJohannes Schauer 
376fc9c5412SJohannes Schauer static void handle_arg_singlestep(const char *arg)
377fc9c5412SJohannes Schauer {
378fc9c5412SJohannes Schauer     singlestep = 1;
379fc9c5412SJohannes Schauer }
380fc9c5412SJohannes Schauer 
381fc9c5412SJohannes Schauer static void handle_arg_strace(const char *arg)
382fc9c5412SJohannes Schauer {
3834b25a506SJosh Kunz     enable_strace = true;
384fc9c5412SJohannes Schauer }
385fc9c5412SJohannes Schauer 
386fc9c5412SJohannes Schauer static void handle_arg_version(const char *arg)
387fc9c5412SJohannes Schauer {
3887e563bfbSThomas Huth     printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
3890781dd6eSThomas Huth            "\n" QEMU_COPYRIGHT "\n");
3904d1275c2SRiku Voipio     exit(EXIT_SUCCESS);
391fc9c5412SJohannes Schauer }
392fc9c5412SJohannes Schauer 
3936533dd6eSLluís Vilanova static void handle_arg_trace(const char *arg)
3946533dd6eSLluís Vilanova {
39592eecfffSPaolo Bonzini     trace_opt_parse(arg);
3966533dd6eSLluís Vilanova }
3976533dd6eSLluís Vilanova 
398130ea832SMax Filippov #if defined(TARGET_XTENSA)
399130ea832SMax Filippov static void handle_arg_abi_call0(const char *arg)
400130ea832SMax Filippov {
401130ea832SMax Filippov     xtensa_set_abi_call0();
402130ea832SMax Filippov }
403130ea832SMax Filippov #endif
404130ea832SMax Filippov 
405f308f64eSLluís Vilanova static QemuPluginList plugins = QTAILQ_HEAD_INITIALIZER(plugins);
406f308f64eSLluís Vilanova 
407f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
408f308f64eSLluís Vilanova static void handle_arg_plugin(const char *arg)
409f308f64eSLluís Vilanova {
410f308f64eSLluís Vilanova     qemu_plugin_opt_parse(arg, &plugins);
411f308f64eSLluís Vilanova }
412f308f64eSLluís Vilanova #endif
413f308f64eSLluís Vilanova 
414fc9c5412SJohannes Schauer struct qemu_argument {
415fc9c5412SJohannes Schauer     const char *argv;
416fc9c5412SJohannes Schauer     const char *env;
417fc9c5412SJohannes Schauer     bool has_arg;
418fc9c5412SJohannes Schauer     void (*handle_opt)(const char *arg);
419fc9c5412SJohannes Schauer     const char *example;
420fc9c5412SJohannes Schauer     const char *help;
421fc9c5412SJohannes Schauer };
422fc9c5412SJohannes Schauer 
42342644ceeSJim Meyering static const struct qemu_argument arg_table[] = {
424fc9c5412SJohannes Schauer     {"h",          "",                 false, handle_arg_help,
425fc9c5412SJohannes Schauer      "",           "print this help"},
426daaf8c8eSMeador Inge     {"help",       "",                 false, handle_arg_help,
427daaf8c8eSMeador Inge      "",           ""},
428fc9c5412SJohannes Schauer     {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
429fc9c5412SJohannes Schauer      "port",       "wait gdb connection to 'port'"},
430fc9c5412SJohannes Schauer     {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
431fc9c5412SJohannes Schauer      "path",       "set the elf interpreter prefix to 'path'"},
432fc9c5412SJohannes Schauer     {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
433fc9c5412SJohannes Schauer      "size",       "set the stack size to 'size' bytes"},
434fc9c5412SJohannes Schauer     {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
435c8057f95SPeter Maydell      "model",      "select CPU (-cpu help for list)"},
436fc9c5412SJohannes Schauer     {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
437fc9c5412SJohannes Schauer      "var=value",  "sets targets environment variable (see below)"},
438fc9c5412SJohannes Schauer     {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
439fc9c5412SJohannes Schauer      "var",        "unsets targets environment variable (see below)"},
440fc9c5412SJohannes Schauer     {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
441fc9c5412SJohannes Schauer      "argv0",      "forces target process argv[0] to be 'argv0'"},
442fc9c5412SJohannes Schauer     {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
443fc9c5412SJohannes Schauer      "uname",      "set qemu uname release string to 'uname'"},
444fc9c5412SJohannes Schauer     {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
445fc9c5412SJohannes Schauer      "address",    "set guest_base address to 'address'"},
446fc9c5412SJohannes Schauer     {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
447fc9c5412SJohannes Schauer      "size",       "reserve 'size' bytes for guest virtual address space"},
448fc9c5412SJohannes Schauer     {"d",          "QEMU_LOG",         true,  handle_arg_log,
449989b697dSPeter Maydell      "item[,...]", "enable logging of specified items "
450989b697dSPeter Maydell      "(use '-d help' for a list of items)"},
4518423fa90SAlex Bennée     {"dfilter",    "QEMU_DFILTER",     true,  handle_arg_dfilter,
4528423fa90SAlex Bennée      "range[,...]","filter logging based on address range"},
45350171d42S陳韋任     {"D",          "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
454989b697dSPeter Maydell      "logfile",     "write logs to 'logfile' (default stderr)"},
455fc9c5412SJohannes Schauer     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
456fc9c5412SJohannes Schauer      "pagesize",   "set the host page size to 'pagesize'"},
457fc9c5412SJohannes Schauer     {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
458fc9c5412SJohannes Schauer      "",           "run in singlestep mode"},
459fc9c5412SJohannes Schauer     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
460fc9c5412SJohannes Schauer      "",           "log system calls"},
4615ebdd774SRichard Henderson     {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_seed,
462c5e4a5a9SMagnus Reftel      "",           "Seed for pseudo-random number generator"},
4636533dd6eSLluís Vilanova     {"trace",      "QEMU_TRACE",       true,  handle_arg_trace,
4646533dd6eSLluís Vilanova      "",           "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
465f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
466f308f64eSLluís Vilanova     {"plugin",     "QEMU_PLUGIN",      true,  handle_arg_plugin,
4673a445acbSMahmoud Mandour      "",           "[file=]<file>[,<argname>=<argvalue>]"},
468f308f64eSLluís Vilanova #endif
469fc9c5412SJohannes Schauer     {"version",    "QEMU_VERSION",     false, handle_arg_version,
4701386d4c0SPeter Maydell      "",           "display version information and exit"},
471130ea832SMax Filippov #if defined(TARGET_XTENSA)
472130ea832SMax Filippov     {"xtensa-abi-call0", "QEMU_XTENSA_ABI_CALL0", false, handle_arg_abi_call0,
473130ea832SMax Filippov      "",           "assume CALL0 Xtensa ABI"},
474130ea832SMax Filippov #endif
475fc9c5412SJohannes Schauer     {NULL, NULL, false, NULL, NULL, NULL}
476fc9c5412SJohannes Schauer };
477fc9c5412SJohannes Schauer 
478d03f9c32SMeador Inge static void usage(int exitcode)
479fc9c5412SJohannes Schauer {
48042644ceeSJim Meyering     const struct qemu_argument *arginfo;
481fc9c5412SJohannes Schauer     int maxarglen;
482fc9c5412SJohannes Schauer     int maxenvlen;
483fc9c5412SJohannes Schauer 
4842e59915dSPaolo Bonzini     printf("usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
4852e59915dSPaolo Bonzini            "Linux CPU emulator (compiled for " TARGET_NAME " emulation)\n"
486fc9c5412SJohannes Schauer            "\n"
487fc9c5412SJohannes Schauer            "Options and associated environment variables:\n"
488fc9c5412SJohannes Schauer            "\n");
489fc9c5412SJohannes Schauer 
49063ec54d7SPeter Maydell     /* Calculate column widths. We must always have at least enough space
49163ec54d7SPeter Maydell      * for the column header.
49263ec54d7SPeter Maydell      */
49363ec54d7SPeter Maydell     maxarglen = strlen("Argument");
49463ec54d7SPeter Maydell     maxenvlen = strlen("Env-variable");
495fc9c5412SJohannes Schauer 
496fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
49763ec54d7SPeter Maydell         int arglen = strlen(arginfo->argv);
49863ec54d7SPeter Maydell         if (arginfo->has_arg) {
49963ec54d7SPeter Maydell             arglen += strlen(arginfo->example) + 1;
50063ec54d7SPeter Maydell         }
501fc9c5412SJohannes Schauer         if (strlen(arginfo->env) > maxenvlen) {
502fc9c5412SJohannes Schauer             maxenvlen = strlen(arginfo->env);
503fc9c5412SJohannes Schauer         }
50463ec54d7SPeter Maydell         if (arglen > maxarglen) {
50563ec54d7SPeter Maydell             maxarglen = arglen;
506fc9c5412SJohannes Schauer         }
507fc9c5412SJohannes Schauer     }
508fc9c5412SJohannes Schauer 
50963ec54d7SPeter Maydell     printf("%-*s %-*s Description\n", maxarglen+1, "Argument",
51063ec54d7SPeter Maydell             maxenvlen, "Env-variable");
511fc9c5412SJohannes Schauer 
512fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
513fc9c5412SJohannes Schauer         if (arginfo->has_arg) {
514fc9c5412SJohannes Schauer             printf("-%s %-*s %-*s %s\n", arginfo->argv,
51563ec54d7SPeter Maydell                    (int)(maxarglen - strlen(arginfo->argv) - 1),
51663ec54d7SPeter Maydell                    arginfo->example, maxenvlen, arginfo->env, arginfo->help);
517fc9c5412SJohannes Schauer         } else {
51863ec54d7SPeter Maydell             printf("-%-*s %-*s %s\n", maxarglen, arginfo->argv,
519fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env,
520fc9c5412SJohannes Schauer                     arginfo->help);
521fc9c5412SJohannes Schauer         }
522fc9c5412SJohannes Schauer     }
523fc9c5412SJohannes Schauer 
524fc9c5412SJohannes Schauer     printf("\n"
525fc9c5412SJohannes Schauer            "Defaults:\n"
526fc9c5412SJohannes Schauer            "QEMU_LD_PREFIX  = %s\n"
527989b697dSPeter Maydell            "QEMU_STACK_SIZE = %ld byte\n",
528fc9c5412SJohannes Schauer            interp_prefix,
529989b697dSPeter Maydell            guest_stack_size);
530fc9c5412SJohannes Schauer 
531fc9c5412SJohannes Schauer     printf("\n"
532fc9c5412SJohannes Schauer            "You can use -E and -U options or the QEMU_SET_ENV and\n"
533fc9c5412SJohannes Schauer            "QEMU_UNSET_ENV environment variables to set and unset\n"
534fc9c5412SJohannes Schauer            "environment variables for the target process.\n"
535fc9c5412SJohannes Schauer            "It is possible to provide several variables by separating them\n"
536fc9c5412SJohannes Schauer            "by commas in getsubopt(3) style. Additionally it is possible to\n"
537fc9c5412SJohannes Schauer            "provide the -E and -U options multiple times.\n"
538fc9c5412SJohannes Schauer            "The following lines are equivalent:\n"
539fc9c5412SJohannes Schauer            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
540fc9c5412SJohannes Schauer            "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
541fc9c5412SJohannes Schauer            "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
542fc9c5412SJohannes Schauer            "Note that if you provide several changes to a single variable\n"
543f5048cb7SEric Blake            "the last change will stay in effect.\n"
544f5048cb7SEric Blake            "\n"
545f5048cb7SEric Blake            QEMU_HELP_BOTTOM "\n");
546fc9c5412SJohannes Schauer 
547d03f9c32SMeador Inge     exit(exitcode);
548fc9c5412SJohannes Schauer }
549fc9c5412SJohannes Schauer 
550fc9c5412SJohannes Schauer static int parse_args(int argc, char **argv)
551fc9c5412SJohannes Schauer {
552fc9c5412SJohannes Schauer     const char *r;
553fc9c5412SJohannes Schauer     int optind;
55442644ceeSJim Meyering     const struct qemu_argument *arginfo;
555fc9c5412SJohannes Schauer 
556fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
557fc9c5412SJohannes Schauer         if (arginfo->env == NULL) {
558fc9c5412SJohannes Schauer             continue;
559fc9c5412SJohannes Schauer         }
560fc9c5412SJohannes Schauer 
561fc9c5412SJohannes Schauer         r = getenv(arginfo->env);
562fc9c5412SJohannes Schauer         if (r != NULL) {
563fc9c5412SJohannes Schauer             arginfo->handle_opt(r);
564fc9c5412SJohannes Schauer         }
565fc9c5412SJohannes Schauer     }
566fc9c5412SJohannes Schauer 
567fc9c5412SJohannes Schauer     optind = 1;
568fc9c5412SJohannes Schauer     for (;;) {
569fc9c5412SJohannes Schauer         if (optind >= argc) {
570fc9c5412SJohannes Schauer             break;
571fc9c5412SJohannes Schauer         }
572fc9c5412SJohannes Schauer         r = argv[optind];
573fc9c5412SJohannes Schauer         if (r[0] != '-') {
574fc9c5412SJohannes Schauer             break;
575fc9c5412SJohannes Schauer         }
576fc9c5412SJohannes Schauer         optind++;
577fc9c5412SJohannes Schauer         r++;
578fc9c5412SJohannes Schauer         if (!strcmp(r, "-")) {
579fc9c5412SJohannes Schauer             break;
580fc9c5412SJohannes Schauer         }
581ba02577cSMeador Inge         /* Treat --foo the same as -foo.  */
582ba02577cSMeador Inge         if (r[0] == '-') {
583ba02577cSMeador Inge             r++;
584ba02577cSMeador Inge         }
585fc9c5412SJohannes Schauer 
586fc9c5412SJohannes Schauer         for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
587fc9c5412SJohannes Schauer             if (!strcmp(r, arginfo->argv)) {
5881386d4c0SPeter Maydell                 if (arginfo->has_arg) {
589fc9c5412SJohannes Schauer                     if (optind >= argc) {
590138940bfSMeador Inge                         (void) fprintf(stderr,
591138940bfSMeador Inge                             "qemu: missing argument for option '%s'\n", r);
5924d1275c2SRiku Voipio                         exit(EXIT_FAILURE);
593fc9c5412SJohannes Schauer                     }
594fc9c5412SJohannes Schauer                     arginfo->handle_opt(argv[optind]);
595fc9c5412SJohannes Schauer                     optind++;
5961386d4c0SPeter Maydell                 } else {
5971386d4c0SPeter Maydell                     arginfo->handle_opt(NULL);
598fc9c5412SJohannes Schauer                 }
599fc9c5412SJohannes Schauer                 break;
600fc9c5412SJohannes Schauer             }
601fc9c5412SJohannes Schauer         }
602fc9c5412SJohannes Schauer 
603fc9c5412SJohannes Schauer         /* no option matched the current argv */
604fc9c5412SJohannes Schauer         if (arginfo->handle_opt == NULL) {
605138940bfSMeador Inge             (void) fprintf(stderr, "qemu: unknown option '%s'\n", r);
6064d1275c2SRiku Voipio             exit(EXIT_FAILURE);
607fc9c5412SJohannes Schauer         }
608fc9c5412SJohannes Schauer     }
609fc9c5412SJohannes Schauer 
610fc9c5412SJohannes Schauer     if (optind >= argc) {
611138940bfSMeador Inge         (void) fprintf(stderr, "qemu: no user program specified\n");
6124d1275c2SRiku Voipio         exit(EXIT_FAILURE);
613fc9c5412SJohannes Schauer     }
614fc9c5412SJohannes Schauer 
615fc9c5412SJohannes Schauer     exec_path = argv[optind];
616fc9c5412SJohannes Schauer 
617fc9c5412SJohannes Schauer     return optind;
618fc9c5412SJohannes Schauer }
619fc9c5412SJohannes Schauer 
620902b3d5cSmalc int main(int argc, char **argv, char **envp)
62131e31b8aSbellard {
62201ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
62331e31b8aSbellard     struct image_info info1, *info = &info1;
624edf8e2afSMika Westerberg     struct linux_binprm bprm;
62548e15fc2SNathan Froyd     TaskState *ts;
6269349b4f9SAndreas Färber     CPUArchState *env;
627db6b81d4SAndreas Färber     CPUState *cpu;
628586314f2Sbellard     int optind;
62904a6dfebSaurel32     char **target_environ, **wrk;
6307d8cec95Saurel32     char **target_argv;
6317d8cec95Saurel32     int target_argc;
6327d8cec95Saurel32     int i;
633fd4d81ddSArnaud Patard     int ret;
63403cfd8faSLaurent Vivier     int execfd;
6354b25a506SJosh Kunz     int log_mask;
6368f67b9c6SRichard Henderson     unsigned long max_reserved_va;
6376e1c0d7bSLaurent Vivier     bool preserve_argv0;
63831e31b8aSbellard 
639f5852efaSChristophe Fergeau     error_init(argv[0]);
640fe4db84dSDaniel P. Berrange     module_call_init(MODULE_INIT_TRACE);
641267f685bSPaolo Bonzini     qemu_init_cpu_list();
642ce008c1fSAndreas Färber     module_call_init(MODULE_INIT_QOM);
643ce008c1fSAndreas Färber 
644ec45bbe5SSaurav Sachidanand     envlist = envlist_create();
64504a6dfebSaurel32 
64604a6dfebSaurel32     /* add current environment into the list */
64704a6dfebSaurel32     for (wrk = environ; *wrk != NULL; wrk++) {
64804a6dfebSaurel32         (void) envlist_setenv(envlist, *wrk);
64904a6dfebSaurel32     }
65004a6dfebSaurel32 
651703e0e89SRichard Henderson     /* Read the stack limit from the kernel.  If it's "unlimited",
652703e0e89SRichard Henderson        then we can do little else besides use the default.  */
653703e0e89SRichard Henderson     {
654703e0e89SRichard Henderson         struct rlimit lim;
655703e0e89SRichard Henderson         if (getrlimit(RLIMIT_STACK, &lim) == 0
65681bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur != RLIM_INFINITY
65781bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur == (target_long)lim.rlim_cur) {
658703e0e89SRichard Henderson             guest_stack_size = lim.rlim_cur;
659703e0e89SRichard Henderson         }
660703e0e89SRichard Henderson     }
661703e0e89SRichard Henderson 
662b1f9be31Sj_mayer     cpu_model = NULL;
663b5ec5ce0Sjohn cooper 
6646533dd6eSLluís Vilanova     qemu_add_opts(&qemu_trace_opts);
665f308f64eSLluís Vilanova     qemu_plugin_add_opts();
6666533dd6eSLluís Vilanova 
667fc9c5412SJohannes Schauer     optind = parse_args(argc, argv);
6684b5dfd82SPeter Maydell 
6694b25a506SJosh Kunz     log_mask = last_log_mask | (enable_strace ? LOG_STRACE : 0);
6704b25a506SJosh Kunz     if (log_mask) {
6714b25a506SJosh Kunz         qemu_log_needs_buffers();
6724b25a506SJosh Kunz         qemu_set_log(log_mask);
6734b25a506SJosh Kunz     }
6744b25a506SJosh Kunz 
6756533dd6eSLluís Vilanova     if (!trace_init_backends()) {
6766533dd6eSLluís Vilanova         exit(1);
6776533dd6eSLluís Vilanova     }
67892eecfffSPaolo Bonzini     trace_init_file();
6790572f558SPaolo Bonzini     qemu_plugin_load_list(&plugins, &error_fatal);
6806533dd6eSLluís Vilanova 
68131e31b8aSbellard     /* Zero out regs */
68201ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
68331e31b8aSbellard 
68431e31b8aSbellard     /* Zero out image_info */
68531e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
68631e31b8aSbellard 
687edf8e2afSMika Westerberg     memset(&bprm, 0, sizeof (bprm));
688edf8e2afSMika Westerberg 
68974cd30b8Sbellard     /* Scan interp_prefix dir for replacement files. */
69074cd30b8Sbellard     init_paths(interp_prefix);
69174cd30b8Sbellard 
6924a24a758SPeter Maydell     init_qemu_uname_release();
6934a24a758SPeter Maydell 
6946e1c0d7bSLaurent Vivier     /*
6956e1c0d7bSLaurent Vivier      * Manage binfmt-misc open-binary flag
6966e1c0d7bSLaurent Vivier      */
697768fe76eSYunQiang Su     execfd = qemu_getauxval(AT_EXECFD);
698768fe76eSYunQiang Su     if (execfd == 0) {
6999d3019bcSLaurent Vivier         execfd = open(exec_path, O_RDONLY);
700768fe76eSYunQiang Su         if (execfd < 0) {
7019d3019bcSLaurent Vivier             printf("Error while loading %s: %s\n", exec_path, strerror(errno));
702768fe76eSYunQiang Su             _exit(EXIT_FAILURE);
703768fe76eSYunQiang Su         }
704768fe76eSYunQiang Su     }
705768fe76eSYunQiang Su 
7066e1c0d7bSLaurent Vivier     /*
7076e1c0d7bSLaurent Vivier      * get binfmt_misc flags
7086e1c0d7bSLaurent Vivier      */
7096e1c0d7bSLaurent Vivier     preserve_argv0 = !!(qemu_getauxval(AT_FLAGS) & AT_FLAGS_PRESERVE_ARGV0);
7106e1c0d7bSLaurent Vivier 
7116e1c0d7bSLaurent Vivier     /*
7126e1c0d7bSLaurent Vivier      * Manage binfmt-misc preserve-arg[0] flag
7136e1c0d7bSLaurent Vivier      *    argv[optind]     full path to the binary
7146e1c0d7bSLaurent Vivier      *    argv[optind + 1] original argv[0]
7156e1c0d7bSLaurent Vivier      */
7166e1c0d7bSLaurent Vivier     if (optind + 1 < argc && preserve_argv0) {
7176e1c0d7bSLaurent Vivier         optind++;
7186e1c0d7bSLaurent Vivier     }
7196e1c0d7bSLaurent Vivier 
72046027c07Sbellard     if (cpu_model == NULL) {
721768fe76eSYunQiang Su         cpu_model = cpu_get_model(get_elf_eflags(execfd));
722aaed909aSbellard     }
723c1c8cfe5SEduardo Habkost     cpu_type = parse_cpu_option(cpu_model);
7242278b939SIgor Mammedov 
7252b5249b8SIgor Mammedov     /* init tcg before creating CPUs and to get qemu_host_page_size */
726940e43aaSClaudio Fontana     {
727940e43aaSClaudio Fontana         AccelClass *ac = ACCEL_GET_CLASS(current_accel());
7282278b939SIgor Mammedov 
729b86f59c7SClaudio Fontana         accel_init_interfaces(ac);
73092242f34SClaudio Fontana         ac->init_machine(NULL);
731940e43aaSClaudio Fontana     }
7322278b939SIgor Mammedov     cpu = cpu_create(cpu_type);
7332994fd96SEduardo Habkost     env = cpu->env_ptr;
7340ac46af3SAndreas Färber     cpu_reset(cpu);
735db6b81d4SAndreas Färber     thread_cpu = cpu;
73654936004Sbellard 
7378f67b9c6SRichard Henderson     /*
7388f67b9c6SRichard Henderson      * Reserving too much vm space via mmap can run into problems
7398f67b9c6SRichard Henderson      * with rlimits, oom due to page table creation, etc.  We will
7408f67b9c6SRichard Henderson      * still try it, if directed by the command-line option, but
7418f67b9c6SRichard Henderson      * not by default.
7428f67b9c6SRichard Henderson      */
7438f67b9c6SRichard Henderson     max_reserved_va = MAX_RESERVED_VA(cpu);
7448f67b9c6SRichard Henderson     if (reserved_va != 0) {
7458f67b9c6SRichard Henderson         if (max_reserved_va && reserved_va > max_reserved_va) {
7468f67b9c6SRichard Henderson             fprintf(stderr, "Reserved virtual address too big\n");
7478f67b9c6SRichard Henderson             exit(EXIT_FAILURE);
7488f67b9c6SRichard Henderson         }
7498f67b9c6SRichard Henderson     } else if (HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32) {
7508f67b9c6SRichard Henderson         /*
7518f67b9c6SRichard Henderson          * reserved_va must be aligned with the host page size
7528f67b9c6SRichard Henderson          * as it is used with mmap()
7538f67b9c6SRichard Henderson          */
7548f67b9c6SRichard Henderson         reserved_va = max_reserved_va & qemu_host_page_mask;
7558f67b9c6SRichard Henderson     }
7568f67b9c6SRichard Henderson 
757a573e9baSRichard Henderson     {
758a573e9baSRichard Henderson         Error *err = NULL;
7595ebdd774SRichard Henderson         if (seed_optarg != NULL) {
760a573e9baSRichard Henderson             qemu_guest_random_seed_main(seed_optarg, &err);
761a573e9baSRichard Henderson         } else {
762a573e9baSRichard Henderson             qcrypto_init(&err);
763a573e9baSRichard Henderson         }
764a573e9baSRichard Henderson         if (err) {
765a573e9baSRichard Henderson             error_reportf_err(err, "cannot initialize crypto: ");
766a573e9baSRichard Henderson             exit(1);
767a573e9baSRichard Henderson         }
768c5e4a5a9SMagnus Reftel     }
769c5e4a5a9SMagnus Reftel 
77004a6dfebSaurel32     target_environ = envlist_to_environ(envlist, NULL);
77104a6dfebSaurel32     envlist_free(envlist);
772b12b6a18Sths 
773379f6698SPaul Brook     /*
774379f6698SPaul Brook      * Read in mmap_min_addr kernel parameter.  This value is used
775379f6698SPaul Brook      * When loading the ELF image to determine whether guest_base
77614f24e14SRichard Henderson      * is needed.  It is also used in mmap_find_vma.
777379f6698SPaul Brook      */
77814f24e14SRichard Henderson     {
779379f6698SPaul Brook         FILE *fp;
780379f6698SPaul Brook 
781379f6698SPaul Brook         if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
782379f6698SPaul Brook             unsigned long tmp;
783c9f80666SRichard Henderson             if (fscanf(fp, "%lu", &tmp) == 1 && tmp != 0) {
784379f6698SPaul Brook                 mmap_min_addr = tmp;
785c9f80666SRichard Henderson                 qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n",
786c9f80666SRichard Henderson                               mmap_min_addr);
787379f6698SPaul Brook             }
788379f6698SPaul Brook             fclose(fp);
789379f6698SPaul Brook         }
790379f6698SPaul Brook     }
791379f6698SPaul Brook 
7927d8cec95Saurel32     /*
793c9f80666SRichard Henderson      * We prefer to not make NULL pointers accessible to QEMU.
794c9f80666SRichard Henderson      * If we're in a chroot with no /proc, fall back to 1 page.
795c9f80666SRichard Henderson      */
796c9f80666SRichard Henderson     if (mmap_min_addr == 0) {
797c9f80666SRichard Henderson         mmap_min_addr = qemu_host_page_size;
798c9f80666SRichard Henderson         qemu_log_mask(CPU_LOG_PAGE,
799c9f80666SRichard Henderson                       "host mmap_min_addr=0x%lx (fallback)\n",
800c9f80666SRichard Henderson                       mmap_min_addr);
801c9f80666SRichard Henderson     }
802c9f80666SRichard Henderson 
803c9f80666SRichard Henderson     /*
8047d8cec95Saurel32      * Prepare copy of argv vector for target.
8057d8cec95Saurel32      */
8067d8cec95Saurel32     target_argc = argc - optind;
8077d8cec95Saurel32     target_argv = calloc(target_argc + 1, sizeof (char *));
8087d8cec95Saurel32     if (target_argv == NULL) {
8097d8cec95Saurel32         (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
8104d1275c2SRiku Voipio         exit(EXIT_FAILURE);
8117d8cec95Saurel32     }
8127d8cec95Saurel32 
8137d8cec95Saurel32     /*
8147d8cec95Saurel32      * If argv0 is specified (using '-0' switch) we replace
8157d8cec95Saurel32      * argv[0] pointer with the given one.
8167d8cec95Saurel32      */
8177d8cec95Saurel32     i = 0;
8187d8cec95Saurel32     if (argv0 != NULL) {
8197d8cec95Saurel32         target_argv[i++] = strdup(argv0);
8207d8cec95Saurel32     }
8217d8cec95Saurel32     for (; i < target_argc; i++) {
8227d8cec95Saurel32         target_argv[i] = strdup(argv[optind + i]);
8237d8cec95Saurel32     }
8247d8cec95Saurel32     target_argv[target_argc] = NULL;
8257d8cec95Saurel32 
826c78d65e8SMarkus Armbruster     ts = g_new0(TaskState, 1);
827edf8e2afSMika Westerberg     init_task_state(ts);
828edf8e2afSMika Westerberg     /* build Task State */
829edf8e2afSMika Westerberg     ts->info = info;
830edf8e2afSMika Westerberg     ts->bprm = &bprm;
8310429a971SAndreas Färber     cpu->opaque = ts;
832edf8e2afSMika Westerberg     task_settid(ts);
833edf8e2afSMika Westerberg 
834c093364fSOwen Anderson     fd_trans_init();
835c093364fSOwen Anderson 
8369d3019bcSLaurent Vivier     ret = loader_exec(execfd, exec_path, target_argv, target_environ, regs,
837fd4d81ddSArnaud Patard         info, &bprm);
838fd4d81ddSArnaud Patard     if (ret != 0) {
8399d3019bcSLaurent Vivier         printf("Error while loading %s: %s\n", exec_path, strerror(-ret));
8404d1275c2SRiku Voipio         _exit(EXIT_FAILURE);
84131e31b8aSbellard     }
84231e31b8aSbellard 
843b12b6a18Sths     for (wrk = target_environ; *wrk; wrk++) {
844ec45bbe5SSaurav Sachidanand         g_free(*wrk);
845b12b6a18Sths     }
846b12b6a18Sths 
847ec45bbe5SSaurav Sachidanand     g_free(target_environ);
848b12b6a18Sths 
84913829020SPaolo Bonzini     if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
8505ca870b9SRichard Henderson         qemu_log("guest_base  %p\n", (void *)guest_base);
85110d0d505SAlex Bennée         log_page_dump("binary load");
85254936004Sbellard 
85393fcfe39Saliguori         qemu_log("start_brk   0x" TARGET_ABI_FMT_lx "\n", info->start_brk);
85493fcfe39Saliguori         qemu_log("end_code    0x" TARGET_ABI_FMT_lx "\n", info->end_code);
8557c4ee5bcSRichard Henderson         qemu_log("start_code  0x" TARGET_ABI_FMT_lx "\n", info->start_code);
8567c4ee5bcSRichard Henderson         qemu_log("start_data  0x" TARGET_ABI_FMT_lx "\n", info->start_data);
85793fcfe39Saliguori         qemu_log("end_data    0x" TARGET_ABI_FMT_lx "\n", info->end_data);
8587c4ee5bcSRichard Henderson         qemu_log("start_stack 0x" TARGET_ABI_FMT_lx "\n", info->start_stack);
85993fcfe39Saliguori         qemu_log("brk         0x" TARGET_ABI_FMT_lx "\n", info->brk);
86093fcfe39Saliguori         qemu_log("entry       0x" TARGET_ABI_FMT_lx "\n", info->entry);
8617c4ee5bcSRichard Henderson         qemu_log("argv_start  0x" TARGET_ABI_FMT_lx "\n", info->arg_start);
8627c4ee5bcSRichard Henderson         qemu_log("env_start   0x" TARGET_ABI_FMT_lx "\n",
8637c4ee5bcSRichard Henderson                  info->arg_end + (abi_ulong)sizeof(abi_ulong));
8647c4ee5bcSRichard Henderson         qemu_log("auxv_start  0x" TARGET_ABI_FMT_lx "\n", info->saved_auxv);
8652e77eac6Sblueswir1     }
86631e31b8aSbellard 
86753a5960aSpbrook     target_set_brk(info->brk);
86831e31b8aSbellard     syscall_init();
86966fb9763Sbellard     signal_init();
87031e31b8aSbellard 
8719002ec79SRichard Henderson     /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
8729002ec79SRichard Henderson        generating the prologue until now so that the prologue can take
8739002ec79SRichard Henderson        the real value of GUEST_BASE into account.  */
874b1311c4aSEmilio G. Cota     tcg_prologue_init(tcg_ctx);
8759002ec79SRichard Henderson 
876cd71c089SLaurent Vivier     target_cpu_copy_regs(env, regs);
877cd71c089SLaurent Vivier 
878fcedd920SAlex Bennée     if (gdbstub) {
879fcedd920SAlex Bennée         if (gdbserver_start(gdbstub) < 0) {
880fcedd920SAlex Bennée             fprintf(stderr, "qemu: could not open gdbserver on %s\n",
881fcedd920SAlex Bennée                     gdbstub);
8824d1275c2SRiku Voipio             exit(EXIT_FAILURE);
883ff7a981aSPeter Maydell         }
884db6b81d4SAndreas Färber         gdb_handlesig(cpu, 0);
8851fddef4bSbellard     }
8861b6b029eSbellard     cpu_loop(env);
8871b6b029eSbellard     /* never exits */
88831e31b8aSbellard     return 0;
88931e31b8aSbellard }
890