xref: /qemu/linux-user/main.c (revision 7de0816f)
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"
2149f95221SMarc-André Lureau #include "qemu/help-texts.h"
22b52713c1SPhilippe Mathieu-Daudé #include "qemu/units.h"
23940e43aaSClaudio Fontana #include "qemu/accel.h"
2467a1de0dSFam Zheng #include "qemu-version.h"
25edf8e2afSMika Westerberg #include <sys/syscall.h>
26703e0e89SRichard Henderson #include <sys/resource.h>
27ee947430SAlex Bennée #include <sys/shm.h>
286e1c0d7bSLaurent Vivier #include <linux/binfmts.h>
2931e31b8aSbellard 
30daa76aa4SMarkus Armbruster #include "qapi/error.h"
313ef693a0Sbellard #include "qemu.h"
323b249d26SPeter Maydell #include "user-internals.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"
4285b4fa0cSPeter Maydell #include "exec/gdbstub.h"
43dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg.h"
441de7afc9SPaolo Bonzini #include "qemu/timer.h"
451de7afc9SPaolo Bonzini #include "qemu/envlist.h"
465ebdd774SRichard Henderson #include "qemu/guest-random.h"
47d8fd2954SPaul Brook #include "elf.h"
486533dd6eSLluís Vilanova #include "trace/control.h"
49542ca434SLaurent Vivier #include "target_elf.h"
50cd71c089SLaurent Vivier #include "cpu_loop-common.h"
51a573e9baSRichard Henderson #include "crypto/init.h"
52c093364fSOwen Anderson #include "fd-trans.h"
532113aed6SPeter Maydell #include "signal-common.h"
543ad0a769SPeter Maydell #include "loader.h"
555423e6d3SPeter Maydell #include "user-mmap.h"
565584e2dbSIlya Leoshkevich #include "accel/tcg/perf.h"
5704a6dfebSaurel32 
58e4a4aaa5SRichard Henderson #ifdef CONFIG_SEMIHOSTING
59e4a4aaa5SRichard Henderson #include "semihosting/semihost.h"
60e4a4aaa5SRichard Henderson #endif
61e4a4aaa5SRichard Henderson 
626e1c0d7bSLaurent Vivier #ifndef AT_FLAGS_PRESERVE_ARGV0
636e1c0d7bSLaurent Vivier #define AT_FLAGS_PRESERVE_ARGV0_BIT 0
646e1c0d7bSLaurent Vivier #define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
656e1c0d7bSLaurent Vivier #endif
666e1c0d7bSLaurent Vivier 
67d088d664Saurel32 char *exec_path;
68d088d664Saurel32 
691b530a6dSaurel32 int singlestep;
708cb76755SStefan Weil static const char *argv0;
71fcedd920SAlex Bennée static const char *gdbstub;
728cb76755SStefan Weil static envlist_t *envlist;
7351fb256aSAndreas Färber static const char *cpu_model;
742278b939SIgor Mammedov static const char *cpu_type;
755ebdd774SRichard Henderson static const char *seed_optarg;
76379f6698SPaul Brook unsigned long mmap_min_addr;
775ca870b9SRichard Henderson uintptr_t guest_base;
78e307c192SRichard Henderson bool have_guest_base;
79120a9848SPaolo Bonzini 
80288e65b9SAlexander Graf /*
814b25a506SJosh Kunz  * Used to implement backwards-compatibility for the `-strace`, and
824b25a506SJosh Kunz  * QEMU_STRACE options. Without this, the QEMU_LOG can be overwritten by
834b25a506SJosh Kunz  * -strace, or vice versa.
844b25a506SJosh Kunz  */
854b25a506SJosh Kunz static bool enable_strace;
864b25a506SJosh Kunz 
874b25a506SJosh Kunz /*
884b25a506SJosh Kunz  * The last log mask given by the user in an environment variable or argument.
894b25a506SJosh Kunz  * Used to support command line arguments overriding environment variables.
904b25a506SJosh Kunz  */
914b25a506SJosh Kunz static int last_log_mask;
92b410253fSRichard Henderson static const char *last_log_filename;
934b25a506SJosh Kunz 
944b25a506SJosh Kunz /*
95288e65b9SAlexander Graf  * When running 32-on-64 we should make sure we can fit all of the possible
96288e65b9SAlexander Graf  * guest address space into a contiguous chunk of virtual host memory.
97288e65b9SAlexander Graf  *
98288e65b9SAlexander Graf  * This way we will never overlap with our own libraries or binaries or stack
99288e65b9SAlexander Graf  * or anything else that QEMU maps.
10018e80c55SRichard Henderson  *
10118e80c55SRichard Henderson  * Many cpus reserve the high bit (or more than one for some 64-bit cpus)
10218e80c55SRichard Henderson  * of the address for the kernel.  Some cpus rely on this and user space
10318e80c55SRichard Henderson  * uses the high bit(s) for pointer tagging and the like.  For them, we
10418e80c55SRichard Henderson  * must preserve the expected address space.
105288e65b9SAlexander Graf  */
10618e80c55SRichard Henderson #ifndef MAX_RESERVED_VA
10718e80c55SRichard Henderson # if HOST_LONG_BITS > TARGET_VIRT_ADDR_SPACE_BITS
10818e80c55SRichard Henderson #  if TARGET_VIRT_ADDR_SPACE_BITS == 32 && \
10918e80c55SRichard Henderson       (TARGET_LONG_BITS == 32 || defined(TARGET_ABI32))
11018e80c55SRichard Henderson /* There are a number of places where we assign reserved_va to a variable
11118e80c55SRichard Henderson    of type abi_ulong and expect it to fit.  Avoid the last page.  */
1128f67b9c6SRichard Henderson #   define MAX_RESERVED_VA(CPU)  (0xfffffffful & TARGET_PAGE_MASK)
113314992b1SAlexander Graf #  else
1148f67b9c6SRichard Henderson #   define MAX_RESERVED_VA(CPU)  (1ul << TARGET_VIRT_ADDR_SPACE_BITS)
115314992b1SAlexander Graf #  endif
116288e65b9SAlexander Graf # else
1178f67b9c6SRichard Henderson #  define MAX_RESERVED_VA(CPU)  0
11818e80c55SRichard Henderson # endif
11918e80c55SRichard Henderson #endif
12018e80c55SRichard Henderson 
12168a1c816SPaul Brook unsigned long reserved_va;
1221b530a6dSaurel32 
123d03f9c32SMeador Inge static void usage(int exitcode);
124fc9c5412SJohannes Schauer 
1257ee2822cSPaolo Bonzini static const char *interp_prefix = CONFIG_QEMU_INTERP_PREFIX;
126e586822aSRiku Voipio const char *qemu_uname_release;
127586314f2Sbellard 
1280a3346b5SHelge Deller #if !defined(TARGET_DEFAULT_STACK_SIZE)
1299de5e440Sbellard /* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
1309de5e440Sbellard    we allocate a bigger stack. Need a better solution, for example
1319de5e440Sbellard    by remapping the process stack directly at the right place */
1320a3346b5SHelge Deller #define TARGET_DEFAULT_STACK_SIZE	8 * 1024 * 1024UL
1330a3346b5SHelge Deller #endif
1340a3346b5SHelge Deller 
1350a3346b5SHelge Deller unsigned long guest_stack_size = TARGET_DEFAULT_STACK_SIZE;
13631e31b8aSbellard 
137d5975363Spbrook /***********************************************************/
138d5975363Spbrook /* Helper routines for implementing atomic operations.  */
139d5975363Spbrook 
140d5975363Spbrook /* Make sure everything is in a consistent state for calling fork().  */
141d5975363Spbrook void fork_start(void)
142d5975363Spbrook {
14306065c45SPeter Maydell     start_exclusive();
144d032d1b4SRiku Voipio     mmap_fork_start();
145024949caSPeter Maydell     cpu_list_lock();
146f7e15affSAlex Bennée     qemu_plugin_user_prefork_lock();
147d5975363Spbrook }
148d5975363Spbrook 
149d5975363Spbrook void fork_end(int child)
150d5975363Spbrook {
151f7e15affSAlex Bennée     qemu_plugin_user_postfork(child);
152d032d1b4SRiku Voipio     mmap_fork_end(child);
153d5975363Spbrook     if (child) {
154bdc44640SAndreas Färber         CPUState *cpu, *next_cpu;
155d5975363Spbrook         /* Child processes created by fork() only have a single thread.
156d5975363Spbrook            Discard information about the parent threads.  */
157bdc44640SAndreas Färber         CPU_FOREACH_SAFE(cpu, next_cpu) {
158bdc44640SAndreas Färber             if (cpu != thread_cpu) {
159068a5ea0SEmilio G. Cota                 QTAILQ_REMOVE_RCU(&cpus, cpu, node);
160bdc44640SAndreas Färber             }
161bdc44640SAndreas Färber         }
162267f685bSPaolo Bonzini         qemu_init_cpu_list();
163f7ec7f7bSPeter Crosthwaite         gdbserver_fork(thread_cpu);
164d5975363Spbrook     } else {
165267f685bSPaolo Bonzini         cpu_list_unlock();
166d5975363Spbrook     }
1677de0816fSIlya Leoshkevich     /*
1687de0816fSIlya Leoshkevich      * qemu_init_cpu_list() reinitialized the child exclusive state, but we
1697de0816fSIlya Leoshkevich      * also need to keep current_cpu consistent, so call end_exclusive() for
1707de0816fSIlya Leoshkevich      * both child and parent.
1717de0816fSIlya Leoshkevich      */
1727de0816fSIlya Leoshkevich     end_exclusive();
173d5975363Spbrook }
174d5975363Spbrook 
175b44316fbSPeter Maydell __thread CPUState *thread_cpu;
17659faf6d6Sbellard 
177178f9429SSergey Fedorov bool qemu_cpu_is_self(CPUState *cpu)
178178f9429SSergey Fedorov {
179178f9429SSergey Fedorov     return thread_cpu == cpu;
180178f9429SSergey Fedorov }
181178f9429SSergey Fedorov 
182178f9429SSergey Fedorov void qemu_cpu_kick(CPUState *cpu)
183178f9429SSergey Fedorov {
184178f9429SSergey Fedorov     cpu_exit(cpu);
185178f9429SSergey Fedorov }
186178f9429SSergey Fedorov 
187edf8e2afSMika Westerberg void task_settid(TaskState *ts)
188edf8e2afSMika Westerberg {
189edf8e2afSMika Westerberg     if (ts->ts_tid == 0) {
190edf8e2afSMika Westerberg         ts->ts_tid = (pid_t)syscall(SYS_gettid);
191edf8e2afSMika Westerberg     }
192edf8e2afSMika Westerberg }
193edf8e2afSMika Westerberg 
194edf8e2afSMika Westerberg void stop_all_tasks(void)
195edf8e2afSMika Westerberg {
196edf8e2afSMika Westerberg     /*
197edf8e2afSMika Westerberg      * We trust that when using NPTL, start_exclusive()
198edf8e2afSMika Westerberg      * handles thread stopping correctly.
199edf8e2afSMika Westerberg      */
200edf8e2afSMika Westerberg     start_exclusive();
201edf8e2afSMika Westerberg }
202edf8e2afSMika Westerberg 
203c3a92833Spbrook /* Assumes contents are already zeroed.  */
204624f7979Spbrook void init_task_state(TaskState *ts)
205624f7979Spbrook {
206eb33cdaeSCameron Esfahani     long ticks_per_sec;
207eb33cdaeSCameron Esfahani     struct timespec bt;
208eb33cdaeSCameron Esfahani 
209624f7979Spbrook     ts->used = 1;
2105bfce0b7SPeter Maydell     ts->sigaltstack_used = (struct target_sigaltstack) {
2115bfce0b7SPeter Maydell         .ss_sp = 0,
2125bfce0b7SPeter Maydell         .ss_size = 0,
2135bfce0b7SPeter Maydell         .ss_flags = TARGET_SS_DISABLE,
2145bfce0b7SPeter Maydell     };
215eb33cdaeSCameron Esfahani 
216eb33cdaeSCameron Esfahani     /* Capture task start time relative to system boot */
217eb33cdaeSCameron Esfahani 
218eb33cdaeSCameron Esfahani     ticks_per_sec = sysconf(_SC_CLK_TCK);
219eb33cdaeSCameron Esfahani 
220eb33cdaeSCameron Esfahani     if ((ticks_per_sec > 0) && !clock_gettime(CLOCK_BOOTTIME, &bt)) {
221eb33cdaeSCameron Esfahani         /* start_boottime is expressed in clock ticks */
222eb33cdaeSCameron Esfahani         ts->start_boottime = bt.tv_sec * (uint64_t) ticks_per_sec;
223eb33cdaeSCameron Esfahani         ts->start_boottime += bt.tv_nsec * (uint64_t) ticks_per_sec /
224eb33cdaeSCameron Esfahani                               NANOSECONDS_PER_SECOND;
225eb33cdaeSCameron Esfahani     }
226624f7979Spbrook }
2279de5e440Sbellard 
22830ba0ee5SAndreas Färber CPUArchState *cpu_copy(CPUArchState *env)
22930ba0ee5SAndreas Färber {
23029a0af61SRichard Henderson     CPUState *cpu = env_cpu(env);
2312278b939SIgor Mammedov     CPUState *new_cpu = cpu_create(cpu_type);
23261c7480fSLeon Alrae     CPUArchState *new_env = new_cpu->env_ptr;
23330ba0ee5SAndreas Färber     CPUBreakpoint *bp;
23430ba0ee5SAndreas Färber 
23530ba0ee5SAndreas Färber     /* Reset non arch specific state */
23675a34036SAndreas Färber     cpu_reset(new_cpu);
23730ba0ee5SAndreas Färber 
2386cc9d67cSRichard Henderson     new_cpu->tcg_cflags = cpu->tcg_cflags;
23930ba0ee5SAndreas Färber     memcpy(new_env, env, sizeof(CPUArchState));
24030ba0ee5SAndreas Färber 
24130ba0ee5SAndreas Färber     /* Clone all break/watchpoints.
24230ba0ee5SAndreas Färber        Note: Once we support ptrace with hw-debug register access, make sure
24330ba0ee5SAndreas Färber        BP_CPU break/watchpoints are handled correctly on clone. */
2441d085f6cSThierry Bultel     QTAILQ_INIT(&new_cpu->breakpoints);
245f0c3c505SAndreas Färber     QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
246b3310ab3SAndreas Färber         cpu_breakpoint_insert(new_cpu, bp->pc, bp->flags, NULL);
24730ba0ee5SAndreas Färber     }
24830ba0ee5SAndreas Färber 
24930ba0ee5SAndreas Färber     return new_env;
25030ba0ee5SAndreas Färber }
25130ba0ee5SAndreas Färber 
252fc9c5412SJohannes Schauer static void handle_arg_help(const char *arg)
253fc9c5412SJohannes Schauer {
2544d1275c2SRiku Voipio     usage(EXIT_SUCCESS);
255fc9c5412SJohannes Schauer }
256fc9c5412SJohannes Schauer 
257fc9c5412SJohannes Schauer static void handle_arg_log(const char *arg)
258fc9c5412SJohannes Schauer {
2594b25a506SJosh Kunz     last_log_mask = qemu_str_to_log_mask(arg);
2604b25a506SJosh Kunz     if (!last_log_mask) {
26159a6fa6eSPeter Maydell         qemu_print_log_usage(stdout);
2624d1275c2SRiku Voipio         exit(EXIT_FAILURE);
263fc9c5412SJohannes Schauer     }
264fc9c5412SJohannes Schauer }
265fc9c5412SJohannes Schauer 
2668423fa90SAlex Bennée static void handle_arg_dfilter(const char *arg)
2678423fa90SAlex Bennée {
2687f4341e8SAlex Bennée     qemu_set_dfilter_ranges(arg, &error_fatal);
2698423fa90SAlex Bennée }
2708423fa90SAlex Bennée 
27150171d42S陳韋任 static void handle_arg_log_filename(const char *arg)
27250171d42S陳韋任 {
273b410253fSRichard Henderson     last_log_filename = arg;
27450171d42S陳韋任 }
27550171d42S陳韋任 
276fc9c5412SJohannes Schauer static void handle_arg_set_env(const char *arg)
277fc9c5412SJohannes Schauer {
278fc9c5412SJohannes Schauer     char *r, *p, *token;
279fc9c5412SJohannes Schauer     r = p = strdup(arg);
280fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
281fc9c5412SJohannes Schauer         if (envlist_setenv(envlist, token) != 0) {
2824d1275c2SRiku Voipio             usage(EXIT_FAILURE);
283fc9c5412SJohannes Schauer         }
284fc9c5412SJohannes Schauer     }
285fc9c5412SJohannes Schauer     free(r);
286fc9c5412SJohannes Schauer }
287fc9c5412SJohannes Schauer 
288fc9c5412SJohannes Schauer static void handle_arg_unset_env(const char *arg)
289fc9c5412SJohannes Schauer {
290fc9c5412SJohannes Schauer     char *r, *p, *token;
291fc9c5412SJohannes Schauer     r = p = strdup(arg);
292fc9c5412SJohannes Schauer     while ((token = strsep(&p, ",")) != NULL) {
293fc9c5412SJohannes Schauer         if (envlist_unsetenv(envlist, token) != 0) {
2944d1275c2SRiku Voipio             usage(EXIT_FAILURE);
295fc9c5412SJohannes Schauer         }
296fc9c5412SJohannes Schauer     }
297fc9c5412SJohannes Schauer     free(r);
298fc9c5412SJohannes Schauer }
299fc9c5412SJohannes Schauer 
300fc9c5412SJohannes Schauer static void handle_arg_argv0(const char *arg)
301fc9c5412SJohannes Schauer {
302fc9c5412SJohannes Schauer     argv0 = strdup(arg);
303fc9c5412SJohannes Schauer }
304fc9c5412SJohannes Schauer 
305fc9c5412SJohannes Schauer static void handle_arg_stack_size(const char *arg)
306fc9c5412SJohannes Schauer {
307fc9c5412SJohannes Schauer     char *p;
308fc9c5412SJohannes Schauer     guest_stack_size = strtoul(arg, &p, 0);
309fc9c5412SJohannes Schauer     if (guest_stack_size == 0) {
3104d1275c2SRiku Voipio         usage(EXIT_FAILURE);
311fc9c5412SJohannes Schauer     }
312fc9c5412SJohannes Schauer 
313fc9c5412SJohannes Schauer     if (*p == 'M') {
314b52713c1SPhilippe Mathieu-Daudé         guest_stack_size *= MiB;
315fc9c5412SJohannes Schauer     } else if (*p == 'k' || *p == 'K') {
316b52713c1SPhilippe Mathieu-Daudé         guest_stack_size *= KiB;
317fc9c5412SJohannes Schauer     }
318fc9c5412SJohannes Schauer }
319fc9c5412SJohannes Schauer 
320fc9c5412SJohannes Schauer static void handle_arg_ld_prefix(const char *arg)
321fc9c5412SJohannes Schauer {
322fc9c5412SJohannes Schauer     interp_prefix = strdup(arg);
323fc9c5412SJohannes Schauer }
324fc9c5412SJohannes Schauer 
325fc9c5412SJohannes Schauer static void handle_arg_pagesize(const char *arg)
326fc9c5412SJohannes Schauer {
327fc9c5412SJohannes Schauer     qemu_host_page_size = atoi(arg);
328fc9c5412SJohannes Schauer     if (qemu_host_page_size == 0 ||
329fc9c5412SJohannes Schauer         (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
330fc9c5412SJohannes Schauer         fprintf(stderr, "page size must be a power of two\n");
3314d1275c2SRiku Voipio         exit(EXIT_FAILURE);
332fc9c5412SJohannes Schauer     }
333fc9c5412SJohannes Schauer }
334fc9c5412SJohannes Schauer 
3355ebdd774SRichard Henderson static void handle_arg_seed(const char *arg)
336c5e4a5a9SMagnus Reftel {
3375ebdd774SRichard Henderson     seed_optarg = arg;
338c5e4a5a9SMagnus Reftel }
339c5e4a5a9SMagnus Reftel 
340fc9c5412SJohannes Schauer static void handle_arg_gdb(const char *arg)
341fc9c5412SJohannes Schauer {
342fcedd920SAlex Bennée     gdbstub = g_strdup(arg);
343fc9c5412SJohannes Schauer }
344fc9c5412SJohannes Schauer 
345fc9c5412SJohannes Schauer static void handle_arg_uname(const char *arg)
346fc9c5412SJohannes Schauer {
347fc9c5412SJohannes Schauer     qemu_uname_release = strdup(arg);
348fc9c5412SJohannes Schauer }
349fc9c5412SJohannes Schauer 
350fc9c5412SJohannes Schauer static void handle_arg_cpu(const char *arg)
351fc9c5412SJohannes Schauer {
352fc9c5412SJohannes Schauer     cpu_model = strdup(arg);
353c8057f95SPeter Maydell     if (cpu_model == NULL || is_help_option(cpu_model)) {
354fc9c5412SJohannes Schauer         /* XXX: implement xxx_cpu_list for targets that still miss it */
355e916cbf8SPeter Maydell #if defined(cpu_list)
3560442428aSMarkus Armbruster         cpu_list();
357fc9c5412SJohannes Schauer #endif
3584d1275c2SRiku Voipio         exit(EXIT_FAILURE);
359fc9c5412SJohannes Schauer     }
360fc9c5412SJohannes Schauer }
361fc9c5412SJohannes Schauer 
362fc9c5412SJohannes Schauer static void handle_arg_guest_base(const char *arg)
363fc9c5412SJohannes Schauer {
364fc9c5412SJohannes Schauer     guest_base = strtol(arg, NULL, 0);
365e307c192SRichard Henderson     have_guest_base = true;
366fc9c5412SJohannes Schauer }
367fc9c5412SJohannes Schauer 
368fc9c5412SJohannes Schauer static void handle_arg_reserved_va(const char *arg)
369fc9c5412SJohannes Schauer {
370fc9c5412SJohannes Schauer     char *p;
371fc9c5412SJohannes Schauer     int shift = 0;
372fc9c5412SJohannes Schauer     reserved_va = strtoul(arg, &p, 0);
373fc9c5412SJohannes Schauer     switch (*p) {
374fc9c5412SJohannes Schauer     case 'k':
375fc9c5412SJohannes Schauer     case 'K':
376fc9c5412SJohannes Schauer         shift = 10;
377fc9c5412SJohannes Schauer         break;
378fc9c5412SJohannes Schauer     case 'M':
379fc9c5412SJohannes Schauer         shift = 20;
380fc9c5412SJohannes Schauer         break;
381fc9c5412SJohannes Schauer     case 'G':
382fc9c5412SJohannes Schauer         shift = 30;
383fc9c5412SJohannes Schauer         break;
384fc9c5412SJohannes Schauer     }
385fc9c5412SJohannes Schauer     if (shift) {
386fc9c5412SJohannes Schauer         unsigned long unshifted = reserved_va;
387fc9c5412SJohannes Schauer         p++;
388fc9c5412SJohannes Schauer         reserved_va <<= shift;
3898f67b9c6SRichard Henderson         if (reserved_va >> shift != unshifted) {
390fc9c5412SJohannes Schauer             fprintf(stderr, "Reserved virtual address too big\n");
3914d1275c2SRiku Voipio             exit(EXIT_FAILURE);
392fc9c5412SJohannes Schauer         }
393fc9c5412SJohannes Schauer     }
394fc9c5412SJohannes Schauer     if (*p) {
395fc9c5412SJohannes Schauer         fprintf(stderr, "Unrecognised -R size suffix '%s'\n", p);
3964d1275c2SRiku Voipio         exit(EXIT_FAILURE);
397fc9c5412SJohannes Schauer     }
398fc9c5412SJohannes Schauer }
399fc9c5412SJohannes Schauer 
400fc9c5412SJohannes Schauer static void handle_arg_singlestep(const char *arg)
401fc9c5412SJohannes Schauer {
402fc9c5412SJohannes Schauer     singlestep = 1;
403fc9c5412SJohannes Schauer }
404fc9c5412SJohannes Schauer 
405fc9c5412SJohannes Schauer static void handle_arg_strace(const char *arg)
406fc9c5412SJohannes Schauer {
4074b25a506SJosh Kunz     enable_strace = true;
408fc9c5412SJohannes Schauer }
409fc9c5412SJohannes Schauer 
410fc9c5412SJohannes Schauer static void handle_arg_version(const char *arg)
411fc9c5412SJohannes Schauer {
4127e563bfbSThomas Huth     printf("qemu-" TARGET_NAME " version " QEMU_FULL_VERSION
4130781dd6eSThomas Huth            "\n" QEMU_COPYRIGHT "\n");
4144d1275c2SRiku Voipio     exit(EXIT_SUCCESS);
415fc9c5412SJohannes Schauer }
416fc9c5412SJohannes Schauer 
4176533dd6eSLluís Vilanova static void handle_arg_trace(const char *arg)
4186533dd6eSLluís Vilanova {
41992eecfffSPaolo Bonzini     trace_opt_parse(arg);
4206533dd6eSLluís Vilanova }
4216533dd6eSLluís Vilanova 
422130ea832SMax Filippov #if defined(TARGET_XTENSA)
423130ea832SMax Filippov static void handle_arg_abi_call0(const char *arg)
424130ea832SMax Filippov {
425130ea832SMax Filippov     xtensa_set_abi_call0();
426130ea832SMax Filippov }
427130ea832SMax Filippov #endif
428130ea832SMax Filippov 
4295584e2dbSIlya Leoshkevich static void handle_arg_perfmap(const char *arg)
4305584e2dbSIlya Leoshkevich {
4315584e2dbSIlya Leoshkevich     perf_enable_perfmap();
4325584e2dbSIlya Leoshkevich }
4335584e2dbSIlya Leoshkevich 
4345584e2dbSIlya Leoshkevich static void handle_arg_jitdump(const char *arg)
4355584e2dbSIlya Leoshkevich {
4365584e2dbSIlya Leoshkevich     perf_enable_jitdump();
4375584e2dbSIlya Leoshkevich }
4385584e2dbSIlya Leoshkevich 
439f308f64eSLluís Vilanova static QemuPluginList plugins = QTAILQ_HEAD_INITIALIZER(plugins);
440f308f64eSLluís Vilanova 
441f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
442f308f64eSLluís Vilanova static void handle_arg_plugin(const char *arg)
443f308f64eSLluís Vilanova {
444f308f64eSLluís Vilanova     qemu_plugin_opt_parse(arg, &plugins);
445f308f64eSLluís Vilanova }
446f308f64eSLluís Vilanova #endif
447f308f64eSLluís Vilanova 
448fc9c5412SJohannes Schauer struct qemu_argument {
449fc9c5412SJohannes Schauer     const char *argv;
450fc9c5412SJohannes Schauer     const char *env;
451fc9c5412SJohannes Schauer     bool has_arg;
452fc9c5412SJohannes Schauer     void (*handle_opt)(const char *arg);
453fc9c5412SJohannes Schauer     const char *example;
454fc9c5412SJohannes Schauer     const char *help;
455fc9c5412SJohannes Schauer };
456fc9c5412SJohannes Schauer 
45742644ceeSJim Meyering static const struct qemu_argument arg_table[] = {
458fc9c5412SJohannes Schauer     {"h",          "",                 false, handle_arg_help,
459fc9c5412SJohannes Schauer      "",           "print this help"},
460daaf8c8eSMeador Inge     {"help",       "",                 false, handle_arg_help,
461daaf8c8eSMeador Inge      "",           ""},
462fc9c5412SJohannes Schauer     {"g",          "QEMU_GDB",         true,  handle_arg_gdb,
463fc9c5412SJohannes Schauer      "port",       "wait gdb connection to 'port'"},
464fc9c5412SJohannes Schauer     {"L",          "QEMU_LD_PREFIX",   true,  handle_arg_ld_prefix,
465fc9c5412SJohannes Schauer      "path",       "set the elf interpreter prefix to 'path'"},
466fc9c5412SJohannes Schauer     {"s",          "QEMU_STACK_SIZE",  true,  handle_arg_stack_size,
467fc9c5412SJohannes Schauer      "size",       "set the stack size to 'size' bytes"},
468fc9c5412SJohannes Schauer     {"cpu",        "QEMU_CPU",         true,  handle_arg_cpu,
469c8057f95SPeter Maydell      "model",      "select CPU (-cpu help for list)"},
470fc9c5412SJohannes Schauer     {"E",          "QEMU_SET_ENV",     true,  handle_arg_set_env,
471fc9c5412SJohannes Schauer      "var=value",  "sets targets environment variable (see below)"},
472fc9c5412SJohannes Schauer     {"U",          "QEMU_UNSET_ENV",   true,  handle_arg_unset_env,
473fc9c5412SJohannes Schauer      "var",        "unsets targets environment variable (see below)"},
474fc9c5412SJohannes Schauer     {"0",          "QEMU_ARGV0",       true,  handle_arg_argv0,
475fc9c5412SJohannes Schauer      "argv0",      "forces target process argv[0] to be 'argv0'"},
476fc9c5412SJohannes Schauer     {"r",          "QEMU_UNAME",       true,  handle_arg_uname,
477fc9c5412SJohannes Schauer      "uname",      "set qemu uname release string to 'uname'"},
478fc9c5412SJohannes Schauer     {"B",          "QEMU_GUEST_BASE",  true,  handle_arg_guest_base,
479fc9c5412SJohannes Schauer      "address",    "set guest_base address to 'address'"},
480fc9c5412SJohannes Schauer     {"R",          "QEMU_RESERVED_VA", true,  handle_arg_reserved_va,
481fc9c5412SJohannes Schauer      "size",       "reserve 'size' bytes for guest virtual address space"},
482fc9c5412SJohannes Schauer     {"d",          "QEMU_LOG",         true,  handle_arg_log,
483989b697dSPeter Maydell      "item[,...]", "enable logging of specified items "
484989b697dSPeter Maydell      "(use '-d help' for a list of items)"},
4858423fa90SAlex Bennée     {"dfilter",    "QEMU_DFILTER",     true,  handle_arg_dfilter,
4868423fa90SAlex Bennée      "range[,...]","filter logging based on address range"},
48750171d42S陳韋任     {"D",          "QEMU_LOG_FILENAME", true, handle_arg_log_filename,
488989b697dSPeter Maydell      "logfile",     "write logs to 'logfile' (default stderr)"},
489fc9c5412SJohannes Schauer     {"p",          "QEMU_PAGESIZE",    true,  handle_arg_pagesize,
490fc9c5412SJohannes Schauer      "pagesize",   "set the host page size to 'pagesize'"},
491fc9c5412SJohannes Schauer     {"singlestep", "QEMU_SINGLESTEP",  false, handle_arg_singlestep,
492fc9c5412SJohannes Schauer      "",           "run in singlestep mode"},
493fc9c5412SJohannes Schauer     {"strace",     "QEMU_STRACE",      false, handle_arg_strace,
494fc9c5412SJohannes Schauer      "",           "log system calls"},
4955ebdd774SRichard Henderson     {"seed",       "QEMU_RAND_SEED",   true,  handle_arg_seed,
496c5e4a5a9SMagnus Reftel      "",           "Seed for pseudo-random number generator"},
4976533dd6eSLluís Vilanova     {"trace",      "QEMU_TRACE",       true,  handle_arg_trace,
4986533dd6eSLluís Vilanova      "",           "[[enable=]<pattern>][,events=<file>][,file=<file>]"},
499f308f64eSLluís Vilanova #ifdef CONFIG_PLUGIN
500f308f64eSLluís Vilanova     {"plugin",     "QEMU_PLUGIN",      true,  handle_arg_plugin,
5013a445acbSMahmoud Mandour      "",           "[file=]<file>[,<argname>=<argvalue>]"},
502f308f64eSLluís Vilanova #endif
503fc9c5412SJohannes Schauer     {"version",    "QEMU_VERSION",     false, handle_arg_version,
5041386d4c0SPeter Maydell      "",           "display version information and exit"},
505130ea832SMax Filippov #if defined(TARGET_XTENSA)
506130ea832SMax Filippov     {"xtensa-abi-call0", "QEMU_XTENSA_ABI_CALL0", false, handle_arg_abi_call0,
507130ea832SMax Filippov      "",           "assume CALL0 Xtensa ABI"},
508130ea832SMax Filippov #endif
5095584e2dbSIlya Leoshkevich     {"perfmap",    "QEMU_PERFMAP",     false, handle_arg_perfmap,
5105584e2dbSIlya Leoshkevich      "",           "Generate a /tmp/perf-${pid}.map file for perf"},
5115584e2dbSIlya Leoshkevich     {"jitdump",    "QEMU_JITDUMP",     false, handle_arg_jitdump,
5125584e2dbSIlya Leoshkevich      "",           "Generate a jit-${pid}.dump file for perf"},
513fc9c5412SJohannes Schauer     {NULL, NULL, false, NULL, NULL, NULL}
514fc9c5412SJohannes Schauer };
515fc9c5412SJohannes Schauer 
516d03f9c32SMeador Inge static void usage(int exitcode)
517fc9c5412SJohannes Schauer {
51842644ceeSJim Meyering     const struct qemu_argument *arginfo;
519fc9c5412SJohannes Schauer     int maxarglen;
520fc9c5412SJohannes Schauer     int maxenvlen;
521fc9c5412SJohannes Schauer 
5222e59915dSPaolo Bonzini     printf("usage: qemu-" TARGET_NAME " [options] program [arguments...]\n"
5232e59915dSPaolo Bonzini            "Linux CPU emulator (compiled for " TARGET_NAME " emulation)\n"
524fc9c5412SJohannes Schauer            "\n"
525fc9c5412SJohannes Schauer            "Options and associated environment variables:\n"
526fc9c5412SJohannes Schauer            "\n");
527fc9c5412SJohannes Schauer 
52863ec54d7SPeter Maydell     /* Calculate column widths. We must always have at least enough space
52963ec54d7SPeter Maydell      * for the column header.
53063ec54d7SPeter Maydell      */
53163ec54d7SPeter Maydell     maxarglen = strlen("Argument");
53263ec54d7SPeter Maydell     maxenvlen = strlen("Env-variable");
533fc9c5412SJohannes Schauer 
534fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
53563ec54d7SPeter Maydell         int arglen = strlen(arginfo->argv);
53663ec54d7SPeter Maydell         if (arginfo->has_arg) {
53763ec54d7SPeter Maydell             arglen += strlen(arginfo->example) + 1;
53863ec54d7SPeter Maydell         }
539fc9c5412SJohannes Schauer         if (strlen(arginfo->env) > maxenvlen) {
540fc9c5412SJohannes Schauer             maxenvlen = strlen(arginfo->env);
541fc9c5412SJohannes Schauer         }
54263ec54d7SPeter Maydell         if (arglen > maxarglen) {
54363ec54d7SPeter Maydell             maxarglen = arglen;
544fc9c5412SJohannes Schauer         }
545fc9c5412SJohannes Schauer     }
546fc9c5412SJohannes Schauer 
54763ec54d7SPeter Maydell     printf("%-*s %-*s Description\n", maxarglen+1, "Argument",
54863ec54d7SPeter Maydell             maxenvlen, "Env-variable");
549fc9c5412SJohannes Schauer 
550fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
551fc9c5412SJohannes Schauer         if (arginfo->has_arg) {
552fc9c5412SJohannes Schauer             printf("-%s %-*s %-*s %s\n", arginfo->argv,
55363ec54d7SPeter Maydell                    (int)(maxarglen - strlen(arginfo->argv) - 1),
55463ec54d7SPeter Maydell                    arginfo->example, maxenvlen, arginfo->env, arginfo->help);
555fc9c5412SJohannes Schauer         } else {
55663ec54d7SPeter Maydell             printf("-%-*s %-*s %s\n", maxarglen, arginfo->argv,
557fc9c5412SJohannes Schauer                     maxenvlen, arginfo->env,
558fc9c5412SJohannes Schauer                     arginfo->help);
559fc9c5412SJohannes Schauer         }
560fc9c5412SJohannes Schauer     }
561fc9c5412SJohannes Schauer 
562fc9c5412SJohannes Schauer     printf("\n"
563fc9c5412SJohannes Schauer            "Defaults:\n"
564fc9c5412SJohannes Schauer            "QEMU_LD_PREFIX  = %s\n"
565989b697dSPeter Maydell            "QEMU_STACK_SIZE = %ld byte\n",
566fc9c5412SJohannes Schauer            interp_prefix,
567989b697dSPeter Maydell            guest_stack_size);
568fc9c5412SJohannes Schauer 
569fc9c5412SJohannes Schauer     printf("\n"
570fc9c5412SJohannes Schauer            "You can use -E and -U options or the QEMU_SET_ENV and\n"
571fc9c5412SJohannes Schauer            "QEMU_UNSET_ENV environment variables to set and unset\n"
572fc9c5412SJohannes Schauer            "environment variables for the target process.\n"
573fc9c5412SJohannes Schauer            "It is possible to provide several variables by separating them\n"
574fc9c5412SJohannes Schauer            "by commas in getsubopt(3) style. Additionally it is possible to\n"
575fc9c5412SJohannes Schauer            "provide the -E and -U options multiple times.\n"
576fc9c5412SJohannes Schauer            "The following lines are equivalent:\n"
577fc9c5412SJohannes Schauer            "    -E var1=val2 -E var2=val2 -U LD_PRELOAD -U LD_DEBUG\n"
578fc9c5412SJohannes Schauer            "    -E var1=val2,var2=val2 -U LD_PRELOAD,LD_DEBUG\n"
579fc9c5412SJohannes Schauer            "    QEMU_SET_ENV=var1=val2,var2=val2 QEMU_UNSET_ENV=LD_PRELOAD,LD_DEBUG\n"
580fc9c5412SJohannes Schauer            "Note that if you provide several changes to a single variable\n"
581f5048cb7SEric Blake            "the last change will stay in effect.\n"
582f5048cb7SEric Blake            "\n"
583f5048cb7SEric Blake            QEMU_HELP_BOTTOM "\n");
584fc9c5412SJohannes Schauer 
585d03f9c32SMeador Inge     exit(exitcode);
586fc9c5412SJohannes Schauer }
587fc9c5412SJohannes Schauer 
588fc9c5412SJohannes Schauer static int parse_args(int argc, char **argv)
589fc9c5412SJohannes Schauer {
590fc9c5412SJohannes Schauer     const char *r;
591fc9c5412SJohannes Schauer     int optind;
59242644ceeSJim Meyering     const struct qemu_argument *arginfo;
593fc9c5412SJohannes Schauer 
594fc9c5412SJohannes Schauer     for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
595fc9c5412SJohannes Schauer         if (arginfo->env == NULL) {
596fc9c5412SJohannes Schauer             continue;
597fc9c5412SJohannes Schauer         }
598fc9c5412SJohannes Schauer 
599fc9c5412SJohannes Schauer         r = getenv(arginfo->env);
600fc9c5412SJohannes Schauer         if (r != NULL) {
601fc9c5412SJohannes Schauer             arginfo->handle_opt(r);
602fc9c5412SJohannes Schauer         }
603fc9c5412SJohannes Schauer     }
604fc9c5412SJohannes Schauer 
605fc9c5412SJohannes Schauer     optind = 1;
606fc9c5412SJohannes Schauer     for (;;) {
607fc9c5412SJohannes Schauer         if (optind >= argc) {
608fc9c5412SJohannes Schauer             break;
609fc9c5412SJohannes Schauer         }
610fc9c5412SJohannes Schauer         r = argv[optind];
611fc9c5412SJohannes Schauer         if (r[0] != '-') {
612fc9c5412SJohannes Schauer             break;
613fc9c5412SJohannes Schauer         }
614fc9c5412SJohannes Schauer         optind++;
615fc9c5412SJohannes Schauer         r++;
616fc9c5412SJohannes Schauer         if (!strcmp(r, "-")) {
617fc9c5412SJohannes Schauer             break;
618fc9c5412SJohannes Schauer         }
619ba02577cSMeador Inge         /* Treat --foo the same as -foo.  */
620ba02577cSMeador Inge         if (r[0] == '-') {
621ba02577cSMeador Inge             r++;
622ba02577cSMeador Inge         }
623fc9c5412SJohannes Schauer 
624fc9c5412SJohannes Schauer         for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
625fc9c5412SJohannes Schauer             if (!strcmp(r, arginfo->argv)) {
6261386d4c0SPeter Maydell                 if (arginfo->has_arg) {
627fc9c5412SJohannes Schauer                     if (optind >= argc) {
628138940bfSMeador Inge                         (void) fprintf(stderr,
629138940bfSMeador Inge                             "qemu: missing argument for option '%s'\n", r);
6304d1275c2SRiku Voipio                         exit(EXIT_FAILURE);
631fc9c5412SJohannes Schauer                     }
632fc9c5412SJohannes Schauer                     arginfo->handle_opt(argv[optind]);
633fc9c5412SJohannes Schauer                     optind++;
6341386d4c0SPeter Maydell                 } else {
6351386d4c0SPeter Maydell                     arginfo->handle_opt(NULL);
636fc9c5412SJohannes Schauer                 }
637fc9c5412SJohannes Schauer                 break;
638fc9c5412SJohannes Schauer             }
639fc9c5412SJohannes Schauer         }
640fc9c5412SJohannes Schauer 
641fc9c5412SJohannes Schauer         /* no option matched the current argv */
642fc9c5412SJohannes Schauer         if (arginfo->handle_opt == NULL) {
643138940bfSMeador Inge             (void) fprintf(stderr, "qemu: unknown option '%s'\n", r);
6444d1275c2SRiku Voipio             exit(EXIT_FAILURE);
645fc9c5412SJohannes Schauer         }
646fc9c5412SJohannes Schauer     }
647fc9c5412SJohannes Schauer 
648fc9c5412SJohannes Schauer     if (optind >= argc) {
649138940bfSMeador Inge         (void) fprintf(stderr, "qemu: no user program specified\n");
6504d1275c2SRiku Voipio         exit(EXIT_FAILURE);
651fc9c5412SJohannes Schauer     }
652fc9c5412SJohannes Schauer 
653fc9c5412SJohannes Schauer     exec_path = argv[optind];
654fc9c5412SJohannes Schauer 
655fc9c5412SJohannes Schauer     return optind;
656fc9c5412SJohannes Schauer }
657fc9c5412SJohannes Schauer 
658902b3d5cSmalc int main(int argc, char **argv, char **envp)
65931e31b8aSbellard {
66001ffc75bSbellard     struct target_pt_regs regs1, *regs = &regs1;
66131e31b8aSbellard     struct image_info info1, *info = &info1;
662edf8e2afSMika Westerberg     struct linux_binprm bprm;
66348e15fc2SNathan Froyd     TaskState *ts;
6649349b4f9SAndreas Färber     CPUArchState *env;
665db6b81d4SAndreas Färber     CPUState *cpu;
666586314f2Sbellard     int optind;
66704a6dfebSaurel32     char **target_environ, **wrk;
6687d8cec95Saurel32     char **target_argv;
6697d8cec95Saurel32     int target_argc;
6707d8cec95Saurel32     int i;
671fd4d81ddSArnaud Patard     int ret;
67203cfd8faSLaurent Vivier     int execfd;
6738f67b9c6SRichard Henderson     unsigned long max_reserved_va;
6746e1c0d7bSLaurent Vivier     bool preserve_argv0;
67531e31b8aSbellard 
676f5852efaSChristophe Fergeau     error_init(argv[0]);
677fe4db84dSDaniel P. Berrange     module_call_init(MODULE_INIT_TRACE);
678267f685bSPaolo Bonzini     qemu_init_cpu_list();
679ce008c1fSAndreas Färber     module_call_init(MODULE_INIT_QOM);
680ce008c1fSAndreas Färber 
681ec45bbe5SSaurav Sachidanand     envlist = envlist_create();
68204a6dfebSaurel32 
68304a6dfebSaurel32     /* add current environment into the list */
68404a6dfebSaurel32     for (wrk = environ; *wrk != NULL; wrk++) {
68504a6dfebSaurel32         (void) envlist_setenv(envlist, *wrk);
68604a6dfebSaurel32     }
68704a6dfebSaurel32 
688703e0e89SRichard Henderson     /* Read the stack limit from the kernel.  If it's "unlimited",
689703e0e89SRichard Henderson        then we can do little else besides use the default.  */
690703e0e89SRichard Henderson     {
691703e0e89SRichard Henderson         struct rlimit lim;
692703e0e89SRichard Henderson         if (getrlimit(RLIMIT_STACK, &lim) == 0
69381bbe906Stakasi-y@ops.dti.ne.jp             && lim.rlim_cur != RLIM_INFINITY
6940a3346b5SHelge Deller             && lim.rlim_cur == (target_long)lim.rlim_cur
6950a3346b5SHelge Deller             && lim.rlim_cur > guest_stack_size) {
696703e0e89SRichard Henderson             guest_stack_size = lim.rlim_cur;
697703e0e89SRichard Henderson         }
698703e0e89SRichard Henderson     }
699703e0e89SRichard Henderson 
700b1f9be31Sj_mayer     cpu_model = NULL;
701b5ec5ce0Sjohn cooper 
7026533dd6eSLluís Vilanova     qemu_add_opts(&qemu_trace_opts);
703f308f64eSLluís Vilanova     qemu_plugin_add_opts();
7046533dd6eSLluís Vilanova 
705fc9c5412SJohannes Schauer     optind = parse_args(argc, argv);
7064b5dfd82SPeter Maydell 
707b410253fSRichard Henderson     qemu_set_log_filename_flags(last_log_filename,
708b410253fSRichard Henderson                                 last_log_mask | (enable_strace * LOG_STRACE),
709b410253fSRichard Henderson                                 &error_fatal);
7104b25a506SJosh Kunz 
7116533dd6eSLluís Vilanova     if (!trace_init_backends()) {
7126533dd6eSLluís Vilanova         exit(1);
7136533dd6eSLluís Vilanova     }
71492eecfffSPaolo Bonzini     trace_init_file();
7150572f558SPaolo Bonzini     qemu_plugin_load_list(&plugins, &error_fatal);
7166533dd6eSLluís Vilanova 
71731e31b8aSbellard     /* Zero out regs */
71801ffc75bSbellard     memset(regs, 0, sizeof(struct target_pt_regs));
71931e31b8aSbellard 
72031e31b8aSbellard     /* Zero out image_info */
72131e31b8aSbellard     memset(info, 0, sizeof(struct image_info));
72231e31b8aSbellard 
723edf8e2afSMika Westerberg     memset(&bprm, 0, sizeof (bprm));
724edf8e2afSMika Westerberg 
72574cd30b8Sbellard     /* Scan interp_prefix dir for replacement files. */
72674cd30b8Sbellard     init_paths(interp_prefix);
72774cd30b8Sbellard 
7284a24a758SPeter Maydell     init_qemu_uname_release();
7294a24a758SPeter Maydell 
7306e1c0d7bSLaurent Vivier     /*
7316e1c0d7bSLaurent Vivier      * Manage binfmt-misc open-binary flag
7326e1c0d7bSLaurent Vivier      */
733768fe76eSYunQiang Su     execfd = qemu_getauxval(AT_EXECFD);
734768fe76eSYunQiang Su     if (execfd == 0) {
7359d3019bcSLaurent Vivier         execfd = open(exec_path, O_RDONLY);
736768fe76eSYunQiang Su         if (execfd < 0) {
7379d3019bcSLaurent Vivier             printf("Error while loading %s: %s\n", exec_path, strerror(errno));
738768fe76eSYunQiang Su             _exit(EXIT_FAILURE);
739768fe76eSYunQiang Su         }
740768fe76eSYunQiang Su     }
741768fe76eSYunQiang Su 
7426e1c0d7bSLaurent Vivier     /*
7436e1c0d7bSLaurent Vivier      * get binfmt_misc flags
7446e1c0d7bSLaurent Vivier      */
7456e1c0d7bSLaurent Vivier     preserve_argv0 = !!(qemu_getauxval(AT_FLAGS) & AT_FLAGS_PRESERVE_ARGV0);
7466e1c0d7bSLaurent Vivier 
7476e1c0d7bSLaurent Vivier     /*
7486e1c0d7bSLaurent Vivier      * Manage binfmt-misc preserve-arg[0] flag
7496e1c0d7bSLaurent Vivier      *    argv[optind]     full path to the binary
7506e1c0d7bSLaurent Vivier      *    argv[optind + 1] original argv[0]
7516e1c0d7bSLaurent Vivier      */
7526e1c0d7bSLaurent Vivier     if (optind + 1 < argc && preserve_argv0) {
7536e1c0d7bSLaurent Vivier         optind++;
7546e1c0d7bSLaurent Vivier     }
7556e1c0d7bSLaurent Vivier 
75646027c07Sbellard     if (cpu_model == NULL) {
757768fe76eSYunQiang Su         cpu_model = cpu_get_model(get_elf_eflags(execfd));
758aaed909aSbellard     }
759c1c8cfe5SEduardo Habkost     cpu_type = parse_cpu_option(cpu_model);
7602278b939SIgor Mammedov 
7612b5249b8SIgor Mammedov     /* init tcg before creating CPUs and to get qemu_host_page_size */
762940e43aaSClaudio Fontana     {
763940e43aaSClaudio Fontana         AccelClass *ac = ACCEL_GET_CLASS(current_accel());
7642278b939SIgor Mammedov 
765b86f59c7SClaudio Fontana         accel_init_interfaces(ac);
76692242f34SClaudio Fontana         ac->init_machine(NULL);
767940e43aaSClaudio Fontana     }
7682278b939SIgor Mammedov     cpu = cpu_create(cpu_type);
7692994fd96SEduardo Habkost     env = cpu->env_ptr;
7700ac46af3SAndreas Färber     cpu_reset(cpu);
771db6b81d4SAndreas Färber     thread_cpu = cpu;
77254936004Sbellard 
7738f67b9c6SRichard Henderson     /*
7748f67b9c6SRichard Henderson      * Reserving too much vm space via mmap can run into problems
7758f67b9c6SRichard Henderson      * with rlimits, oom due to page table creation, etc.  We will
7768f67b9c6SRichard Henderson      * still try it, if directed by the command-line option, but
7778f67b9c6SRichard Henderson      * not by default.
7788f67b9c6SRichard Henderson      */
7798f67b9c6SRichard Henderson     max_reserved_va = MAX_RESERVED_VA(cpu);
7808f67b9c6SRichard Henderson     if (reserved_va != 0) {
7818f67b9c6SRichard Henderson         if (max_reserved_va && reserved_va > max_reserved_va) {
7828f67b9c6SRichard Henderson             fprintf(stderr, "Reserved virtual address too big\n");
7838f67b9c6SRichard Henderson             exit(EXIT_FAILURE);
7848f67b9c6SRichard Henderson         }
7858f67b9c6SRichard Henderson     } else if (HOST_LONG_BITS == 64 && TARGET_VIRT_ADDR_SPACE_BITS <= 32) {
7868f67b9c6SRichard Henderson         /*
7878f67b9c6SRichard Henderson          * reserved_va must be aligned with the host page size
7888f67b9c6SRichard Henderson          * as it is used with mmap()
7898f67b9c6SRichard Henderson          */
7908f67b9c6SRichard Henderson         reserved_va = max_reserved_va & qemu_host_page_mask;
7918f67b9c6SRichard Henderson     }
7928f67b9c6SRichard Henderson 
793a573e9baSRichard Henderson     {
794a573e9baSRichard Henderson         Error *err = NULL;
7955ebdd774SRichard Henderson         if (seed_optarg != NULL) {
796a573e9baSRichard Henderson             qemu_guest_random_seed_main(seed_optarg, &err);
797a573e9baSRichard Henderson         } else {
798a573e9baSRichard Henderson             qcrypto_init(&err);
799a573e9baSRichard Henderson         }
800a573e9baSRichard Henderson         if (err) {
801a573e9baSRichard Henderson             error_reportf_err(err, "cannot initialize crypto: ");
802a573e9baSRichard Henderson             exit(1);
803a573e9baSRichard Henderson         }
804c5e4a5a9SMagnus Reftel     }
805c5e4a5a9SMagnus Reftel 
80604a6dfebSaurel32     target_environ = envlist_to_environ(envlist, NULL);
80704a6dfebSaurel32     envlist_free(envlist);
808b12b6a18Sths 
809379f6698SPaul Brook     /*
810379f6698SPaul Brook      * Read in mmap_min_addr kernel parameter.  This value is used
811379f6698SPaul Brook      * When loading the ELF image to determine whether guest_base
81214f24e14SRichard Henderson      * is needed.  It is also used in mmap_find_vma.
813379f6698SPaul Brook      */
81414f24e14SRichard Henderson     {
815379f6698SPaul Brook         FILE *fp;
816379f6698SPaul Brook 
817379f6698SPaul Brook         if ((fp = fopen("/proc/sys/vm/mmap_min_addr", "r")) != NULL) {
818379f6698SPaul Brook             unsigned long tmp;
819c9f80666SRichard Henderson             if (fscanf(fp, "%lu", &tmp) == 1 && tmp != 0) {
820379f6698SPaul Brook                 mmap_min_addr = tmp;
821c9f80666SRichard Henderson                 qemu_log_mask(CPU_LOG_PAGE, "host mmap_min_addr=0x%lx\n",
822c9f80666SRichard Henderson                               mmap_min_addr);
823379f6698SPaul Brook             }
824379f6698SPaul Brook             fclose(fp);
825379f6698SPaul Brook         }
826379f6698SPaul Brook     }
827379f6698SPaul Brook 
8287d8cec95Saurel32     /*
829c9f80666SRichard Henderson      * We prefer to not make NULL pointers accessible to QEMU.
830c9f80666SRichard Henderson      * If we're in a chroot with no /proc, fall back to 1 page.
831c9f80666SRichard Henderson      */
832c9f80666SRichard Henderson     if (mmap_min_addr == 0) {
833c9f80666SRichard Henderson         mmap_min_addr = qemu_host_page_size;
834c9f80666SRichard Henderson         qemu_log_mask(CPU_LOG_PAGE,
835c9f80666SRichard Henderson                       "host mmap_min_addr=0x%lx (fallback)\n",
836c9f80666SRichard Henderson                       mmap_min_addr);
837c9f80666SRichard Henderson     }
838c9f80666SRichard Henderson 
839c9f80666SRichard Henderson     /*
8407d8cec95Saurel32      * Prepare copy of argv vector for target.
8417d8cec95Saurel32      */
8427d8cec95Saurel32     target_argc = argc - optind;
8437d8cec95Saurel32     target_argv = calloc(target_argc + 1, sizeof (char *));
8447d8cec95Saurel32     if (target_argv == NULL) {
8457d8cec95Saurel32         (void) fprintf(stderr, "Unable to allocate memory for target_argv\n");
8464d1275c2SRiku Voipio         exit(EXIT_FAILURE);
8477d8cec95Saurel32     }
8487d8cec95Saurel32 
8497d8cec95Saurel32     /*
8507d8cec95Saurel32      * If argv0 is specified (using '-0' switch) we replace
8517d8cec95Saurel32      * argv[0] pointer with the given one.
8527d8cec95Saurel32      */
8537d8cec95Saurel32     i = 0;
8547d8cec95Saurel32     if (argv0 != NULL) {
8557d8cec95Saurel32         target_argv[i++] = strdup(argv0);
8567d8cec95Saurel32     }
8577d8cec95Saurel32     for (; i < target_argc; i++) {
8587d8cec95Saurel32         target_argv[i] = strdup(argv[optind + i]);
8597d8cec95Saurel32     }
8607d8cec95Saurel32     target_argv[target_argc] = NULL;
8617d8cec95Saurel32 
862c78d65e8SMarkus Armbruster     ts = g_new0(TaskState, 1);
863edf8e2afSMika Westerberg     init_task_state(ts);
864edf8e2afSMika Westerberg     /* build Task State */
865edf8e2afSMika Westerberg     ts->info = info;
866edf8e2afSMika Westerberg     ts->bprm = &bprm;
8670429a971SAndreas Färber     cpu->opaque = ts;
868edf8e2afSMika Westerberg     task_settid(ts);
869edf8e2afSMika Westerberg 
870c093364fSOwen Anderson     fd_trans_init();
871c093364fSOwen Anderson 
8729d3019bcSLaurent Vivier     ret = loader_exec(execfd, exec_path, target_argv, target_environ, regs,
873fd4d81ddSArnaud Patard         info, &bprm);
874fd4d81ddSArnaud Patard     if (ret != 0) {
8759d3019bcSLaurent Vivier         printf("Error while loading %s: %s\n", exec_path, strerror(-ret));
8764d1275c2SRiku Voipio         _exit(EXIT_FAILURE);
87731e31b8aSbellard     }
87831e31b8aSbellard 
879b12b6a18Sths     for (wrk = target_environ; *wrk; wrk++) {
880ec45bbe5SSaurav Sachidanand         g_free(*wrk);
881b12b6a18Sths     }
882b12b6a18Sths 
883ec45bbe5SSaurav Sachidanand     g_free(target_environ);
884b12b6a18Sths 
88513829020SPaolo Bonzini     if (qemu_loglevel_mask(CPU_LOG_PAGE)) {
88693756fdcSRichard Henderson         FILE *f = qemu_log_trylock();
88793756fdcSRichard Henderson         if (f) {
88893756fdcSRichard Henderson             fprintf(f, "guest_base  %p\n", (void *)guest_base);
88993756fdcSRichard Henderson             fprintf(f, "page layout changed following binary load\n");
89093756fdcSRichard Henderson             page_dump(f);
89154936004Sbellard 
89293756fdcSRichard Henderson             fprintf(f, "start_brk   0x" TARGET_ABI_FMT_lx "\n",
89393756fdcSRichard Henderson                     info->start_brk);
89493756fdcSRichard Henderson             fprintf(f, "end_code    0x" TARGET_ABI_FMT_lx "\n",
89593756fdcSRichard Henderson                     info->end_code);
89693756fdcSRichard Henderson             fprintf(f, "start_code  0x" TARGET_ABI_FMT_lx "\n",
89793756fdcSRichard Henderson                     info->start_code);
89893756fdcSRichard Henderson             fprintf(f, "start_data  0x" TARGET_ABI_FMT_lx "\n",
89993756fdcSRichard Henderson                     info->start_data);
90093756fdcSRichard Henderson             fprintf(f, "end_data    0x" TARGET_ABI_FMT_lx "\n",
90193756fdcSRichard Henderson                     info->end_data);
90293756fdcSRichard Henderson             fprintf(f, "start_stack 0x" TARGET_ABI_FMT_lx "\n",
90393756fdcSRichard Henderson                     info->start_stack);
90493756fdcSRichard Henderson             fprintf(f, "brk         0x" TARGET_ABI_FMT_lx "\n",
90593756fdcSRichard Henderson                     info->brk);
90693756fdcSRichard Henderson             fprintf(f, "entry       0x" TARGET_ABI_FMT_lx "\n",
90793756fdcSRichard Henderson                     info->entry);
90893756fdcSRichard Henderson             fprintf(f, "argv_start  0x" TARGET_ABI_FMT_lx "\n",
90960f1c801SRichard Henderson                     info->argv);
91093756fdcSRichard Henderson             fprintf(f, "env_start   0x" TARGET_ABI_FMT_lx "\n",
91160f1c801SRichard Henderson                     info->envp);
91293756fdcSRichard Henderson             fprintf(f, "auxv_start  0x" TARGET_ABI_FMT_lx "\n",
91393756fdcSRichard Henderson                     info->saved_auxv);
91493756fdcSRichard Henderson             qemu_log_unlock(f);
91593756fdcSRichard Henderson         }
9162e77eac6Sblueswir1     }
91731e31b8aSbellard 
91853a5960aSpbrook     target_set_brk(info->brk);
91931e31b8aSbellard     syscall_init();
92066fb9763Sbellard     signal_init();
92131e31b8aSbellard 
9229002ec79SRichard Henderson     /* Now that we've loaded the binary, GUEST_BASE is fixed.  Delay
9239002ec79SRichard Henderson        generating the prologue until now so that the prologue can take
9249002ec79SRichard Henderson        the real value of GUEST_BASE into account.  */
925b1311c4aSEmilio G. Cota     tcg_prologue_init(tcg_ctx);
9269002ec79SRichard Henderson 
927cd71c089SLaurent Vivier     target_cpu_copy_regs(env, regs);
928cd71c089SLaurent Vivier 
929fcedd920SAlex Bennée     if (gdbstub) {
930fcedd920SAlex Bennée         if (gdbserver_start(gdbstub) < 0) {
931fcedd920SAlex Bennée             fprintf(stderr, "qemu: could not open gdbserver on %s\n",
932fcedd920SAlex Bennée                     gdbstub);
9334d1275c2SRiku Voipio             exit(EXIT_FAILURE);
934ff7a981aSPeter Maydell         }
935db6b81d4SAndreas Färber         gdb_handlesig(cpu, 0);
9361fddef4bSbellard     }
937e4a4aaa5SRichard Henderson 
938e4a4aaa5SRichard Henderson #ifdef CONFIG_SEMIHOSTING
939e4a4aaa5SRichard Henderson     qemu_semihosting_guestfd_init();
940e4a4aaa5SRichard Henderson #endif
941e4a4aaa5SRichard Henderson 
9421b6b029eSbellard     cpu_loop(env);
9431b6b029eSbellard     /* never exits */
94431e31b8aSbellard     return 0;
94531e31b8aSbellard }
946